diff --git a/.builds/openbsd_0.yml b/.builds/openbsd_0.yml index 278cb3de9d..146ad81657 100644 --- a/.builds/openbsd_0.yml +++ b/.builds/openbsd_0.yml @@ -13,7 +13,7 @@ packages: sources: - https://github.com/nim-lang/Nim environment: - NIM_TESTAMENT_BATCH: "0_3" + NIM_TESTAMENT_BATCH: "0_2" CC: /usr/bin/clang tasks: - setup: | diff --git a/.builds/openbsd_1.yml b/.builds/openbsd_1.yml index d3f0c8795d..ad37340083 100644 --- a/.builds/openbsd_1.yml +++ b/.builds/openbsd_1.yml @@ -13,7 +13,7 @@ packages: sources: - https://github.com/nim-lang/Nim environment: - NIM_TESTAMENT_BATCH: "1_3" + NIM_TESTAMENT_BATCH: "1_2" CC: /usr/bin/clang tasks: - setup: | diff --git a/.builds/openbsd_2.yml b/.builds/openbsd_2.yml deleted file mode 100644 index 4b63e914d7..0000000000 --- a/.builds/openbsd_2.yml +++ /dev/null @@ -1,34 +0,0 @@ -## do not edit directly; auto-generated by `nim r tools/ci_generate.nim` - -image: openbsd/latest -packages: -- gmake -- sqlite3 -- node -- boehm-gc -- pcre -- sfml -- sdl2 -- libffi -sources: -- https://github.com/nim-lang/Nim -environment: - NIM_TESTAMENT_BATCH: "2_3" - 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.ncpuonline) - bin/nim c 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/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..0187064b52 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,10 @@ +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/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index 74ca804f32..22d425b103 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -26,7 +26,7 @@ on: - 'tools/dochack/dochack.nim' - 'tools/kochdocs.nim' - '.github/workflows/ci_docs.yml' - + - 'koch.nim' jobs: build: @@ -126,10 +126,6 @@ jobs: shell: bash run: ./koch boot -d:release - - name: 'Clone fusion' - shell: bash - run: ./koch fusion - - name: 'Build documentation' shell: bash run: ./koch doc --git.commit:devel diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index 59e918f589..dd42db0c46 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -10,11 +10,12 @@ jobs: matrix: os: [ubuntu-18.04, macos-10.15] cpu: [amd64] - pkg: [1, 2] - name: '${{ matrix.os }} (pkg: ${{ matrix.pkg }})' + batch: ["0_3", "1_3", "2_3"] # list of `index_num` + name: '${{ matrix.os }} (batch: ${{ matrix.batch }})' runs-on: ${{ matrix.os }} env: - NIM_TEST_PACKAGES: ${{ matrix.pkg }} + NIM_TEST_PACKAGES: "1" + NIM_TESTAMENT_BATCH: ${{ matrix.batch }} steps: - name: 'Checkout' uses: actions/checkout@v2 diff --git a/.github/workflows/ci_ssl.yml b/.github/workflows/ci_ssl.yml deleted file mode 100644 index 0ec7aeb3bb..0000000000 --- a/.github/workflows/ci_ssl.yml +++ /dev/null @@ -1,93 +0,0 @@ -name: Nim SSL CI -on: - pull_request: - # Run only on changes on related files - paths: - - 'lib/pure/httpclient.nim' - - 'lib/pure/net.nim' - - 'lib/pure/ssl_certs.nim' - - 'lib/wrappers/openssl.nim' - - 'tests/stdlib/thttpclient_ssl*' - - 'tests/untestable/thttpclient_ssl*' - -jobs: - build: - if: | - !contains(format('{0} {1}', github.event.head_commit.message, github.event.pull_request.title), '[skip ci]') - strategy: - fail-fast: false - matrix: - os: [ubuntu-18.04, macos-10.15, windows-2019] - cpu: [amd64] - name: '${{ matrix.os }} (${{ matrix.cpu }})' - runs-on: ${{ matrix.os }} - steps: - - name: 'Checkout' - uses: actions/checkout@v2 - - - name: 'Checkout csources' - uses: actions/checkout@v2 - with: - repository: nim-lang/csources - path: csources - - - 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 -y libssl1.1 - - name: 'Install dependencies (macOS)' - if: runner.os == 'macOS' - run: brew install make - - name: 'Install dependencies (Windows)' - if: runner.os == 'Windows' - shell: bash - run: | - 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 "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" - - - name: 'Add build binaries to PATH' - shell: bash - run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - - - name: 'Build 1-stage compiler from csources' - shell: bash - run: | - ncpu= - case '${{ runner.os }}' in - 'Linux') - ncpu=$(nproc) - ;; - 'macOS') - ncpu=$(sysctl -n hw.ncpu) - ;; - 'Windows') - ncpu=$NUMBER_OF_PROCESSORS - ;; - esac - [[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1 - - make -C csources -j $ncpu CC=gcc ucpu='${{ matrix.cpu }}' - - - name: 'Build koch' - shell: bash - run: nim c koch - - - name: 'Build the real compiler' - shell: bash - run: ./koch boot - - - name: 'Run SSL nimDisableCertificateValidation integration tests' - shell: bash - run: nim c -d:nimDisableCertificateValidation -d:ssl -r -p:. tests/untestable/thttpclient_ssl_disabled.nim - - - name: 'Run SSL certificate check integration tests' - # Not supported on Windows due to old openssl version - if: runner.os != 'Windows' - shell: bash - run: nim c -d:ssl -p:. --threads:on -r tests/untestable/thttpclient_ssl.nim diff --git a/.gitignore b/.gitignore index e55f2c5f06..e71fdf352a 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,7 @@ deinstall.sh doc/html/ doc/*.html -doc/*.pdf +doc/pdf doc/*.idx /web/upload /build/* @@ -66,7 +66,7 @@ testament.db /tests/**/*.js /csources /dist/ -/lib/fusion +# /lib/fusion # fusion is now unbundled; `git status` should reveal if it's there so users can act on it # Private directories and files (IDEs) .*/ @@ -100,3 +100,5 @@ 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 9f536e6c97..ad9e565a6c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -54,7 +54,7 @@ test-windows: script: - call ci\deps.bat - nim c testament\tester - - testament\tester.exe --pedantic all + - testament\tester.exe all tags: - windows - fast diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 109efc6e12..f65f8ca11e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -17,9 +17,11 @@ jobs: Linux_amd64: vmImage: 'ubuntu-16.04' CPU: amd64 - Linux_i386: - vmImage: 'ubuntu-16.04' - CPU: i386 + # Linux_i386: + # # bug #17325: fails on 'ubuntu-16.04' because it now errors with: + # # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed + # vmImage: 'ubuntu-18.04' + # CPU: i386 OSX_amd64: vmImage: 'macOS-10.15' CPU: amd64 @@ -64,29 +66,34 @@ jobs: displayName: 'Install node.js 12.x' - bash: | - sudo apt-fast update -qq + set -e + . ci/funs.sh + echo_run sudo apt-fast update -qq DEBIAN_FRONTEND='noninteractive' \ - sudo apt-fast install --no-install-recommends -yq \ + echo_run sudo apt-fast install --no-install-recommends -yq \ libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg displayName: 'Install dependencies (amd64 Linux)' condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64')) - bash: | - sudo dpkg --add-architecture i386 - + 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. + cat << EOF | sudo tee /etc/apt/preferences.d/pin-to-rel Package: libllvm6.0 Pin: origin "azure.archive.ubuntu.com" Pin-Priority: 1001 EOF - sudo apt-fast update -qq + # echo_run sudo apt-fast update -qq + echo_run sudo apt-fast update -qq || echo "failed, see bug #17343" # `:i386` (e.g. in `libffi-dev:i386`) is needed otherwise you may get: # `could not load: libffi.so` during dynamic loading. DEBIAN_FRONTEND='noninteractive' \ - sudo apt-fast install --no-install-recommends --allow-downgrades -yq \ + echo_run sudo apt-fast install --no-install-recommends --allow-downgrades -yq \ g++-multilib gcc-multilib libcurl4-openssl-dev:i386 libgc-dev:i386 \ libsdl1.2-dev:i386 libsfml-dev:i386 libglib2.0-dev:i386 libffi-dev:i386 @@ -95,14 +102,15 @@ jobs: exec $(which gcc) -m32 "\$@" EOF + cat << EOF > bin/g++ #!/bin/bash exec $(which g++) -m32 "\$@" EOF - chmod 755 bin/gcc - chmod 755 bin/g++ + echo_run chmod 755 bin/gcc + echo_run chmod 755 bin/g++ displayName: 'Install dependencies (i386 Linux)' condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'i386')) @@ -112,12 +120,14 @@ jobs: condition: eq(variables['Agent.OS'], 'Darwin') - bash: | - 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' + set -e + . ci/funs.sh + 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 + echo_run echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/dist/mingw64/bin' displayName: 'Install dependencies (Windows)' condition: eq(variables['Agent.OS'], 'Windows_NT') @@ -126,13 +136,15 @@ jobs: displayName: 'Add build binaries to PATH' - bash: | - echo 'PATH:' "$PATH" - echo '##[section]gcc version' - gcc -v - echo '##[section]nodejs version' - node -v - echo '##[section]make version' - make -v + set -e + . ci/funs.sh + echo_run echo 'PATH:' "$PATH" + echo_run echo '##[section]gcc version' + echo_run gcc -v + echo_run echo '##[section]nodejs version' + echo_run node -v + echo_run echo '##[section]make version' + echo_run make -v displayName: 'System information' - bash: echo '##vso[task.setvariable variable=csources_version]'"$(git -C csources rev-parse HEAD)" @@ -145,6 +157,8 @@ jobs: displayName: 'Restore built csources' - bash: | + set -e + . ci/funs.sh ncpu= ext= case '$(Agent.OS)' in @@ -162,12 +176,12 @@ jobs: [[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1 if [[ -x csources/bin/nim$ext ]]; then - echo "Found cached compiler, skipping build" + echo_run echo "Found cached compiler, skipping build" else - make -C csources -j $ncpu CC=gcc ucpu=$(CPU) koch=no + echo_run make -C csources -j $ncpu CC=gcc ucpu=$(CPU) koch=no fi - cp csources/bin/nim$ext bin + echo_run cp csources/bin/nim$ext bin displayName: 'Build 1-stage compiler from csources' - bash: nim c koch diff --git a/changelog.md b/changelog.md index a6a865514b..cc4f54fe02 100644 --- a/changelog.md +++ b/changelog.md @@ -4,15 +4,28 @@ ## Standard library additions and changes +- Make custom op in macros.quote work for all statements. + +- On Windows the SSL library now 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 + now also need to ship `cacert.pem` with your `.exe` file. + + - Make `{.requiresInit.}` pragma to work for `distinct` types. - Added a macros `enumLen` for returning the number of items in an enum to the `typetraits.nim` module. - `prelude` now works with the JavaScript target. + Added `sequtils` import to `prelude`. + `prelude` can now be used via `include std/prelude`, but `include prelude` still works. - Added `almostEqual` in `math` for comparing two float values using a machine epsilon. +- Added `clamp` in `math` which allows using a `Slice` to clamp to a value. + - The JSON module 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 @@ -22,32 +35,49 @@ literals remain in the "raw" string form so that client code can easily treat small and large numbers uniformly. +- Added `BackwardsIndex` overload for `JsonNode`. + +- added `jsonutils.jsonTo` overload with `opt = Joptions()` param. + +- `json.%`,`json.to`, `jsonutils.formJson`,`jsonutils.toJson` now work with `uint|uint64` + instead of raising (as in 1.4) or giving wrong results (as in 1.2). + - Added an overload for the `collect` macro that inferes the container type based on the syntax of the last expression. Works with std seqs, tables and sets. - Added `randState` template that exposes the default random number generator. Useful for library authors. -- Added std/enumutils module containing `genEnumCaseStmt` macro that generates - case statement to parse string to enum. +- Added `std/enumutils` module. 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 `typetraits.HoleyEnum` for enums with holes, `OrdinalEnum` for enums without holes. - Removed deprecated `iup` module from stdlib, it has already moved to [nimble](https://github.com/nim-lang/iup). +- various functions in `httpclient` now accept `url` of type `Uri`. Moreover `request` function's + `httpMethod` argument of type `string` was deprecated in favor of `HttpMethod` enum type. + - `nodejs` backend now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv`. +- Added `cmpMem` to `system`. + - `doAssertRaises` now correctly handles foreign exceptions. - Added `asyncdispatch.activeDescriptors` that returns the number of currently active async event handles/file descriptors. -- ``--gc:orc`` is now 10% faster than previously for common workloads. If - you have trouble with its changed behavior, compile with ``-d:nimOldOrc``. +- `--gc:orc` is now 10% faster than previously for common workloads. If + you have trouble with its changed behavior, compile with `-d:nimOldOrc`. - `os.FileInfo` (returned by `getFileInfo`) now contains `blockSize`, determining preferred I/O block size for this file object. +- Added a simpler to use `io.readChars` overload. + - `repr` now doesn't insert trailing newline; previous behavior was very inconsistent, see #16034. Use `-d:nimLegacyReprWithNewline` for previous behavior. @@ -55,27 +85,162 @@ - `writeStackTrace` is available in JS backend now. -- `strscans.scanf` now supports parsing single characters. -- `strscans.scanTuple` added which uses `strscans.scanf` internally, returning a tuple which can be unpacked for easier usage of `scanf`. +- Added `decodeQuery` to `std/uri`. -- Added `setutils.toSet` that can take any iterable and convert it to a built-in set, +- `strscans.scanf` now supports parsing single characters. + +- `strscans.scanTuple` added which uses `strscans.scanf` internally, + returning a tuple which can be unpacked for easier usage of `scanf`. + +- 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.[]=`. + - Added `math.isNaN`. - `echo` and `debugEcho` will now raise `IOError` if writing to stdout fails. Previous behavior silently ignored errors. See #16366. Use `-d:nimLegacyEchoNoRaise` for previous behavior. +- Added `jsbigints` module, arbitrary precision integers for JavaScript target. + +- Added `math.copySign`. + - 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. - -- Added `sequtils` import to `prelude`. - Added `euclDiv` and `euclMod` to `math`. + - Added `httpcore.is1xx` and missing HTTP codes. +- Added `jsconsole.jsAssert` for JavaScript target. + +- Added `posix_utils.osReleaseFile` to get system identification from `os-release` file on Linux and the BSDs. + https://www.freedesktop.org/software/systemd/man/os-release.html + +- `math.round` now is rounded "away from zero" in JS backend which is consistent + with other backends. See #9125. Use `-d:nimLegacyJsRound` for previous behavior. + +- Added `socketstream` module that wraps sockets in the stream interface + +- 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. + +- Added `sugar.dumpToString` which improves on `sugar.dump`. + +- Added `math.signbit`. + +- Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably) + +- In `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. + +- Deprecated `any`. See https://github.com/nim-lang/RFCs/issues/281 + +- Added `std/sysrand` module to get random numbers from a secure source + provided by the operating system. + +- 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 `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 `random.initRand()` overload with no argument which uses the current time as a seed. + +- Added experimental `linenoise.readLineStatus` to get line and status (e.g. ctrl-D or ctrl-C). + +- Added `compilesettings.SingleValueSetting.libPath`. + +- `std/wrapnils` doesn't use `experimental:dotOperators` anymore, avoiding + issues like https://github.com/nim-lang/Nim/issues/13063 (which affected error messages) + for modules importing `std/wrapnils`. + Added `??.` macro which returns an `Option`. + +- Added `math.frexp` overload procs. Deprecated `c_frexp`, use `frexp` instead. + +- `parseopt.initOptParser` has been made available and `parseopt` has been + added back to `prelude` for all backends. Previously `initOptParser` was + unavailable if the `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 `prelude` for JS, as it could not be imported. + +- 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. + +- Added `system.prepareStrMutation` for better support of low + level `moveMem`, `copyMem` operations for Orc's copy-on-write string + implementation. + +- `hashes.hash` now supports `object`, but can be overloaded. + +- Added `std/strbasics` for high performance string operations. + Added `strip`, `setSlice`, `add(a: var string, b: openArray[char])`. + +- `hashes.hash` now supports `object`, but can be overloaded. + +- Added to `wrapnils` an option-like API via `??.`, `isSome`, `get`. + +- `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"` + and `$none(int)` to `"none(int)"` instead of `"None[int]"`. + +- Added `std/jsfetch` module [Fetch](https://developer.mozilla.org/docs/Web/API/Fetch_API) wrapper for JavaScript target. + +- Added `std/jsheaders` module [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) wrapper for JavaScript target. + +- Added `std/jsformdata` module [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) wrapper for JavaScript target. + +- `system.addEscapedChar` now renders `\r` as `\r` instead of `\c`, to be compatible + with most other languages. + +- Removed support for named procs in `sugar.=>`. + +- 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 `std/channels`. + +- Added `htmlgen.portal` for [making "SPA style" pages using HTML only](https://web.dev/hands-on-portals). + +- Added `ZZZ` and `ZZZZ` patterns to `times.nim` `DateTime` parsing, to match time + zone offsets without colons, e.g. `UTC+7 -> +0700`. + +- In `std/os`, `getHomeDir`, `expandTilde`, `getTempDir`, `getConfigDir` now do not include trailing `DirSep`, + unless `-d:nimLegacyHomeDir` is specified (for a transition period). + +- Added `jsconsole.dir`, `jsconsole.dirxml`, `jsconsole.timeStamp`. + +- Added dollar `$` and `len` for `jsre.RegExp`. + ## Language changes @@ -85,20 +250,58 @@ - nil dereference is not allowed at compile time. `cast[ptr int](nil)[]` is rejected at compile time. +- `typetraits.distinctBase` now is identity instead of error for non distinct types. + +- `os.copyFile` is now 2.5x faster on OSX, by using `copyfile` from `copyfile.h`; + use `-d:nimLegacyCopyFile` for OSX < 10.5. + +- The required name of case statement macros for the experimental + `caseStmtMacros` feature has changed from `match` to `` `case` ``. + +- `typedesc[Foo]` now renders as such instead of `type Foo` in compiler messages. + + ## Compiler changes - Added `--declaredlocs` to show symbol declaration location in messages. +- Deprecated `TaintedString` and `--taintmode`. + +- Deprecated `--nilseqs` which is now a noop. + +- Added `--spellSuggest` to show spelling suggestions on typos. + - Source+Edit links now appear on top of every docgen'd page when `nim doc --git.url:url ...` is given. - Added `nim --eval:cmd` to evaluate a command directly, see `nim --help`. - VM now supports `addr(mystring[ind])` (index + index assignment) + - Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for previous behavior. +- Added `--hintAsError` with similar semantics as `--warningAsError`. + +- TLS: OSX 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. + +- Now array literals(JS backend) uses JS typed arrays when the corresponding js typed array exists, for example `[byte(1), 2, 3]` generates `new Uint8Array([1, 2, 3])`. + +- docgen: rst files can now use single backticks instead of double backticks and correctly render + in both rst2html (as before) as well as common tools rendering rst directly (e.g. github), by + adding: `default-role:: code` directive inside the rst file, which is now handled by rst2html. + +- Added `-d:nimStrictMode` in CI in several places to ensure code doesn't have certain hints/warnings + +- Added `then`, `catch` to `asyncjs`, for now hidden behind `-d:nimExperimentalAsyncjsThen`. + +- `--newruntime` and `--refchecks` are deprecated. + +- Added `unsafeIsolate` and `extract` to `std/isolation`. + + ## Tool changes @@ -107,3 +310,6 @@ - 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 |`. + +- `fusion` is now un-bundled from nim, `./koch fusion` will + install it via nimble at a fixed hash. diff --git a/ci/funs.sh b/ci/funs.sh new file mode 100644 index 0000000000..de56ef1529 --- /dev/null +++ b/ci/funs.sh @@ -0,0 +1,8 @@ +# utilities used in CI pipelines to avoid duplication. + +echo_run () { + # echo's a command before running it, which helps understanding logs + echo "" + echo "$@" + "$@" +} diff --git a/compiler/ast.nim b/compiler/ast.nim index 4ca5035edc..50a2fb58c8 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -221,6 +221,9 @@ type nkBreakState, # special break statement for easier code generation nkFuncDef, # a func nkTupleConstr # a tuple constructor + 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] @@ -262,6 +265,10 @@ type 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 @@ -427,9 +434,8 @@ type # instantiation and prior to this it has the potential to # be any type. - tyOptDeprecated - # 'out' parameter. Comparable to a 'var' parameter but every - # path must assign a value to it before it can be read from. + tyConcept + # new style concept. tyVoid # now different from tyEmpty, hurray! @@ -484,6 +490,8 @@ 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 TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: ~40) @@ -717,6 +725,16 @@ type module*: int32 item*: int32 +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* = object of RootObj itemId*: ItemId PIdObj* = ref TIdObj @@ -827,24 +845,10 @@ type TSym* {.acyclic.} = object of TIdObj # Keep in sync with PackedSym # proc and type instantiations are cached in the generic symbol case kind*: TSymKind - of skType, skGenericParam: - typeInstCache*: seq[PType] of routineKinds: - procInstCache*: seq[PInstantiation] + #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 @@ -922,8 +926,6 @@ 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 @@ -933,7 +935,7 @@ type 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 - # required by the --incremental:on mode. + # is required by the --incremental:on mode. TPair* = object key*, val*: RootRef @@ -1004,7 +1006,7 @@ const ConstantDataTypes*: TTypeKinds = {tyArray, tySet, tyTuple, tySequence} NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, - tyProc, tyError} + tyProc, tyError} # TODO PtrLikeKinds*: TTypeKinds = {tyPointer, tyPtr} # for VM ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType, skIterator, @@ -1013,7 +1015,7 @@ const nfDotSetter, nfDotField, nfIsRef, nfIsPtr, nfPreventCg, nfLL, nfFromTemplate, nfDefaultRefsParam, - nfExecuteOnReload} + nfExecuteOnReload, nfLastRead, nfFirstWrite} namePos* = 0 patternPos* = 1 # empty except for term rewriting macros genericParamsPos* = 2 @@ -1038,6 +1040,7 @@ const declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef} routineDefs* = declarativeDefs + {nkMacroDef, nkTemplateDef} procDefs* = nkLambdaKinds + declarativeDefs + callableDefs* = nkLambdaKinds + routineDefs nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice} nkStrKinds* = {nkStrLit..nkTripleStrLit} @@ -1074,18 +1077,33 @@ template id*(a: PIdObj): int = (x.itemId.module.int shl moduleShift) + x.itemId.item.int type - IdGenerator* = ref ItemId # unfortunately, we really need the 'shared mutable' aspect here. + 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, item: m.itemId.item) + result = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0) -proc nextId*(x: IdGenerator): ItemId {.inline.} = - inc x.item - result = x[] +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.} = @@ -1111,11 +1129,7 @@ proc discardSons*(father: PNode) type Indexable = PNode | PType proc len*(n: Indexable): int {.inline.} = - when defined(nimNoNilSeqs): - result = n.sons.len - else: - if isNil(n.sons): result = 0 - else: result = n.sons.len + result = n.sons.len proc safeLen*(n: PNode): int {.inline.} = ## works even for leaves. @@ -1130,8 +1144,9 @@ proc safeArrLen*(n: PNode): int {.inline.} = proc add*(father, son: Indexable) = assert son != nil - when not defined(nimNoNilSeqs): - if isNil(father.sons): father.sons = @[] + father.sons.add(son) + +proc addAllowNil*(father, son: Indexable) {.inline.} = father.sons.add(son) template `[]`*(n: Indexable, i: int): Indexable = n.sons[i] @@ -1199,11 +1214,32 @@ proc newTreeIT*(kind: TNodeKind; info: TLineInfo; typ: PType; children: varargs[ 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, 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, options: options, owner: owner, offset: defaultOffset) + when false: + if id.item > 2141: + let s = getStackTrace() + const words = ["createTypeBoundOps", + "initOperators", + "generateInstance", + "semIdentDef", "addLocalDecl"] + for w in words: + if w in s: + x.inc w + return + x.inc "" proc astdef*(s: PSym): PNode = # get only the definition (initializer) portion of the ast @@ -1268,10 +1304,7 @@ proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) = for i in 0..high(src.data): dest.data[i] = src.data[i] proc discardSons*(father: PNode) = - when defined(nimNoNilSeqs): - father.sons = @[] - else: - father.sons = nil + father.sons = @[] proc withInfo*(n: PNode, info: TLineInfo): PNode = n.info = info @@ -1383,10 +1416,11 @@ proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType = lockLevel: UnspecifiedLockLevel, uniqueId: id) when false: - if result.id == 76426: + if result.itemId.module == 55 and result.itemId.item == 2: 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 @@ -1395,13 +1429,7 @@ proc mergeLoc(a: var TLoc, b: TLoc) = if a.r == nil: a.r = b.r proc newSons*(father: Indexable, length: int) = - when defined(nimNoNilSeqs): - setLen(father.sons, length) - else: - if isNil(father.sons): - newSeq(father.sons, length) - else: - setLen(father.sons, length) + setLen(father.sons, length) proc assignType*(dest, src: PType) = dest.kind = src.kind @@ -1410,7 +1438,6 @@ 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: @@ -1437,8 +1464,6 @@ proc copySym*(s: PSym; id: ItemId): PSym = result.typ = s.typ result.flags = s.flags result.magic = s.magic - if s.kind == skModule: - copyStrTable(result.tab, s.tab) result.options = s.options result.position = s.position result.loc = s.loc @@ -1456,13 +1481,10 @@ proc createModuleAlias*(s: PSym, id: ItemId, newIdent: PIdent, info: TLineInfo; result.ast = s.ast #result.id = s.id # XXX figure out what to do with the ID. result.flags = s.flags - system.shallowCopy(result.tab, s.tab) result.options = s.options result.position = s.position result.loc = s.loc result.annex = s.annex - # XXX once usedGenerics is used, ensure module aliases keep working! - assert s.usedGenerics.len == 0 proc initStrTable*(x: var TStrTable) = x.counter = 0 @@ -1541,26 +1563,17 @@ proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) = owner.flags.incl tfHasGCedMem proc rawAddSon*(father, son: PType; propagateHasAsgn = true) = - when not defined(nimNoNilSeqs): - if isNil(father.sons): father.sons = @[] father.sons.add(son) if not son.isNil: propagateToOwner(father, son, propagateHasAsgn) proc rawAddSonNoPropagationOfTypeFlags*(father, son: PType) = - when not defined(nimNoNilSeqs): - if isNil(father.sons): father.sons = @[] father.sons.add(son) proc addSonNilAllowed*(father, son: PNode) = - when not defined(nimNoNilSeqs): - if isNil(father.sons): father.sons = @[] father.sons.add(son) proc delSon*(father: PNode, idx: int) = - when defined(nimNoNilSeqs): - if father.len == 0: return - else: - if isNil(father.sons): return + if father.len == 0: return for i in idx.. 0)) + # TODO check for n having sons? or just return false for now if not + if fn.typ != nil and fn.typ.n != nil and fn.typ.n[0].kind == nkSym: + result = false + else: + 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 @@ -1971,3 +1995,7 @@ proc toHumanStr*(kind: TTypeKind): string = 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 diff --git a/compiler/canonicalizer.nim b/compiler/canonicalizer.nim deleted file mode 100644 index de0d0f30e6..0000000000 --- a/compiler/canonicalizer.nim +++ /dev/null @@ -1,421 +0,0 @@ -# -# -# 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 the canonalization for the various caching mechanisms. - -import strutils, db_sqlite, md5 - -var db: DbConn - -# We *hash* the relevant information into 128 bit hashes. This should be good -# enough to prevent any collisions. - -type - TUid = distinct MD5Digest - -# For name mangling we encode these hashes via a variant of base64 (called -# 'base64a') and prepend the *primary* identifier to ease the debugging pain. -# So a signature like: -# -# proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) -# -# is mangled into: -# gABI_MTdmOWY5MTQ1MDcyNGQ3ZA -# -# This is a good compromise between correctness and brevity. ;-) - -const - cb64 = [ - "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"] - -proc toBase64a(s: cstring, len: int): string = - ## encodes `s` into base64 representation. After `lineLen` characters, a - ## `newline` is added. - result = newStringOfCap(((len + 2) div 3) * 4) - var i = 0 - while i < s.len - 2: - let a = ord(s[i]) - let b = ord(s[i+1]) - let c = ord(s[i+2]) - result.add cb64[a shr 2] - result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] - result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)] - result.add cb64[c and 0x3F] - inc(i, 3) - if i < s.len-1: - let a = ord(s[i]) - let b = ord(s[i+1]) - result.add cb64[a shr 2] - result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] - result.add cb64[((b and 0x0F) shl 2)] - elif i < s.len: - let a = ord(s[i]) - result.add cb64[a shr 2] - result.add cb64[(a and 3) shl 4] - -proc toBase64a(u: TUid): string = toBase64a(cast[cstring](u), sizeof(u)) - -proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len) - -proc hashSym(c: var MD5Context, s: PSym) = - if sfAnon in s.flags or s.kind == skGenericParam: - c &= ":anon" - else: - var it = s.owner - while it != nil: - hashSym(c, it) - c &= "." - it = s.owner - c &= s.name.s - -proc hashTree(c: var MD5Context, n: PNode) = - if n == nil: - c &= "\255" - return - var k = n.kind - md5Update(c, cast[cstring](addr(k)), 1) - # we really must not hash line information. 'n.typ' is debatable but - # shouldn't be necessary for now and avoids potential infinite recursions. - case n.kind - of nkEmpty, nkNilLit, nkType: discard - of nkIdent: - c &= n.ident.s - of nkSym: - hashSym(c, n.sym) - of nkCharLit..nkUInt64Lit: - var v = n.intVal - md5Update(c, cast[cstring](addr(v)), sizeof(v)) - of nkFloatLit..nkFloat64Lit: - var v = n.floatVal - md5Update(c, cast[cstring](addr(v)), sizeof(v)) - of nkStrLit..nkTripleStrLit: - c &= n.strVal - else: - for i 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.. (NU)$2){ #raiseIndexError2($1,$2); $3}$n", - [rdLoc(b), lenExpr(p, a), raiseInstr(p)]) - else: - linefmt(p, cpsStmts, - "if ((NU)($1) >= (NU)$2){ #raiseIndexError2($1,$2-1); $3}$n", - [rdLoc(b), lenExpr(p, a), raiseInstr(p)]) + linefmt(p, cpsStmts, + "if ((NU)($1) >= (NU)$2){ #raiseIndexError2($1,$2-1); $3}$n", + [rdLoc(b), lenExpr(p, a), raiseInstr(p)]) if d.k == locNone: d.storage = OnHeap if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: a.r = ropecg(p.module, "(*$1)", [a.r]) @@ -1289,16 +1285,17 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = genAssignment(p, a, b, {}) else: let ti = genTypeInfoV1(p.module, typ, a.lode.info) - if bt.destructor != nil and not isTrivialProc(bt.destructor): + let op = getAttachedOp(p.module.g.graph, bt, attachedDestructor) + if op != nil and not isTrivialProc(p.module.g.graph, op): # 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 bt.destructor.typ == nil or bt.destructor.typ.callConv != ccNimCall: + if op.typ == nil or op.typ.callConv != ccNimCall: 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(bt.destructor), f) + initLocExpr(p, newSymNode(op), f) p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) if a.storage == OnHeap and usesWriteBarrier(p.config): @@ -1372,8 +1369,7 @@ proc genNewSeq(p: BProc, e: PNode) = getTypeDesc(p.module, seqtype.lastSon), getSeqPayloadType(p.module, seqtype)]) else: - let lenIsZero = optNilSeqs notin p.options and - e[2].kind == nkIntLit and e[2].intVal == 0 + let lenIsZero = e[2].kind == nkIntLit and e[2].intVal == 0 genNewSeqAux(p, a, b.rdLoc, lenIsZero) gcUsage(p.config, e) @@ -1498,8 +1494,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) = getSeqPayloadType(p.module, seqtype)]) else: # generate call to newSeq before adding the elements per hand: - genNewSeqAux(p, dest[], l, - optNilSeqs notin p.options and n.len == 0) + genNewSeqAux(p, dest[], l, n.len == 0) for i in 0..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) - 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") + 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) + else: + var a: TLoc + initLocExpr(p, arg, a) + var r = rdLoc(a) & (if isRef: "->Sup" else: ".Sup") for i in 2..abs(inheritanceDiff(dest, src)): r.add(".Sup") - 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) + putIntoDest(p, d, n, if isRef: "&" & r else: r, a.storage) proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = let t = n.typ @@ -2642,7 +2625,60 @@ 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: + fillLoc(sym.loc, locData, sym.ast, mangleName(p.module, sym), OnStatic) + if m.hcrOn: incl(sym.loc.flags, lfIndirect) + result = lfNoDecl notin sym.loc.flags + +proc genConstHeader(m, q: BModule; p: BProc, sym: PSym) = + assert(sym.loc.r != nil) + 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 + q.s[cfsData].addf("N_LIB_PRIVATE NIM_CONST $1 $2 = $3;$n", + [getTypeDesc(q, sym.typ), actualConstName, + genBracedInit(q.initProc, sym.ast, isConst = true, sym.typ)]) + 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(nimCompilerStackraceHints): + setFrameMsg p.config$n.info & " " & $n.kind p.currLineInfo = n.info case n.kind @@ -2650,7 +2686,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = var sym = n.sym case sym.kind of skMethod: - if {sfDispatcher, sfForward} * sym.flags != {}: + if useAliveDataFromDce in p.module.flags or {sfDispatcher, sfForward} * sym.flags != {}: # we cannot produce code for the dispatcher yet: fillProcLoc(p.module, n) genProcPrototype(p.module, sym) @@ -2663,13 +2699,21 @@ 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) - genProc(p.module, sym) + 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 == 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): putIntoDest(p, d, n, genLiteral(p, sym.ast, sym.typ), OnStatic) + elif useAliveDataFromDce in p.module.flags: + genConstHeader(p.module, p.module, p, sym) + assert((sym.loc.r != nil) and (sym.loc.t != nil)) + putLocIntoDest(p, d, sym.loc) else: genComplexConst(p, sym, d) of skEnumField: @@ -2790,7 +2834,10 @@ 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: discard # consts generated lazily on use + of nkConstSection: + if useAliveDataFromDce in p.module.flags: + genConstStmt(p, n) + # else: 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) @@ -2835,13 +2882,16 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef: if n[genericParamsPos].kind == nkEmpty: var prc = n[namePos].sym - # 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 useAliveDataFromDce in p.module.flags: + if p.module.alive.contains(prc.itemId.item) and prc.magic in {mNone, mIsolate}: + genProc(p.module, prc) + elif 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) @@ -2851,6 +2901,7 @@ 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 genNamedConstExpr(p: BProc, n: PNode; isConst: bool): Rope = @@ -3089,7 +3140,9 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType): Rope else: result = genConstSeq(p, n, typ, isConst) of tyProc: - if typ.callConv == ccClosure and n.len > 1 and n[1].kind == nkNilLit: + 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. # 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 diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge_unused.nim similarity index 99% rename from compiler/ccgmerge.nim rename to compiler/ccgmerge_unused.nim index 40833a64e9..c7d19da7ac 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge_unused.nim @@ -218,9 +218,6 @@ 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 diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 367e693e92..6cbff6ee90 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -25,10 +25,10 @@ proc getTraverseProc(p: BProc, v: PSym): Rope = proc registerTraverseProc(p: BProc, v: PSym, traverseProc: Rope) = if sfThread in v.flags: - appcg(p.module, p.module.initProc.procSec(cpsInit), + appcg(p.module, p.module.preInitProc.procSec(cpsInit), "$n\t#nimRegisterThreadLocalMarker($1);$n$n", [traverseProc]) else: - appcg(p.module, p.module.initProc.procSec(cpsInit), + appcg(p.module, p.module.preInitProc.procSec(cpsInit), "$n\t#nimRegisterGlobalMarker($1);$n$n", [traverseProc]) proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} = @@ -653,12 +653,19 @@ proc genParForStmt(p: BProc, t: PNode) = initLocExpr(p, call[2], rangeB) # $n at the beginning because of #9710 - if call.len == 4: # `||`(a, b, annotation) - lineF(p, cpsStmts, "$n#pragma omp $4$n" & - "for ($1 = $2; $1 <= $3; ++$1)", - [forLoopVar.loc.rdLoc, - rangeA.rdLoc, rangeB.rdLoc, - call[3].getStr.rope]) + if call.len == 4: # procName(a, b, annotation) + if call[0].sym.name.s == "||": # `||`(a, b, annotation) + lineF(p, cpsStmts, "$n#pragma omp $4$n" & + "for ($1 = $2; $1 <= $3; ++$1)", + [forLoopVar.loc.rdLoc, + rangeA.rdLoc, rangeB.rdLoc, + call[3].getStr.rope]) + else: + lineF(p, cpsStmts, "$n#pragma $4$n" & + "for ($1 = $2; $1 <= $3; ++$1)", + [forLoopVar.loc.rdLoc, + rangeA.rdLoc, rangeB.rdLoc, + call[3].getStr.rope]) else: # `||`(a, b, step, annotation) var step: TLoc initLocExpr(p, call[3], step) @@ -1523,20 +1530,21 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType, [rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field), intLiteral(toInt64(lengthOrd(p.config, field.typ))+1)]) -proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) = - const ObjDiscMappingProcSlot = -5 - var theProc: PSym = nil - for idx, p in items(t.methods): - if idx == ObjDiscMappingProcSlot: - theProc = p - break - if theProc == nil: - theProc = genCaseObjDiscMapping(t, field, e.info, p.module.g.graph, p.module.idgen) - t.methods.add((ObjDiscMappingProcSlot, theProc)) - var call = newNodeIT(nkCall, e.info, getSysType(p.module.g.graph, e.info, tyUInt8)) - call.add newSymNode(theProc) - call.add e - expr(p, call, d) +when false: + proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) = + const ObjDiscMappingProcSlot = -5 + var theProc: PSym = nil + for idx, p in items(t.methods): + if idx == ObjDiscMappingProcSlot: + theProc = p + break + if theProc == nil: + theProc = genCaseObjDiscMapping(t, field, e.info, p.module.g.graph, p.module.idgen) + t.methods.add((ObjDiscMappingProcSlot, theProc)) + var call = newNodeIT(nkCall, e.info, getSysType(p.module.g.graph, e.info, tyUInt8)) + call.add newSymNode(theProc) + call.add e + expr(p, call, d) proc asgnFieldDiscriminant(p: BProc, e: PNode) = var a, tmp: TLoc diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index eba46f8299..fbe8bce9ed 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -7,8 +7,8 @@ # distribution, for details about the copyright. # -## Thread var support for crappy architectures that lack native support for -## thread local storage. (**Thank you Mac OS X!**) +## Thread var support for architectures that lack native support for +## thread local storage. # included from cgen.nim @@ -35,7 +35,11 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) = if isExtern: m.s[cfsVars].add("extern ") elif lfExportLib in s.loc.flags: m.s[cfsVars].add("N_LIB_EXPORT_VAR ") else: m.s[cfsVars].add("N_LIB_PRIVATE ") - if optThreads in m.config.globalOptions: m.s[cfsVars].add("NIM_THREADVAR ") + if optThreads in m.config.globalOptions: + let sym = s.typ.sym + if sym != nil and sfCppNonPod in sym.flags: + m.s[cfsVars].add("NIM_THREAD_LOCAL ") + else: m.s[cfsVars].add("NIM_THREADVAR ") m.s[cfsVars].add(getTypeDesc(m, s.loc.t)) m.s[cfsVars].addf(" $1;$n", [s.loc.r]) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 142fec0569..73ee9cb8a2 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -36,19 +36,17 @@ proc mangleField(m: BModule; name: PIdent): string = if isKeyword(name): result.add "_0" -when false: - proc hashOwner(s: PSym): SigHash = - var m = s - while m.kind != skModule: m = m.owner - let p = m.owner - assert p.kind == skPackage - result = gDebugInfo.register(p.name.s, m.name.s) - proc mangleName(m: BModule; s: PSym): Rope = result = s.loc.r if result == nil: result = s.name.s.mangle.rope - result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts)) + result.add "_" + result.add m.g.graph.ifaces[s.itemId.module].uniqueName + result.add "_" + result.add rope s.itemId.item + if m.hcrOn: + result.add "_" + result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts)) s.loc.r = result writeMangledName(m.ndi, s, m.config) @@ -1267,9 +1265,9 @@ proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = proc fakeClosureType(m: BModule; owner: PSym): PType = # we generate the same RTTI as for a tuple[pointer, ref tuple[]] - result = newType(tyTuple, nextId m.idgen, owner) - result.rawAddSon(newType(tyPointer, nextId m.idgen, owner)) - var r = newType(tyRef, nextId m.idgen, owner) + 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) r.rawAddSon(obj) result.rawAddSon(r) @@ -1281,12 +1279,12 @@ 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, ownerModule: PSym) = +proc declareNimType(m: BModule, name: string; str: Rope, module: int) = let nr = rope(name) if m.hcrOn: m.s[cfsData].addf("static $2* $1;$n", [str, nr]) m.s[cfsTypeInit1].addf("\t$1 = ($3*)hcrGetGlobal($2, \"$1\");$n", - [str, getModuleDllPath(m, ownerModule), nr]) + [str, getModuleDllPath(m, module), nr]) else: m.s[cfsData].addf("extern $2 $1;$n", [str, nr]) @@ -1313,11 +1311,11 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope = it = it[0] result = makeCString(res) -proc isTrivialProc(s: PSym): bool {.inline.} = s.ast[bodyPos].len == 0 +proc isTrivialProc(g: ModuleGraph; s: PSym): bool {.inline.} = getBody(g, s).len == 0 proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope = - let theProc = t.attachedOps[op] - if theProc != nil and not isTrivialProc(theProc): + let theProc = getAttachedOp(m.g.graph, t, op) + if theProc != nil and not isTrivialProc(m.g.graph, 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: @@ -1338,7 +1336,7 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope = proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) = var typeName: Rope - if t.kind == tyObject: + if t.kind in {tyObject, tyDistinct}: if incompleteType(t): localError(m.config, info, "request for RTTI generation for incomplete object: " & typeToString(t)) @@ -1359,9 +1357,13 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: discard genTypeInfoV1(m, t, info) +proc moduleOpenForCodegen(m: BModule; module: int32): bool {.inline.} = + result = module < m.g.modules.len and m.g.modules[module] != nil + proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = let origType = t - var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses) + # distinct types can have their own destructors + var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses - {tyDistinct}) let prefixTI = if m.hcrOn: "(" else: "(&" @@ -1381,11 +1383,11 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = result = "NTIv2$1_" % [rope($sig)] m.typeInfoMarkerV2[sig] = result - let owner = t.skipTypes(typedescPtrs).owner.getModule - if owner != m.module: + let owner = t.skipTypes(typedescPtrs).itemId.module + if owner != m.module.position and moduleOpenForCodegen(m, owner): # make sure the type info is created in the owner module - assert m.g.modules[owner.position] != nil - discard genTypeInfoV2(m.g.modules[owner.position], origType, info) + assert m.g.modules[owner] != nil + discard genTypeInfoV2(m.g.modules[owner], origType, info) # reference the type info as extern here discard cgsym(m, "TNimTypeV2") declareNimType(m, "TNimTypeV2", result, owner) @@ -1396,14 +1398,41 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = result = prefixTI.rope & result & ")".rope proc openArrayToTuple(m: BModule; t: PType): PType = - result = newType(tyTuple, nextId m.idgen, t.owner) - let p = newType(tyPtr, nextId m.idgen, t.owner) - let a = newType(tyUncheckedArray, nextId m.idgen, t.owner) + 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) +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..len = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)]) + else: + linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) elif not isComplexValueType(typ): if containsGcRef: var nilLoc: TLoc @@ -855,7 +863,8 @@ proc containsResult(n: PNode): bool = for i in 0.. 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)])) - # declare header: - if q != m and not containsOrIncl(m.declaredThings, sym.id): - assert(sym.loc.r != nil) - 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) + 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) proc isActivated(prc: PSym): bool = prc.typ != nil @@ -1610,9 +1589,7 @@ 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", []) @@ -1670,9 +1647,7 @@ 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: @@ -1684,7 +1659,7 @@ proc genInitCode(m: BModule) = writeSection(preInitProc, cpsLocals) writeSection(preInitProc, cpsInit, m.hcrOn) writeSection(preInitProc, cpsStmts) - prc.addf("}$N", []) + 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) @@ -1764,28 +1739,21 @@ 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: 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 @@ -1839,7 +1807,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: @@ -1875,9 +1843,7 @@ proc writeHeader(m: BModule) = generateThreadLocalStorage(m) for i in cfsHeaders..cfsProcs: - result.add(genSectionStart(i, m.config)) result.add(m.s[i]) - 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]) @@ -1922,13 +1888,9 @@ proc addHcrInitGuards(p: BProc, n: PNode, inInitGuard: var bool) = genStmts(p, n) -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 +proc genTopLevelStmt*(m: BModule; n: PNode) = + ## Also called from `ic/cbackend.nim`. + if passes.skipCodegen(m.config, n): return m.initProc.options = initProcOptions(m) #softRnl = if optLineDir in m.config.options: noRnl else: rnl # XXX replicate this logic! @@ -1941,6 +1903,12 @@ proc myProcess(b: PPassContext, n: PNode): PNode = else: genProcBody(m.initProc, transformedN) +proc myProcess(b: PPassContext, n: PNode): PNode = + result = n + if b != nil: + var m = BModule(b) + genTopLevelStmt(m, n) + proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool = if optForceFullMake notin m.config.globalOptions: if not moduleHasChanged(m.g.graph, m.module): @@ -1974,46 +1942,26 @@ proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool = proc writeModule(m: BModule, pending: bool) = template onExit() = close(m.ndi, m.config) let cfile = getCFile(m) - 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 m.config.cmd == cmdTcc: - tccgen.compileCCode($code, m.config) - onExit() - 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) + if moduleHasChanged(m.g.graph, m.module): 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: - # 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} + 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 m.config.cmd == cmdTcc: + tccgen.compileCCode($code, m.config) + onExit() + return + + if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached} addFileToCompile(m.config, cf) onExit() @@ -2021,26 +1969,13 @@ 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) - 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) +proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = + ## Also called from IC. if sfMainModule in m.module.flags: # phase ordering problem here: We need to announce this # dependency to 'nimTestErrorFlag' before system.c has been written to disk. @@ -2091,6 +2026,12 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = let mm = m m.g.modulesClosed.add mm + +proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = + result = n + if b == nil: return + finalCodegenActions(graph, BModule(b), n) + proc genForwardedProcs(g: BModuleList) = # Forward declared proc:s lack bodies when first encountered, so they're given # a second pass here @@ -2098,8 +2039,7 @@ proc genForwardedProcs(g: BModuleList) = while g.forwardedProcs.len > 0: let prc = g.forwardedProcs.pop() - ms = getModule(prc) - m = g.modules[ms.position] + m = g.modules[prc.itemId.module] if sfForward in prc.flags: internalError(m.config, prc.info, "still forwarded: " & prc.name.s) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 8e50943366..3678adacf8 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -102,7 +102,7 @@ type TTypeSeq* = seq[PType] TypeCache* = Table[SigHash, Rope] - TypeCacheWithOwner* = Table[SigHash, tuple[str: Rope, owner: PSym]] + TypeCacheWithOwner* = Table[SigHash, tuple[str: Rope, owner: int32]] CodegenFlag* = enum preventStackTrace, # true if stack traces need to be prevented @@ -112,7 +112,8 @@ 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 @@ -154,6 +155,7 @@ type 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 @@ -200,7 +202,7 @@ proc newProc*(prc: PSym, module: BModule): BProc = result.sigConflicts = initCountTable[string]() proc newModuleList*(g: ModuleGraph): BModuleList = - BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: PSym]](), + BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: int32]](), config: g.config, graph: g, nimtvDeclared: initIntSet()) iterator cgenModules*(g: BModuleList): BModule = diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index a0c16f2ed4..484bc9d976 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -67,7 +67,7 @@ proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult = while true: aa = skipTypes(aa, {tyGenericInst, tyAlias}) bb = skipTypes(bb, {tyGenericInst, tyAlias}) - if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef, tyLent}: + if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef, tyLent, tySink}: aa = aa.lastSon bb = bb.lastSon else: @@ -107,11 +107,14 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) = s.ast[resultPos] = newNodeI(nkEmpty, s.info) s.ast[dispatcherPos] = dispatcher -proc createDispatcher(s: PSym; idgen: IdGenerator): PSym = - var disp = copySym(s, nextId(idgen)) +proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym = + var disp = copySym(s, nextSymId(idgen)) incl(disp.flags, sfDispatcher) excl(disp.flags, sfExported) - disp.typ = copyType(disp.typ, nextId(idgen), disp.typ.owner) + let old = disp.typ + disp.typ = copyType(disp.typ, nextTypeId(idgen), disp.typ.owner) + copyTypeProps(g, idgen.module, disp.typ, old) + # we can't inline the dispatcher itself (for now): if disp.typ.callConv == ccInline: disp.typ.callConv = ccNimCall disp.ast = copyTree(s.ast) @@ -119,7 +122,7 @@ proc createDispatcher(s: PSym; idgen: IdGenerator): PSym = disp.loc.r = nil if s.typ[0] != nil: if disp.ast.len > resultPos: - disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, nextId(idgen)) + disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, nextSymId(idgen)) else: # We've encountered a method prototype without a filled-in # resultPos slot. We put a placeholder in there that will @@ -157,7 +160,7 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) = if disp.typ.lockLevel < meth.typ.lockLevel: disp.typ.lockLevel = meth.typ.lockLevel -proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym, fromCache: bool) = +proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) = var witness: PSym for i in 0..= 0: options.setConfigVar(conf, switch, arg) else: invalidCmdLineOption(conf, pass, switch, info) @@ -975,7 +992,6 @@ proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) = 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) diff --git a/compiler/concepts.nim b/compiler/concepts.nim new file mode 100644 index 0000000000..54579f73f6 --- /dev/null +++ b/compiler/concepts.nim @@ -0,0 +1,340 @@ +# +# +# 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 + +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 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.. 0.20.0 defineSymbol("nimNoZeroExtendMagic") defineSymbol("nimMacrosGetNodeId") for f in Feature: @@ -123,3 +126,7 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasEffectTraitsModule") defineSymbol("nimHasCastPragmaBlocks") defineSymbol("nimHasDeclaredLocs") + defineSymbol("nimHasJsBigIntBackend") + defineSymbol("nimHasWarningAsError") + defineSymbol("nimHasHintAsError") + defineSymbol("nimHasSpellSuggest") diff --git a/compiler/dfa.nim b/compiler/dfa.nim index d07122552c..c7a9d46944 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -29,9 +29,8 @@ ## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen. ## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf -import ast, types, intsets, lineinfos, renderer, asciitables - -from patterns import sameTrees +import ast, types, intsets, lineinfos, renderer +import std/private/asciitables type InstrKind* = enum @@ -456,6 +455,10 @@ proc genCase(c: var Con; n: PNode) = let isExhaustive = skipTypes(n[0].typ, abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString} + # we generate endings as a set of chained gotos, this is a bit awkward but it + # ensures when recursively traversing the CFG for various analysis, we don't + # artificially extended the life of each branch (for the purposes of DFA) + # beyond the minimum amount. var endings: seq[TPosition] = @[] c.gen(n[0]) for i in 1.. field: + # x -> x: true + # x -> x.f: true + # x.f -> x: false + # x.f -> x.f: true + # x.f -> x.v: 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, nkCheckedFieldExpr, nkBracketExpr}: + n = n[0] + of PathKinds1: + n = n[1] + of nkDotExpr, nkCheckedFieldExpr, nkBracketExpr: + result.add n + n = n[0] + of nkSym: + result.add n; break + else: return no -proc instrTargets*(insloc, loc: PNode): InstrTargetKind = - if sameTrees(insloc, loc) or insloc.aliases(loc): - Full # x -> x; x -> x.f - elif loc.aliases(insloc): - Partial # x.f -> x - else: None + 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 nkCheckedFieldExpr: + if currFieldPath[0][1].sym != currObjPath[0][1].sym: return no + 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 proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool = var n = orig while true: case n.kind - of PathKinds0 - {nkBracketExpr, nkHiddenDeref, nkDerefExpr}: + of PathKinds0 - {nkHiddenDeref, nkDerefExpr}: n = n[0] of PathKinds1: n = n[1] - 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. diff --git a/compiler/docgen.nim b/compiler/docgen.nim index d21db76343..57d5e7b013 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -25,6 +25,7 @@ from std/private/globs import nativeToUnixPath const exportSection = skField docCmdSkip = "skip" + DocColOffset = "## ".len # assuming that a space was added after ## type TSections = array[TSymKind, Rope] @@ -57,6 +58,11 @@ type PDoc* = ref TDocumentor ## Alias to type less. +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, isTitle = false): RelativeFile = ## returns a relative file that will be appended to outDir let file2 = $file @@ -132,10 +138,12 @@ template declareClosures = of meNewSectionExpected: k = errNewSectionExpected of meGeneralParseError: k = errGeneralParseError of meInvalidDirective: k = errInvalidDirectiveX + of meFootnoteMismatch: k = errFootnoteMismatch of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel of mwUnknownSubstitution: k = warnUnknownSubstitutionX of mwUnsupportedLanguage: k = warnLanguageXNotSupported of mwUnsupportedField: k = warnFieldXNotSupported + of mwRstStyle: k = warnRstStyle {.gcsafe.}: globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg) @@ -203,7 +211,8 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, var outp: AbsoluteFile if filename.len == 0: let nameOnly = splitFile(d.filename).name - outp = getNimcacheDir(conf) / RelativeDir(nameOnly) / + # "snippets" needed, refs bug #17183 + outp = getNimcacheDir(conf) / "snippets".RelativeDir / RelativeDir(nameOnly) / RelativeFile(nameOnly & "_snippet_" & $d.id & ".nim") elif isAbsolute(filename): outp = AbsoluteFile(filename) @@ -221,10 +230,14 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, # 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) @@ -310,8 +323,12 @@ proc genComment(d: PDoc, n: PNode): string = when false: # RFC: to preseve newlines in comments, this would work: comment = comment.replace("\n", "\n\n") - renderRstToOut(d[], parseRst(comment, toFullPath(d.conf, n.info), toLinenumber(n.info), - toColumn(n.info), (var dummy: bool; dummy), d.options, d.conf), result) + renderRstToOut(d[], + parseRst(comment, toFullPath(d.conf, n.info), + toLinenumber(n.info), + toColumn(n.info) + DocColOffset, + (var dummy: bool; dummy), d.options, d.conf), + result) proc genRecCommentAux(d: PDoc, n: PNode): Rope = if n == nil: return nil @@ -324,8 +341,7 @@ proc genRecCommentAux(d: PDoc, n: PNode): Rope = result = genRecCommentAux(d, n[i]) if result != nil: return else: - when defined(nimNoNilSeqs): n.comment = "" - else: n.comment = nil + n.comment = "" proc genRecComment(d: PDoc, n: PNode): Rope = if n == nil: return nil @@ -445,18 +461,6 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe proc exampleOutputDir(d: PDoc): AbsoluteDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples" -proc writeExample(d: PDoc; ex: PNode, rdoccmd: string) = - if d.conf.errorCounter > 0: return - let outputDir = d.exampleOutputDir - createDir(outputDir) - inc d.exampleCounter - 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) - 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 r\"$1\"\n" % outp.string - 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` @@ -469,8 +473,9 @@ proc runAllExamples(d: PDoc) = 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", os.getAppFilename(), + "nim", quoteShell(os.getAppFilename()), "backend", $d.conf.backend, "path", quoteShell(d.conf.projectPath), "libpath", quoteShell(d.conf.libpath), @@ -480,12 +485,14 @@ proc runAllExamples(d: PDoc) = "docCmd", group.docCmd, ] if os.execShellCmd(cmd) != 0: - quit "[runnableExamples] failed: generated file: '$1' group: '$2' cmd: $3" % [outp.string, $group[], cmd] + quit "[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 prepareExample(d: PDoc; n: PNode): tuple[rdoccmd: string, code: string] = ## returns `rdoccmd` and source code for this runnableExamples var rdoccmd = "" @@ -496,19 +503,48 @@ proc prepareExample(d: PDoc; n: PNode): tuple[rdoccmd: string, code: string] = if n1.kind notin nkStrKinds: globalError(d.conf, n1.info, "string litteral expected") rdoccmd = n1.strVal - var docComment = newTree(nkCommentStmt) + let useRenderModule = false let loc = d.conf.toFileLineCol(n.info) + let code = extractRunnableExamplesSource(d.conf, n) - docComment.comment = "autogenerated by docgen\nloc: $1\nrdoccmd: $2" % [loc, rdoccmd] - var runnableExamples = newTree(nkStmtList, - docComment, - newTree(nkImportStmt, newStrNode(nkStrLit, d.filename))) - runnableExamples.info = n.info - let ret = extractRunnableExamplesSource(d.conf, n) - for a in n.lastSon: runnableExamples.add a - # we could also use `ret` instead here, to keep sources verbatim - writeExample(d, runnableExamples, rdoccmd) - result = (rdoccmd, ret) + if d.conf.errorCounter > 0: + return (rdoccmd, code) + + let comment = "autogenerated by docgen\nloc: $1\nrdoccmd: $2" % [loc, rdoccmd] + let outputDir = d.exampleOutputDir + createDir(outputDir) + inc d.exampleCounter + let outp = outputDir / RelativeFile(extractFilename(d.filename.changeFileExt"" & ("_examples$1.nim" % $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) + + else: + let code2 = """ +#[ +$1 +]# +import $2 +$3 +""" % [comment, d.filename.quoted, code] + writeFile(outp.string, code2) + + 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 + result = (rdoccmd, code) when false: proc extractImports(n: PNode; result: PNode) = if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}: @@ -560,7 +596,7 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var Rope, state: Runnab "\n\\textbf{$1}\n", [msg.rope]) inc d.listingCounter let id = $d.listingCounter - dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim"]) + dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim", ""]) var dest2 = "" renderNimCode(dest2, code, isLatex = d.conf.cmd == cmdRst2tex) dest.add dest2 @@ -671,8 +707,8 @@ proc getRstName(n: PNode): PRstNode = case n.kind of nkPostfix: result = getRstName(n[1]) of nkPragmaExpr: result = getRstName(n[0]) - of nkSym: result = newRstNode(rnLeaf, n.sym.renderDefinitionName) - of nkIdent: result = newRstNode(rnLeaf, n.ident.s) + of nkSym: result = newRstLeaf(n.sym.renderDefinitionName) + of nkIdent: result = newRstLeaf(n.ident.s) of nkAccQuoted: result = getRstName(n[0]) for i in 1..$1", + "\\\\\\vspace{0.5em}\\large $1", [d.meta[metaSubtitle].rope]) var groupsection = getConfigVar(d.conf, "doc.body_toc_groupsection") let bodyname = if d.hasToc and not d.isPureRst: @@ -1233,18 +1273,18 @@ proc genOutFile(d: PDoc, groupedToc = false): Rope = elif d.hasToc: "doc.body_toc" else: "doc.body_no_toc" let seeSrcRope = genSeeSrcRope(d, d.filename, 1) - content = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, bodyname), ["title", + content = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, bodyname), ["title", "subtitle", "tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg", "theindexhref", "body_toc_groupsection", "seeSrc"], - [title.rope, toc, d.modDesc, rope(getDateStr()), + [title.rope, subtitle, toc, d.modDesc, rope(getDateStr()), rope(getClockStr()), code, d.modDeprecationMsg, relLink(d.conf.outDir, d.destFile.AbsoluteFile, theindexFname.RelativeFile), groupsection.rope, seeSrcRope]) if optCompileOnly notin d.conf.globalOptions: # XXX what is this hack doing here? 'optCompileOnly' means raw output!? code = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.file"), [ - "nimdoccss", "dochackjs", "title", "tableofcontents", "moduledesc", "date", "time", + "nimdoccss", "dochackjs", "title", "subtitle", "tableofcontents", "moduledesc", "date", "time", "content", "author", "version", "analytics", "deprecationMsg"], [relLink(d.conf.outDir, d.destFile.AbsoluteFile, nimdocOutCss.RelativeFile), relLink(d.conf.outDir, d.destFile.AbsoluteFile, docHackJsFname.RelativeFile), - title.rope, toc, d.modDesc, rope(getDateStr()), rope(getClockStr()), + title.rope, subtitle, toc, d.modDesc, rope(getDateStr()), rope(getClockStr()), content, d.meta[metaAuthor].rope, d.meta[metaVersion].rope, d.analytics.rope, d.modDeprecationMsg]) else: code = content @@ -1331,8 +1371,9 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef; 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 rst = parseRst(readFile(filen.string), filen.string, + line=LineRstInit, column=ColRstInit, + d.hasToc, {roSupportRawDirective, roSupportMarkdown}, conf) var modDesc = newStringOfCap(30_000) renderRstToOut(d[], rst, modDesc) d.modDesc = rope(modDesc) @@ -1396,11 +1437,11 @@ proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") let code = ropeFormatNamedVars(conf, getConfigVar(conf, "doc.file"), [ "nimdoccss", "dochackjs", - "title", "tableofcontents", "moduledesc", "date", "time", + "title", "subtitle", "tableofcontents", "moduledesc", "date", "time", "content", "author", "version", "analytics"], [relLink(conf.outDir, filename, nimdocOutCss.RelativeFile), relLink(conf.outDir, filename, docHackJsFname.RelativeFile), - rope"Index", nil, nil, rope(getDateStr()), + rope"Index", rope"", nil, nil, rope(getDateStr()), rope(getClockStr()), content, nil, nil, nil]) # no analytics because context is not available diff --git a/compiler/enumtostr.nim b/compiler/enumtostr.nim index 3274462d70..9bfa7001a9 100644 --- a/compiler/enumtostr.nim +++ b/compiler/enumtostr.nim @@ -2,15 +2,15 @@ import ast, idents, lineinfos, modulegraphs, magicsys proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym = - result = newSym(skProc, getIdent(g.cache, "$"), nextId idgen, t.owner, info) + result = newSym(skProc, getIdent(g.cache, "$"), nextSymId idgen, t.owner, info) - let dest = newSym(skParam, getIdent(g.cache, "e"), nextId idgen, result, info) + let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info) dest.typ = t - let res = newSym(skResult, getIdent(g.cache, "result"), nextId idgen, result, info) + let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info) res.typ = getSysType(g, info, tyString) - result.typ = newType(tyProc, nextId idgen, t.owner) + result.typ = newType(tyProc, nextTypeId idgen, t.owner) result.typ.n = newNodeI(nkFormalParams, info) rawAddSon(result.typ, res.typ) result.typ.n.add newNodeI(nkEffectList, info) @@ -63,15 +63,15 @@ proc searchObjCase(t: PType; field: PSym): PNode = doAssert result != nil proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym = - result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), nextId idgen, t.owner, info) + result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), nextSymId idgen, t.owner, info) - let dest = newSym(skParam, getIdent(g.cache, "e"), nextId idgen, result, info) + let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info) dest.typ = field.typ - let res = newSym(skResult, getIdent(g.cache, "result"), nextId idgen, result, info) + let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info) res.typ = getSysType(g, info, tyUInt8) - result.typ = newType(tyProc, nextId idgen, t.owner) + result.typ = newType(tyProc, nextTypeId idgen, t.owner) result.typ.n = newNodeI(nkFormalParams, info) rawAddSon(result.typ, res.typ) result.typ.n.add newNodeI(nkEffectList, info) diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 218a597d8d..a85314ac2f 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -49,7 +49,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = internalAssert c.config, sfGenSym in s.flags or s.kind == skType var x = PSym(idTableGet(c.mapping, s)) if x == nil: - x = copySym(s, nextId(c.idgen)) + x = copySym(s, nextSymId(c.idgen)) # sem'check needs to set the owner properly later, see bug #9476 x.owner = nil # c.genSymOwner #if x.kind == skParam and x.owner.kind == skModule: @@ -187,7 +187,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; ctx.instID = instID[] ctx.idgen = idgen - let body = tmpl.getBody + let body = tmpl.ast[bodyPos] #echo "instantion of ", renderTree(body, {renderIds}) if isAtom(body): result = newNodeI(nkPar, body.info) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index e37e867daa..e95ed893b6 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -12,9 +12,9 @@ # from a lineinfos file, to provide generalized procedures to compile # nim files. -import - ropes, os, strutils, osproc, platform, condsyms, options, msgs, - lineinfos, std / sha1, streams, pathutils, sequtils, times, strtabs +import ropes, platform, condsyms, options, msgs, lineinfos, pathutils + +import std/[os, strutils, osproc, sha1, streams, sequtils, times, strtabs, json] type TInfoCCProp* = enum # properties of the C compiler: @@ -124,8 +124,8 @@ compiler llvmGcc: result.name = "llvm_gcc" result.compilerExe = "llvm-gcc" result.cppCompiler = "llvm-g++" - when defined(macosx): - # OS X has no 'llvm-ar' tool: + when defined(macosx) or defined(openbsd): + # `llvm-ar` not available result.buildLib = "ar rcs $libfile $objfiles" else: result.buildLib = "llvm-ar rcs $libfile $objfiles" @@ -571,10 +571,10 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, includeCmd.add(join([CC[c].includeCmd, quoteShell(conf.projectPath.string)])) - var cf = if noAbsolutePaths(conf): AbsoluteFile extractFilename(cfile.cname.string) + let cf = if noAbsolutePaths(conf): AbsoluteFile extractFilename(cfile.cname.string) else: cfile.cname - var objfile = + let objfile = if cfile.obj.isEmpty: if CfileFlag.External notin cfile.flags or noAbsolutePaths(conf): toObjFile(conf, cf).string @@ -629,8 +629,8 @@ proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash = proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool = if conf.backend == backendJs: return false # pre-existing behavior, but not sure it's good - var hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1") - var currentHash = footprint(conf, cfile) + let hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1") + let currentHash = footprint(conf, cfile) var f: File if open(f, hashFile.string, fmRead): let oldHash = parseSecureHash(f.readLine()) @@ -662,6 +662,7 @@ proc addExternalFileToCompile*(conf: ConfigRef; filename: AbsoluteFile) = proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile, objfiles: string, isDllBuild: bool): string = if optGenStaticLib in conf.globalOptions: + removeFile output # fixes: bug #16947 result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(output), "objfiles", objfiles] else: @@ -848,7 +849,10 @@ proc callCCompiler*(conf: ConfigRef) = var cmds: TStringSeq var prettyCmds: TStringSeq let prettyCb = proc (idx: int) = - if prettyCmds[idx].len > 0: echo prettyCmds[idx] + if prettyCmds[idx].len > 0: + flushDot(conf) + # xxx should probably use stderr like other compiler messages, not stdout + echo prettyCmds[idx] for idx, it in conf.toCompile: # call the C compiler for the .c file: @@ -899,8 +903,8 @@ proc callCCompiler*(conf: ConfigRef) = # 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: let mainObjFile = getObjFilePath(conf, conf.toCompile[mainFileIdx]) - var src = conf.hcrLinkTargetName(mainObjFile, true) - var dst = conf.prepareToWriteOutput + let src = conf.hcrLinkTargetName(mainObjFile, true) + let dst = conf.prepareToWriteOutput copyFileWithPermissions(src.string, dst.string) else: for x in conf.toCompile: @@ -929,20 +933,15 @@ 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 writeJsonBuildInstructions*(conf: ConfigRef) = - 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) + template lit(x: string) = f.write x + template str(x: string) = + buf.setLen 0 + escapeJson(x, buf) + f.write buf proc cfiles(conf: ConfigRef; f: File; buf: var string; clist: CfileList, isExternal: bool) = var comma = false @@ -978,7 +977,7 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = pastStart = true lit "\L" - proc depfiles(conf: ConfigRef; f: File) = + proc depfiles(conf: ConfigRef; f: File; buf: var string) = var i = 0 for it in conf.m.fileInfos: let path = it.fullPath.string @@ -1023,12 +1022,14 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = lit $(%* conf.projectIsCmd) lit ",\L\"cmdInput\": " lit $(%* conf.cmdInput) + lit ",\L\"currentDir\": " + lit $(%* getCurrentDir()) if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"): lit ",\L\"cmdline\": " str conf.commandLine lit ",\L\"depfiles\":[\L" - depfiles(conf, f) + depfiles(conf, f, buf) lit "],\L\"nimexe\": \L" str hashNimExe() lit "\L" @@ -1043,14 +1044,23 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; projectfile: Absol result = false try: let data = json.parseFile(jsonFile.string) - if not data.hasKey("depfiles") or not data.hasKey("cmdline"): + for key in "depfiles cmdline stdinInput currentDir".split: + if not data.hasKey(key): return true + if getCurrentDir() != data["currentDir"].getStr: + # fixes bug #16271 + # Note that simply comparing `expandFilename(projectFile)` would + # not be sufficient in case other flags depend implicitly on `getCurrentDir`, + # and would require much more care. Simply re-compiling is safer for now. + # A better strategy for future work would be to cache (with an LRU cache) + # the N most recent unique build instructions, as done with `rdmd`, + # which is both robust and avoids recompilation when switching back and forth + # between projects, see https://github.com/timotheecour/Nim/issues/199 return true let oldCmdLine = data["cmdline"].getStr if conf.commandLine != oldCmdLine: return true if hashNimExe() != data["nimexe"].getStr: return true - if not data.hasKey("stdinInput"): return true let stdinInput = data["stdinInput"].getBool let projectIsCmd = data["projectIsCmd"].getBool if conf.projectIsStdin or stdinInput: diff --git a/compiler/guards.nim b/compiler/guards.nim index 4f07df201a..0281421276 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -82,26 +82,6 @@ proc isLetLocation(m: PNode, isApprox: bool): bool = proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true) -type - Operators* = object - opNot*, opContains*, opLe*, opLt*, opAnd*, opOr*, opIsNil*, opEq*: PSym - opAdd*, opSub*, opMul*, opDiv*, opLen*: PSym - -proc initOperators*(g: ModuleGraph): Operators = - result.opLe = createMagic(g, "<=", mLeI) - result.opLt = createMagic(g, "<", mLtI) - result.opAnd = createMagic(g, "and", mAnd) - result.opOr = createMagic(g, "or", mOr) - result.opIsNil = createMagic(g, "isnil", mIsNil) - result.opEq = createMagic(g, "==", mEqI) - result.opAdd = createMagic(g, "+", mAddI) - result.opSub = createMagic(g, "-", mSubI) - result.opMul = createMagic(g, "*", mMulI) - result.opDiv = createMagic(g, "div", mDivI) - result.opLen = createMagic(g, "len", mLengthSeq) - result.opNot = createMagic(g, "not", mNot) - result.opContains = createMagic(g, "contains", mInSet) - proc swapArgs(fact: PNode, newOp: PSym): PNode = result = newNodeI(nkCall, fact.info, 3) result[0] = newSymNode(newOp) @@ -404,16 +384,16 @@ proc usefulFact(n: PNode; o: Operators): PNode = type TModel* = object s*: seq[PNode] # the "knowledge base" - o*: Operators + g*: ModuleGraph beSmart*: bool proc addFact*(m: var TModel, nn: PNode) = - let n = usefulFact(nn, m.o) + let n = usefulFact(nn, m.g.operators) if n != nil: if not m.beSmart: m.s.add n else: - let c = canon(n, m.o) + let c = canon(n, m.g.operators) if c.getMagic == mAnd: addFact(m, c[1]) addFact(m, c[2]) @@ -421,7 +401,7 @@ proc addFact*(m: var TModel, nn: PNode) = m.s.add c proc addFactNeg*(m: var TModel, n: PNode) = - let n = n.neg(m.o) + let n = n.neg(m.g.operators) if n != nil: addFact(m, n) proc sameOpr(a, b: PSym): bool = @@ -740,7 +720,7 @@ proc doesImply*(facts: TModel, prop: PNode): TImplication = if result != impUnknown: return proc impliesNotNil*(m: TModel, arg: PNode): TImplication = - result = doesImply(m, m.o.opIsNil.buildCall(arg).neg(m.o)) + result = doesImply(m, m.g.operators.opIsNil.buildCall(arg).neg(m.g.operators)) proc simpleSlice*(a, b: PNode): BiggestInt = # returns 'c' if a..b matches (i+c)..(i+c), -1 otherwise. (i)..(i) is matched @@ -794,12 +774,7 @@ macro `=~`(x: PNode, pat: untyped): bool = var conds = newTree(nnkBracket) m(x, pat, conds) - when compiles(nestList(ident"and", conds)): - result = nestList(ident"and", conds) - #elif declared(macros.toNimIdent): - # result = nestList(toNimIdent"and", conds) - else: - result = nestList(!"and", conds) + result = nestList(ident"and", conds) proc isMinusOne(n: PNode): bool = n.kind in {nkCharLit..nkUInt64Lit} and n.intVal == -1 @@ -833,7 +808,7 @@ proc ple(m: TModel; a, b: PNode): TImplication = 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.o.opSub.buildCall(a, b[2]), m.o) <=? b[1]): + if b[2] <=? zero() and (canon(m.g.operators.opSub.buildCall(a, b[2]), m.g.operators) <=? b[1]): return impYes # x+c <= y if c <= 0 and x <= y @@ -847,20 +822,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.o.opDiv, a[1][1], `|div|`(a[1][2], a[2])), b) == impYes: + if ple(m, buildCall(m.g.operators.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.o.opAdd.buildCall(ec, minusOne()) + let ec1 = m.g.operators.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.o.opAdd.buildCall(ec, minusOne()) + let ec1 = m.g.operators.opAdd.buildCall(ec, minusOne()) if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? zero(): return impYes @@ -963,12 +938,12 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication = var b = bb if replacements.len > 0: m.s = @[] - m.o = model.o + m.g = model.g # 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.o) + m.s.add applyReplacements(fact, replacements).canon(m.g.operators) a = applyReplacements(aa, replacements) b = applyReplacements(bb, replacements) else: @@ -977,19 +952,19 @@ 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.o.opLe.buildCall(a, b), m.o) + let x = canon(m.g.operators.opLe.buildCall(a, b), m.g.operators) #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.o.opLe.buildCall(m.o.opAdd.buildCall(b, one()), a), m.o) + let y = canon(m.g.operators.opLe.buildCall(m.g.operators.opAdd.buildCall(b, one()), a), m.g.operators) result = ~ple(m, y[1], y[2]) proc addFactLe*(m: var TModel; a, b: PNode) = - m.s.add canon(m.o.opLe.buildCall(a, b), m.o) + 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.o.opAdd.buildCall(b, minusOne()) + let bb = m.g.operators.opAdd.buildCall(b, minusOne()) addFactLe(m, a, bb) proc settype(n: PNode): PType = @@ -1021,14 +996,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.o.opEq) + fact[0] = newSymNode(m.g.operators.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.o.opEq) + fact[0] = newSymNode(m.g.operators.opEq) fact[1] = key fact[2] = value m.s.add fact @@ -1044,7 +1019,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.o.opEq) + check[0] = newSymNode(m.g.operators.opEq) check[1] = a check[2] = b result = m.doesImply(check) == impYes @@ -1052,9 +1027,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.o) + m.s.add buildOf(branch, n[0], m.g.operators) else: - m.s.add n.buildElse(m.o).neg(m.o) + m.s.add n.buildElse(m.g.operators).neg(m.g.operators) proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode = if check[1].kind == nkCurly: @@ -1072,6 +1047,6 @@ proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode = proc checkFieldAccess*(m: TModel, n: PNode; conf: ConfigRef) = for i in 1.. 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 index 1a33f6a27b..d8e1315b1d 100644 --- a/compiler/ic/design.rst +++ b/compiler/ic/design.rst @@ -29,14 +29,32 @@ mechanism needs to be implemented that we could get wrong. ModuleIds are rod-file specific too. -Configuration setup changes ---------------------------- - -For a MVP these are not detected. Later the configuration will be -stored in every `.rod` file. - Global state ------------ -Global persistent state will be kept in a project specific `.rod` file. +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/from_packed_ast.nim b/compiler/ic/from_packed_ast.nim deleted file mode 100644 index cb2ecee79e..0000000000 --- a/compiler/ic/from_packed_ast.nim +++ /dev/null @@ -1,12 +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 std / [hashes, tables] -import bitabs -import ".." / [ast, lineinfos, options, pathutils] diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim new file mode 100644 index 0000000000..99a68e0f03 --- /dev/null +++ b/compiler/ic/ic.nim @@ -0,0 +1,1147 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import std / [hashes, tables, intsets, sha1] +import packed_ast, bitabs, rodfiles +import ".." / [ast, idents, lineinfos, msgs, ropes, options, + pathutils, condsyms] +#import ".." / [renderer, astalgo] +from std / os import removeFile, isAbsolute + +type + PackedConfig* = object + backend: TBackend + selectedGC: TGCMode + cCompiler: TSystemCC + options: TOptions + globalOptions: TGlobalOptions + + PackedModule* = object ## the parts of a PackedEncoder that are part of the .rod file + definedSymbols: string + 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)] + reexports*: seq[(LitId, PackedItemId)] + compilerProcs*: seq[(LitId, int32)] + converters*, methods*, trmacros*, pureEnums*: seq[int32] + 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)] + + sh*: Shared + 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 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 + +proc configIdentical(m: PackedModule; config: ConfigRef): bool = + result = m.definedSymbols == definedSymbolsAsString(config) + #if not result: + # echo "A ", m.definedSymbols, " ", definedSymbolsAsString(config) + template eq(x) = + result = result and m.cfg.x == config.x + #if not result: + # 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.sh.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.sh.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 + m.sh = Shared() + c.thisModule = moduleSym.itemId.module + c.config = config + m.bodies = newTreeFrom(m.topLevel) + m.toReplay = newTreeFrom(m.topLevel) + + 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 addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) = + let nameId = getOrIncl(m.sh.strings, s.name.s) + m.exports.add((nameId, s.itemId.item)) + +proc addConverter*(c: var PackedEncoder; m: var PackedModule; s: PSym) = + 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.sh.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.sh.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.sh.strings, x) + +proc toLitId(x: BiggestInt; m: var PackedModule): LitId = + ## store an integer as a literal + result = getOrIncl(m.sh.integers, 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 + + if t.uniqueId.module != c.thisModule: + # XXX Assert here that it already was serialized in the foreign module! + # it is a foreign type: + assert t.uniqueId.module >= 0 + assert t.uniqueId.item > 0 + return PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) + assert t.itemId.module >= 0 + assert t.uniqueId.item > 0 + result = PackedItemId(module: toLitId(t.itemId.module.FileIndex, c, m), item: t.uniqueId.item) + addMissing(c, t) + +proc storeSymLater(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId = + if s.isNil: return nilItemId + assert s.itemId.module >= 0 + if s.itemId.module != c.thisModule: + # XXX Assert here that it already was serialized in the foreign module! + # it is a foreign symbol: + assert s.itemId.module >= 0 + return PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item) + assert s.itemId.module >= 0 + result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item) + addMissing(c, s) + +proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId = + ## serialize a ptype + if t.isNil: return nilItemId + + if t.uniqueId.module != c.thisModule: + # XXX Assert here that it already was serialized in the foreign module! + # it is a foreign type: + assert t.uniqueId.module >= 0 + assert t.uniqueId.item > 0 + return PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) + + if not c.typeMarker.containsOrIncl(t.uniqueId.item): + if t.uniqueId.item >= m.sh.types.len: + setLen m.sh.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, lockLevel: t.lockLevel) + storeNode(p, t, n) + + when false: + for op, s in pairs t.attachedOps: + c.addMissing s + p.attachedOps[op] = s.safeItemId(c, m) + + p.typeInst = t.typeInst.storeType(c, m) + for kid in items t.sons: + p.types.add kid.storeType(c, m) + + when false: + for i, s in items t.methods: + c.addMissing s + p.methods.add (i, s.safeItemId(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.sh.types[t.uniqueId.item] = p + + assert t.itemId.module >= 0 + assert t.uniqueId.item > 0 + result = PackedItemId(module: toLitId(t.itemId.module.FileIndex, c, m), item: t.uniqueId.item) + +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 + + if s.itemId.module != c.thisModule: + # XXX Assert here that it already was serialized in the foreign module! + # it is a foreign symbol: + assert s.itemId.module >= 0 + return PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item) + + if not c.symMarker.containsOrIncl(s.itemId.item): + if s.itemId.item >= m.sh.syms.len: + setLen m.sh.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(if s.loc.r.isNil: "" else: $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.sh.syms[s.itemId.item] = p + + assert s.itemId.module >= 0 + result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item) + +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.sh.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.sh.integers, 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.sh.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.sh.floats, 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.sh.types.len + + if g[si].types[t.item] == nil: + result = typeHeaderFromPacked(c, g, g[si].fromDisk.sh.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.sh.types[t.item], si, t.item, result) + else: + result = g[si].types[t.item] + assert result.itemId.item > 0 + +proc newPackage(config: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym = + let filename = AbsoluteFile toFullPath(config, fileIdx) + let name = getIdent(cache, splitFile(filename).name) + let info = newLineInfo(fileIdx, 1, 1) + let + pck = getPackageName(config, filename.string) + pck2 = if pck.len > 0: pck else: "unknown" + pack = getIdent(cache, pck2) + result = newSym(skPackage, getIdent(cache, pck2), + ItemId(module: PackageModuleId, item: int32(fileIdx)), nil, info) + +proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; + fileIdx: FileIndex; m: var LoadedModule) = + m.iface = initTable[PIdent, seq[PackedItemId]]() + for e in m.fromDisk.exports: + let nameLit = e[0] + m.iface.mgetOrPut(cache.getIdent(m.fromDisk.sh.strings[nameLit]), @[]).add(PackedItemId(module: LitId(0), item: e[1])) + for re in m.fromDisk.reexports: + let nameLit = re[0] + m.iface.mgetOrPut(cache.getIdent(m.fromDisk.sh.strings[nameLit]), @[]).add(re[1]) + + 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 = newPackage(conf, cache, fileIdx) + if fileIdx == conf.projectMainIdx2: + m.module.flags.incl sfMainModule + +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: + 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.sh.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.sh.syms): + if m.sh.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.sh.types): + inc nones, m.sh.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 + +proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache; + g: var PackedModuleGraph; module: FileIndex; + name: PIdent): PSym = + it.decoder = PackedDecoder( + lastModule: int32(-1), + lastLit: LitId(0), + lastFile: FileIndex(-1), + config: config, + cache: cache) + it.values = g[int module].iface.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): 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].iface.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): PSym = + setupDecoder() + let values = g[int module].iface.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): PSym = + setupDecoder() + let values = g[int module].iface.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.sh.syms.len, + typeId: int32 m.fromDisk.sh.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.sh.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: + echo "Error: could not load: ", rodfile.string, " reason: ", err + quit 1 + + when true: + echo "exports:" + for ex in m.exports: + echo " ", m.sh.strings[ex[0]], " local ID: ", ex[1] + assert ex[0] == m.sh.syms[ex[1]].name + # ex[1] int32 + + echo "reexports:" + for ex in m.reexports: + echo " ", m.sh.strings[ex[0]] + # reexports*: seq[(LitId, PackedItemId)] + + echo "all symbols" + for i in 0..high(m.sh.syms): + echo " ", m.sh.strings[m.sh.syms[i].name], " local ID: ", i + + echo "symbols: ", m.sh.syms.len, " types: ", m.sh.types.len, + " top level nodes: ", m.topLevel.nodes.len, " other nodes: ", m.bodies.nodes.len, + " strings: ", m.sh.strings.len, " integers: ", m.sh.integers.len, + " floats: ", m.sh.floats.len diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index ef609e8c87..353cc3a42e 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -12,43 +12,28 @@ ## use this representation directly in all the transformations, ## it is superior. -import std / [hashes, tables] +import std / [hashes, tables, strtabs] import bitabs -import ".." / [ast, lineinfos, options, pathutils] - -const - localNamePos* = 0 - localExportMarkerPos* = 1 - localPragmaPos* = 2 - localTypePos* = 3 - localValuePos* = 4 - - typeNamePos* = 0 - typeExportMarkerPos* = 1 - typeGenericParamsPos* = 2 - typePragmaPos* = 3 - typeBodyPos* = 4 - - routineNamePos* = 0 - routineExportMarkerPos* = 1 - routinePatternPos* = 2 - routineGenericParamsPos* = 3 - routineParamsPos* = 4 - routineResultPos* = 5 - routinePragmasPos* = 6 - routineBodyPos* = 7 - -const - nkModuleRef = nkNone # pair of (ModuleId, SymId) +import ".." / [ast, options] type SymId* = distinct int32 - TypeId* = 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 @@ -64,19 +49,20 @@ type PackedSym* = object kind*: TSymKind name*: LitId - typeId*: TypeId + typ*: PackedItemId flags*: TSymFlags magic*: TMagic info*: PackedLineInfo - ast*: NodePos - owner*: ItemId - guard*: ItemId + 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 @@ -84,103 +70,91 @@ type PackedType* = object kind*: TTypeKind - nodekind*: TNodeKind + callConv*: TCallingConvention + #nodekind*: TNodeKind flags*: TTypeFlags - types*: int32 - nodes*: int32 - methods*: int32 - nodeflags*: TNodeFlags - info*: PackedLineInfo - sym*: ItemId - owner*: ItemId - attachedOps*: array[TTypeAttachedOp, ItemId] + types*: seq[PackedItemId] + n*: NodeId + #nodeflags*: TNodeFlags + sym*: PackedItemId + owner*: PackedItemId size*: BiggestInt align*: int16 paddingAtEnd*: int16 lockLevel*: TLockLevel # lock level as required for deadlock checking # not serialized: loc*: TLoc because it is backend-specific - typeInst*: TypeId - nonUniqueId*: ItemId + typeInst*: PackedItemId + nonUniqueId*: int32 - Node* = object # 20 bytes + PackedNode* = object # 20 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*: TypeId + typeId*: PackedItemId info*: PackedLineInfo - ModulePhase* = enum - preLookup, lookedUpTopLevelStmts - - Module* = object - name*: string - file*: AbsoluteFile - ast*: PackedTree - phase*: ModulePhase - iface*: Table[string, seq[SymId]] # 'seq' because of overloading - - Program* = ref object - modules*: seq[Module] + PackedTree* = object ## usually represents a full Nim module + nodes*: seq[PackedNode] + #sh*: Shared Shared* = ref object # shared between different versions of 'Module'. # (though there is always exactly one valid # version of a module) syms*: seq[PackedSym] - types*: seq[seq[Node]] + types*: seq[PackedType] strings*: BiTable[string] # we could share these between modules. integers*: BiTable[BiggestInt] floats*: BiTable[BiggestFloat] - config*: ConfigRef - #thisModule*: ModuleId - #program*: Program + #config*: ConfigRef - PackedTree* = object ## usually represents a full Nim module - nodes*: seq[Node] - toPosition*: Table[SymId, NodePos] - sh*: Shared + 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: TypeId): bool {.borrow.} -proc `==`*(a, b: ModuleId): bool {.borrow.} - -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 `==`*(a, b: PackedItemId): bool {.borrow.} +proc `==`*(a, b: NodeId): bool {.borrow.} proc newTreeFrom*(old: PackedTree): PackedTree = result.nodes = @[] - result.sh = old.sh + when false: result.sh = old.sh -proc litIdFromName*(tree: PackedTree; name: string): LitId = - result = tree.sh.strings.getOrIncl(name) +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 add*(tree: var PackedTree; kind: TNodeKind; token: string; info: PackedLineInfo) = - tree.nodes.add Node(kind: kind, operand: int32 getOrIncl(tree.sh.strings, token), info: info) + proc litIdFromName*(tree: PackedTree; name: string): LitId = + result = tree.sh.strings.getOrIncl(name) -proc add*(tree: var PackedTree; kind: TNodeKind; info: PackedLineInfo) = - tree.nodes.add Node(kind: kind, operand: 0, info: info) + 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 Node(kind: nkIdent, operand: int32(s), info: info) + tree.nodes.add PackedNode(kind: nkIdent, operand: int32(s), info: info) -proc addSym*(tree: var PackedTree; s: SymId; info: PackedLineInfo) = - tree.nodes.add Node(kind: nkSym, 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 Node(kind: nkInt32Lit, operand: int32(s), info: info) + tree.nodes.add PackedNode(kind: nkInt32Lit, operand: int32(s), info: info) proc addSymDef*(tree: var PackedTree; s: SymId; info: PackedLineInfo) = - tree.nodes.add Node(kind: nkSym, operand: int32(s), info: info) + tree.nodes.add PackedNode(kind: nkSym, operand: int32(s), info: info) proc isAtom*(tree: PackedTree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= nkNilLit @@ -194,11 +168,12 @@ proc copyTree*(dest: var PackedTree; tree: PackedTree; n: NodePos) = for i in 0.. nkNilLit: @@ -247,7 +224,8 @@ iterator sons*(dest: var PackedTree; tree: PackedTree; n: NodePos): NodePos = for x in sonsReadonly(tree, n): yield x patch dest, patchPos -iterator isons*(dest: var PackedTree; tree: PackedTree; n: NodePos): (int, NodePos) = +iterator isons*(dest: var PackedTree; tree: PackedTree; + n: NodePos): (int, NodePos) = var i = 0 for ch0 in sons(dest, tree, n): yield (i, ch0) @@ -301,12 +279,24 @@ proc hasAtLeastXsons*(tree: PackedTree; n: NodePos; x: int): bool = 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 +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 -proc span(tree: PackedTree; pos: int): int {.inline.} = +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) = @@ -330,7 +320,9 @@ proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos = inc count assert false, "node has no i-th child" -proc `@`*(tree: PackedTree; lit: LitId): lent string {.inline.} = tree.sh.strings[lit] +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 @@ -340,29 +332,30 @@ template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].operand proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1) -proc strLit*(tree: PackedTree; n: NodePos): lent string = - assert n.kind == nkStrLit - result = tree.sh.strings[LitId tree.nodes[n.int].operand] +when false: + 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 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 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] + 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, @@ -380,7 +373,8 @@ const externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit} directIntLit* = nkInt32Lit -proc toString*(tree: PackedTree; n: NodePos; nesting: int; result: var string) = +proc toString*(tree: PackedTree; n: NodePos; sh: Shared; nesting: int; + result: var string) = let pos = n.int if result.len > 0 and result[^1] notin {' ', '\n'}: result.add ' ' @@ -390,46 +384,47 @@ proc toString*(tree: PackedTree; n: NodePos; nesting: int; result: var string) = of nkNone, nkEmpty, nkNilLit, nkType: discard of nkIdent, nkStrLit..nkTripleStrLit: result.add " " - result.add tree.sh.strings[LitId tree.nodes[pos].operand] + result.add sh.strings[LitId tree.nodes[pos].operand] of nkSym: result.add " " - result.add tree.sh.strings[tree.sh.syms[tree.nodes[pos].operand].name] + result.add sh.strings[sh.syms[tree.nodes[pos].operand].name] of directIntLit: result.add " " result.addInt tree.nodes[pos].operand of externSIntLit: result.add " " - result.addInt tree.sh.integers[LitId tree.nodes[pos].operand] + result.addInt sh.integers[LitId tree.nodes[pos].operand] of externUIntLit: result.add " " - result.add $cast[uint64](tree.sh.integers[LitId tree.nodes[pos].operand]) + result.add $cast[uint64](sh.integers[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, nesting + 1, result) + toString(tree, child, sh, 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): string = +proc toString*(tree: PackedTree; n: NodePos; sh: Shared): string = result = "" - toString(tree, n, 0, result) + toString(tree, n, sh, 0, result) -proc debug*(tree: PackedTree) = - stdout.write toString(tree, NodePos 0) +proc debug*(tree: PackedTree; sh: Shared) = + stdout.write toString(tree, NodePos 0, sh) -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) +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 identId*(n: NodePos): LitId = identIdImpl(tree, n) template copyInto*(dest, n, body) = let patchPos = prepare(dest, tree, n) @@ -441,17 +436,20 @@ template copyIntoKind*(dest, kind, info, body) = body patch dest, patchPos -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: +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 - 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) = @@ -459,3 +457,13 @@ when false: 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 new file mode 100644 index 0000000000..61aa0e697f --- /dev/null +++ b/compiler/ic/replayer.nim @@ -0,0 +1,147 @@ +# +# +# 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 + +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 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)) + + 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) + + 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 new file mode 100644 index 0000000000..fa0a7c7342 --- /dev/null +++ b/compiler/ic/rodfiles.nim @@ -0,0 +1,174 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +from typetraits import supportsCopyMem + +type + RodSection* = enum + versionSection + configSection + stringsSection + checkSumsSection + depsSection + integersSection + floatsSection + exportsSection + reexportsSection + compilerProcsSection + trmacrosSection + convertersSection + methodsSection + pureEnumsSection + macroUsagesSection + toReplaySection + topLevelSection + bodiesSection + symsSection + typesSection + typeInstCacheSection + procInstCacheSection + attachedOpsSection + methodsPerTypeSection + enumToStringProcsSection + 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) = + 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) = + 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]) = + 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) = + 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]) = + 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, "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/injectdestructors.nim b/compiler/injectdestructors.nim index 34c11e06ca..b653912526 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -22,7 +22,16 @@ import from trees import exprStructuralEquivalent, getRoot type - Scope = object # well we do scope-based memory management. \ + Con = object + owner: PSym + g: ControlFlowGraph + graph: ModuleGraph + inLoop, inSpawn, inLoopCond: int + uninit: IntSet # set of uninit'ed vars + uninitComputed: bool + idgen: IdGenerator + + 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] @@ -31,17 +40,6 @@ type needsTry: bool parent: ptr Scope -type - Con = object - owner: PSym - g: ControlFlowGraph - graph: ModuleGraph - otherRead: PNode - inLoop, inSpawn, inLoopCond: int - uninit: IntSet # set of uninit'ed vars - uninitComputed: bool - idgen: IdGenerator - ProcessMode = enum normal consumed @@ -62,7 +60,7 @@ template dbg(body) = body proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = - let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), nextId c.idgen, c.owner, info) + let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), nextSymId c.idgen, c.owner, info) sym.typ = typ s.vars.add(sym) result = newSymNode(sym) @@ -73,123 +71,118 @@ proc nestedScope(parent: var Scope): Scope = proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; isDecl = false): PNode -proc isLastRead(location: PNode; cfg: ControlFlowGraph; otherRead: var PNode; pc, until: int): int = - var pc = pc - while pc < cfg.len and pc < until: - case cfg[pc].kind - of def: - if instrTargets(cfg[pc].n, location) == Full: - # the path leads to a redefinition of 's' --> abandon it. - return high(int) - elif instrTargets(cfg[pc].n, location) == Partial: - # only partially writes to 's' --> can't sink 's', so this def reads 's' - otherRead = cfg[pc].n - return -1 - inc pc - of use: - if instrTargets(cfg[pc].n, location) != None: - otherRead = cfg[pc].n - return -1 - inc pc - of goto: - pc += cfg[pc].dest - of fork: - # every branch must lead to the last read of the location: - var variantA = pc + 1 - var variantB = pc + cfg[pc].dest - while variantA != variantB: - if min(variantA, variantB) < 0: return -1 - if max(variantA, variantB) >= cfg.len or min(variantA, variantB) >= until: - break - if variantA < variantB: - variantA = isLastRead(location, cfg, otherRead, variantA, min(variantB, until)) - else: - variantB = isLastRead(location, cfg, otherRead, variantB, min(variantA, until)) - pc = min(variantA, variantB) - return pc +import sets, hashes, tables -proc isCursor(n: PNode; c: Con): bool = - case n.kind - of nkSym: - sfCursor in n.sym.flags - of nkDotExpr: - isCursor(n[1], c) - of nkCheckedFieldExpr: - isCursor(n[0], c) - else: - false +proc hash(n: PNode): Hash = hash(cast[pointer](n)) -proc isLastRead(n: PNode; c: var Con): bool = - # first we need to search for the instruction that belongs to 'n': - var instr = -1 - let m = dfa.skipConvDfa(n) - if m.kind == nkSym and sfSingleUsedTemp in m.sym.flags: return true +type AliasCache = Table[(PNode, PNode), AliasKind] +proc aliasesCached(cache: var AliasCache, obj, field: PNode): AliasKind = + let key = (obj, field) + if not cache.hasKey(key): + cache[key] = aliases(obj, field) + cache[key] - for i in 0..= c.g.len: return true - - c.otherRead = nil - result = isLastRead(n, c.g, c.otherRead, instr+1, int.high) >= 0 - dbg: echo "ugh ", c.otherRead.isNil, " ", result - -proc isFirstWrite(location: PNode; cfg: ControlFlowGraph; pc, until: int): int = - var pc = pc +proc collectLastReads(cfg: ControlFlowGraph; cache: var AliasCache, lastReads, potLastReads: var IntSet; pc: var int, until: int) = + template aliasesCached(obj, field: PNode): untyped = + aliasesCached(cache, obj, field) while pc < until: case cfg[pc].kind of def: - if instrTargets(cfg[pc].n, location) != None: - # a definition of 's' before ours makes ours not the first write - return -1 + let potLastReadsCopy = potLastReads + for r in potLastReadsCopy: + if cfg[pc].n.aliasesCached(cfg[r].n) == yes: + # the path leads to a redefinition of 's' --> sink 's'. + lastReads.incl r + potLastReads.excl r + elif cfg[r].n.aliasesCached(cfg[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' + cfg[r].n.comment = '\n' & $pc + potLastReads.excl r + inc pc of use: - if instrTargets(cfg[pc].n, location) != None: - return -1 + let potLastReadsCopy = potLastReads + for r in potLastReadsCopy: + if cfg[pc].n.aliasesCached(cfg[r].n) != no or cfg[r].n.aliasesCached(cfg[pc].n) != no: + cfg[r].n.comment = '\n' & $pc + potLastReads.excl r + + potLastReads.incl pc + inc pc of goto: pc += cfg[pc].dest of fork: - # every branch must not contain a def/use of our location: var variantA = pc + 1 var variantB = pc + cfg[pc].dest - while variantA != variantB: - if min(variantA, variantB) < 0: return -1 - if max(variantA, variantB) > until: - break + var potLastReadsA, potLastReadsB = potLastReads + var lastReadsA, lastReadsB: IntSet + while variantA != variantB and max(variantA, variantB) < cfg.len and min(variantA, variantB) < until: if variantA < variantB: - variantA = isFirstWrite(location, cfg, variantA, min(variantB, until)) + collectLastReads(cfg, cache, lastReadsA, potLastReadsA, variantA, min(variantB, until)) else: - variantB = isFirstWrite(location, cfg, variantB, min(variantA, until)) + collectLastReads(cfg, cache, lastReadsB, potLastReadsB, variantB, min(variantA, until)) + + # Add those last reads that were turned into last reads on both branches + lastReads.incl lastReadsA * lastReadsB + # Add those last reads that were turned into last reads on only one branch, + # but where the read operation itself also belongs to only that branch + lastReads.incl (lastReadsA + lastReadsB) - potLastReads + + let oldPotLastReads = potLastReads + potLastReads = initIntSet() + + potLastReads.incl potLastReadsA + potLastReadsB + + # Remove potential last reads that were invalidated in a branch, + # but don't remove those which were turned into last reads on that branch + potLastReads.excl ((oldPotLastReads - potLastReadsA) - lastReadsA) + potLastReads.excl ((oldPotLastReads - potLastReadsB) - lastReadsB) + pc = min(variantA, variantB) - return pc + +proc collectFirstWrites(cfg: ControlFlowGraph; alreadySeen: var HashSet[PNode]; pc: var int, until: int) = + while pc < until: + case cfg[pc].kind + of def: + var alreadySeenThisNode = false + for s in alreadySeen: + if cfg[pc].n.aliases(s) != no or s.aliases(cfg[pc].n) != no: + alreadySeenThisNode = true; break + if alreadySeenThisNode: cfg[pc].n.flags.excl nfFirstWrite + else: cfg[pc].n.flags.incl nfFirstWrite + + alreadySeen.incl cfg[pc].n + + inc pc + of use: + alreadySeen.incl cfg[pc].n + + inc pc + of goto: + pc += cfg[pc].dest + of fork: + var variantA = pc + 1 + var variantB = pc + cfg[pc].dest + var alreadySeenA, alreadySeenB = alreadySeen + while variantA != variantB and max(variantA, variantB) < cfg.len and min(variantA, variantB) < until: + if variantA < variantB: + collectFirstWrites(cfg, alreadySeenA, variantA, min(variantB, until)) + else: + collectFirstWrites(cfg, alreadySeenB, variantB, min(variantA, until)) + + alreadySeen.incl alreadySeenA + alreadySeenB + + pc = min(variantA, variantB) + +proc isLastRead(n: PNode; c: var Con): bool = + let m = dfa.skipConvDfa(n) + (m.kind == nkSym and sfSingleUsedTemp in m.sym.flags) or nfLastRead in m.flags proc isFirstWrite(n: PNode; c: var Con): bool = - # first we need to search for the instruction that belongs to 'n': - var instr = -1 let m = dfa.skipConvDfa(n) - - 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.g, 0, instr) >= 0 + nfFirstWrite in m.flags proc initialized(code: ControlFlowGraph; pc: int, init, uninit: var IntSet; until: int): int = @@ -229,20 +222,33 @@ proc initialized(code: ControlFlowGraph; pc: int, inc pc return pc +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 + template isUnpackedTuple(n: PNode): bool = ## we move out all elements of unpacked tuples, ## hence unpacked tuples themselves don't need to be destroyed (n.kind == nkSym and n.sym.kind == skTemp and n.sym.typ.kind == tyTuple) +from strutils import parseInt + 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: m.add "; requires a copy because it's not the last read of '" m.add renderTree(ri) m.add '\'' - if c.otherRead != nil: + if ri.comment.startsWith('\n'): m.add "; another read is done here: " - m.add c.graph.config $ c.otherRead.info + m.add c.graph.config $ c.g[parseInt(ri.comment[1..^1])].n.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) @@ -252,7 +258,7 @@ proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) = localError(c.graph.config, ri.info, errGenerated, m) proc makePtrType(c: var Con, baseType: PType): PType = - result = newType(tyPtr, nextId c.idgen, c.owner) + result = newType(tyPtr, nextTypeId c.idgen, c.owner) addSonSkipIntLit(result, baseType, c.idgen) proc genOp(c: var Con; op: PSym; dest: PNode): PNode = @@ -261,18 +267,18 @@ proc genOp(c: var Con; op: PSym; dest: PNode): PNode = result = newTree(nkCall, newSymNode(op), addrExp) proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode = - var op = t.attachedOps[kind] - if op == nil or op.ast[genericParamsPos].kind != nkEmpty: + var op = getAttachedOp(c.graph, t, kind) + if op == nil or op.ast.isGenericRoutine: # give up and find the canonical type instead: let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct}) let canon = c.graph.canonTypes.getOrDefault(h) if canon != nil: - op = canon.attachedOps[kind] + op = getAttachedOp(c.graph, canon, 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[genericParamsPos].kind != nkEmpty: + elif op.ast.isGenericRoutine: globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] & "' operator is generic") dbg: @@ -288,9 +294,9 @@ proc genDestroy(c: var Con; dest: PNode): PNode = 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 t.attachedOps[attachedSink] != nil + result = t.kind != tyRef and getAttachedOp(c.graph, t, attachedSink) != nil else: - result = t.attachedOps[attachedSink] != nil + result = getAttachedOp(c.graph, t, attachedSink) != nil proc isNoInit(dest: PNode): bool {.inline.} = result = dest.kind == nkSym and sfNoInit in dest.sym.flags @@ -303,7 +309,7 @@ proc genSink(c: var Con; dest, ri: PNode, isDecl = false): PNode = result = newTree(nkFastAsgn, dest, ri) else: let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) - if t.attachedOps[attachedSink] != nil: + if getAttachedOp(c.graph, t, attachedSink) != nil: result = c.genOp(t, attachedSink, dest, ri) result.add ri else: @@ -344,7 +350,7 @@ proc genMarkCyclic(c: var Con; result, dest: PNode) = if t.kind == tyRef: result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest) else: - let xenv = genBuiltin(c.graph, mAccessEnv, "accessEnv", dest) + 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) @@ -356,7 +362,6 @@ 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 c.otherRead == nil: discard isLastRead(ri, c) c.checkForErrorPragma(t, ri, "=copy") result = c.genCopyNoCheck(dest, ri) @@ -376,8 +381,8 @@ proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode = let objType = leDotExpr[0].typ if hasDestructor(c, objType): - if objType.attachedOps[attachedDestructor] != nil and - sfOverriden in objType.attachedOps[attachedDestructor].flags: + 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) @@ -390,21 +395,21 @@ It is best to factor out piece of object that needs custom destructor into separ cond.add le cond.add tmp let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool)) - notExpr.add newSymNode(createMagic(c.graph, "not", mNot)) + 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 = result = newNodeI(nkCall, n.info) - result.add(newSymNode(createMagic(c.graph, "wasMoved", mWasMoved))) + result.add(newSymNode(createMagic(c.graph, c.idgen, "wasMoved", mWasMoved))) result.add copyTree(n) #mWasMoved does not take the address #if n.kind != nkSym: # message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")") proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode = result = newNodeI(nkCall, info) - result.add(newSymNode(createMagic(c.graph, "default", mDefault))) + result.add(newSymNode(createMagic(c.graph, c.idgen, "default", mDefault))) result.typ = t proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = @@ -415,7 +420,7 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = else: result = newNodeIT(nkStmtListExpr, n.info, n.typ) - var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), nextId c.idgen, c.owner, n.info) + var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), nextSymId c.idgen, c.owner, n.info) temp.typ = n.typ var v = newNodeI(nkLetSection, n.info) let tempAsNode = newSymNode(temp) @@ -523,23 +528,19 @@ proc cycleCheck(n: PNode; c: var Con) = message(c.graph.config, n.info, warnCycleCreated, msg) break -proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) = +proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; res: PNode) = # move the variable declaration to the top of the frame: s.vars.add v.sym if isUnpackedTuple(v): if c.inLoop > 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: + 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 in v.sym.flags and s.parent == nil: #XXX: Rethink this logic (see tarcmisc.test2) c.graph.globalDestructors.add c.genDestroy(v) else: s.final.add c.genDestroy(v) - if ri.kind == nkEmpty and c.inLoop > 0: - res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = true) - elif ri.kind != nkEmpty: - res.add moveOrCopy(v, ri, c, s, isDecl = true) proc processScope(c: var Con; s: var Scope; ret: PNode): PNode = result = newNodeI(nkStmtList, ret.info) @@ -739,7 +740,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = nkCallKinds + nkLiterals: result = p(n, c, s, consumed) elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and - isLastRead(n, c) and not (n.kind == nkSym and isCursor(n, c)): + isLastRead(n, c) and not (n.kind == nkSym and isCursor(n)): # Sinked params can be consumed only once. We need to reset the memory # to disable the destructor which we have not elided result = destructiveMoveVar(n, c, s) @@ -845,17 +846,16 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = if it.kind == nkVarTuple and hasDestructor(c, ri.typ): let x = lowerTupleUnpacking(c.graph, it, c.idgen, c.owner) result.add p(x, c, s, consumed) - elif it.kind == nkIdentDefs and hasDestructor(c, it[0].typ) and not isCursor(it[0], c): + elif it.kind == nkIdentDefs and hasDestructor(c, it[0].typ): for j in 0.. 0: - ri = genDefaultCall(v.typ, c, v.info) - if ri.kind != nkEmpty: - result.add moveOrCopy(v, ri, c, s, isDecl = false) + pVarTopLevel(v, c, s, result) + if ri.kind != nkEmpty: + result.add moveOrCopy(v, ri, c, s, isDecl = v.kind == nkSym) + elif ri.kind == nkEmpty and c.inLoop > 0: + result.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = v.kind == nkSym) else: # keep the var but transform 'ri': var v = copyNode(n) var itCopy = copyNode(it) @@ -865,8 +865,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = v.add itCopy result.add v of nkAsgn, nkFastAsgn: - if hasDestructor(c, n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda} and - not isCursor(n[0], c): + if hasDestructor(c, n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda}: if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}: cycleCheck(n, c) assert n[1].kind notin {nkAsgn, nkFastAsgn} @@ -885,7 +884,8 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, - nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr: + nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, + nkTypeOfExpr, nkMixinStmt, nkBindStmt: result = n of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock: @@ -968,68 +968,105 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = else: internalError(c.graph.config, n.info, "cannot inject destructors to node kind: " & $n.kind) -proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNode = - case ri.kind - of nkCallKinds: - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - of nkBracketExpr: - if isUnpackedTuple(ri[0]): - # unpacking of tuple: take over the elements - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and - not aliases(dest, ri): - # Rule 3: `=sink`(x, z); wasMoved(z) - var snk = c.genSink(dest, ri, isDecl) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) - else: - result = c.genCopy(dest, ri) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) - of nkBracket: - # array constructor - if ri.len > 0 and isDangerousSeq(ri.typ): - result = c.genCopy(dest, ri) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) - else: - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) - of nkSym: - if dest.kind == nkSym and dest.sym == ri.sym: - # rule (self-assignment-removal): - result = newNodeI(nkEmpty, dest.info) - elif isSinkParam(ri.sym) and isLastRead(ri, c): - # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = c.genSink(dest, ri, isDecl) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) - elif ri.sym.kind != skParam and ri.sym.owner == c.owner and - isLastRead(ri, c) and canBeMoved(c, dest.typ) and not isCursor(ri, c): - # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = c.genSink(dest, ri, isDecl) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) - else: - result = c.genCopy(dest, ri) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) - of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv: - result = c.genSink(dest, p(ri, c, s, sinkArg), isDecl) - of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt: - template process(child, s): untyped = moveOrCopy(dest, child, c, s, isDecl) - # 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) +proc sameLocation*(a, b: PNode): bool = + proc sameConstant(a, b: PNode): bool = + a.kind in nkLiterals and a.intVal == b.intVal + + const nkEndPoint = {nkSym, nkDotExpr, nkCheckedFieldExpr, nkBracketExpr} + if a.kind in nkEndPoint and b.kind in nkEndPoint: + if a.kind == b.kind: + case a.kind + of nkSym: a.sym == b.sym + of nkDotExpr, nkCheckedFieldExpr: sameLocation(a[0], b[0]) and sameLocation(a[1], b[1]) + of nkBracketExpr: sameLocation(a[0], b[0]) and sameConstant(a[1], b[1]) + else: false + else: false else: - if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and - canBeMoved(c, dest.typ): - # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = c.genSink(dest, ri, isDecl) - result = newTree(nkStmtList, snk, c.genWasMoved(ri)) + 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 moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): 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, isDecl) + # We know the result will be a stmt so we use that fact to optimize + handleNestedTempl(ri, process, willProduceStmt = true) else: - result = c.genCopy(dest, ri) - result.add p(ri, c, s, consumed) - c.finishCopy(result, dest, isFromSink = false) + result = newTree(nkFastAsgn, dest, p(ri, c, s, normal)) + else: + case ri.kind + of nkCallKinds: + result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + of nkBracketExpr: + if isUnpackedTuple(ri[0]): + # unpacking of tuple: take over the elements + result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c): + if aliases(dest, ri) == no: + # Rule 3: `=sink`(x, z); wasMoved(z) + var snk = c.genSink(dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) + else: + result = c.genSink(dest, destructiveMoveVar(ri, c, s), isDecl) + else: + result = c.genCopy(dest, ri) + result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) + of nkBracket: + # array constructor + if ri.len > 0 and isDangerousSeq(ri.typ): + result = c.genCopy(dest, ri) + result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) + else: + result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: + result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + of nkSym: + if isSinkParam(ri.sym) and isLastRead(ri, c): + # Rule 3: `=sink`(x, z); wasMoved(z) + let snk = c.genSink(dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) + elif ri.sym.kind != skParam and ri.sym.owner == c.owner and + isLastRead(ri, c) and canBeMoved(c, dest.typ) and not isCursor(ri): + # Rule 3: `=sink`(x, z); wasMoved(z) + let snk = c.genSink(dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) + else: + result = c.genCopy(dest, ri) + result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) + of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv: + result = c.genSink(dest, p(ri, c, s, sinkArg), isDecl) + of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt: + template process(child, s): untyped = moveOrCopy(dest, child, c, s, isDecl) + # 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) and + canBeMoved(c, dest.typ): + # Rule 3: `=sink`(x, z); wasMoved(z) + let snk = c.genSink(dest, ri, isDecl) + result = newTree(nkStmtList, snk, c.genWasMoved(ri)) + else: + result = c.genCopy(dest, ri) + result.add p(ri, c, s, consumed) + c.finishCopy(result, dest, isFromSink = false) proc computeUninit(c: var Con) = if not c.uninitComputed: @@ -1067,7 +1104,28 @@ proc injectDestructorCalls*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n: echo n if optCursorInference in g.config.options: - computeCursors(owner, n, g.config) + computeCursors(owner, n, g) + + block: + var cache = initTable[(PNode, PNode), AliasKind]() + var lastReads, potLastReads: IntSet + var pc = 0 + collectLastReads(c.g, cache, lastReads, potLastReads, pc, c.g.len) + lastReads.incl potLastReads + var lastReadTable: Table[PNode, seq[int]] + for position, node in c.g: + if node.kind == use: + lastReadTable.mgetOrPut(node.n, @[]).add position + for node, positions in lastReadTable: + var allPositionsLastRead = true + for p in positions: + if p notin lastReads: allPositionsLastRead = false; break + if allPositionsLastRead: + node.flags.incl nfLastRead + + var alreadySeen: HashSet[PNode] + pc = 0 + collectFirstWrites(c.g, alreadySeen, pc, c.g.len) var scope: Scope let body = p(n, c, scope, normal) diff --git a/compiler/installer.ini b/compiler/installer.ini index 2f11d0df91..3f1630a921 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -76,7 +76,6 @@ Files: "lib" [Other] Files: "examples" Files: "dist/nimble" -Files: "dist/fusion" Files: "tests" @@ -110,6 +109,7 @@ 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" diff --git a/compiler/int128.nim b/compiler/int128.nim index e266b9cd05..8d3cd71131 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -1,13 +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 +from std/math import trunc 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 @@ -17,12 +17,12 @@ 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 @@ -57,10 +57,10 @@ template isNegative(arg: Int128): bool = template isNegative(arg: int32): bool = arg < 0 -proc bitconcat(a,b: uint32): uint64 = +proc bitconcat(a, b: uint32): uint64 = (uint64(a) shl 32) or uint64(b) -proc bitsplit(a: uint64): (uint32,uint32) = +proc bitsplit(a: uint64): (uint32, uint32) = (cast[uint32](a shr 32), cast[uint32](a)) proc toInt64*(arg: Int128): int64 = @@ -176,7 +176,6 @@ 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 @@ -186,7 +185,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]) @@ -196,13 +195,13 @@ 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 @@ -221,19 +220,19 @@ proc bitnot*(a: Int128): Int128 = 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] @@ -288,7 +287,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) @@ -305,7 +304,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) = @@ -342,7 +341,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) @@ -354,7 +353,7 @@ proc high64(a: Int128): uint64 = proc low64(a: Int128): uint64 = bitconcat(a.udata[1], a.udata[0]) -proc `*`*(lhs,rhs: Int128): Int128 = +proc `*`*(lhs, rhs: Int128): Int128 = let a = cast[uint64](lhs.udata[0]) b = cast[uint64](lhs.udata[1]) @@ -379,7 +378,7 @@ proc `*`*(lhs,rhs: Int128): Int128 = proc `*=`*(a: var Int128, b: Int128) = a = a * b -import bitops +import std/bitops proc fastLog2*(a: Int128): int = if a.udata[3] != 0: @@ -389,7 +388,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) @@ -441,12 +440,12 @@ proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] = else: result.remainder = dividend -proc `div`*(a,b: Int128): Int128 = - let (a,b) = divMod(a,b) +proc `div`*(a, b: Int128): Int128 = + let (a, b) = divMod(a, b) return a -proc `mod`*(a,b: Int128): Int128 = - let (a,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) = @@ -477,7 +476,7 @@ proc `$`*(a: Int128): string = 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 @@ -497,13 +496,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 @@ -539,7 +538,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 diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 675a24c923..3fc7708bf7 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -14,27 +14,28 @@ 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, strutils, trees, magicsys, options, - nversion, msgs, idents, types, tables, - ropes, math, passes, ccgutils, wordrecg, renderer, - intsets, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, - transf, injectdestructors, sourcemap, json, sets + ast, trees, magicsys, options, + nversion, msgs, idents, types, + ropes, passes, ccgutils, wordrecg, renderer, + cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, + transf, injectdestructors, sourcemap +import std/[json, sets, math, tables, intsets, strutils] from modulegraphs import ModuleGraph, PPassContext @@ -210,7 +211,7 @@ proc mapType(typ: PType): TJSTypeKind = else: result = etyNone of tyProc: result = etyProc of tyCString: result = etyString - of tyOptDeprecated: doAssert false + of tyConcept: doAssert false proc mapType(p: PProc; typ: PType): TJSTypeKind = result = mapType(typ) @@ -670,7 +671,10 @@ 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, "/") + of mDivU: + binaryUintExpr(p, n, r, "/") + if n[1].typ.skipTypes(abstractRange).size == 8: + r.res = "Math.trunc($1)" % [r.res] of mDivI: arithAux(p, n, r, op) of mModI: @@ -887,7 +891,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = var v = copyNode(e[0]) inc(totalRange, int(e[1].intVal - v.intVal)) if totalRange > 65535: - localError(p.config, n.info, + localError(p.config, n.info, "Your case statement contains too many branches, consider using if/else instead!") while v.intVal <= e[1].intVal: gen(p, v, cond) @@ -1076,11 +1080,11 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = 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, y.typ)]) + 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, y.typ)]) + [a.res, b.res, genTypeInfo(p, x.typ)]) of etyBaseIndex: if a.typ != etyBaseIndex or b.typ != etyBaseIndex: if y.kind == nkCall: @@ -1350,7 +1354,15 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = of nkStmtListExpr: if n.len == 1: gen(p, n[0], r) else: internalError(p.config, n[0].info, "genAddr for complex nkStmtListExpr") - else: internalError(p.config, n[0].info, "genAddr: " & $n[0].kind) + 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) + else: + internalError(p.config, n[0].info, "genAddr: " & $n[0].kind) proc attachProc(p: PProc; content: Rope; s: PSym) = p.g.code.add(content) @@ -1423,10 +1435,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 != mNone or + if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate} or {sfImportc, sfInfixCall} * s.flags != {}: discard - elif s.kind == skMethod and s.getBody.kind == nkEmpty: + elif s.kind == skMethod and getBody(p.module.graph, s).kind == nkEmpty: # we cannot produce code for the dispatcher yet: discard elif sfForward in s.flags: @@ -1677,7 +1689,10 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = var t = skipTypes(typ, abstractInst) case t.kind of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: - result = putToSeq("0", indirect) + if $t.sym.loc.r == "bigint": + result = putToSeq("0n", indirect) + else: + result = putToSeq("0", indirect) of tyFloat..tyFloat128: result = putToSeq("0.0", indirect) of tyRange, tyGenericInst, tyAlias, tySink, tyOwned: @@ -1979,6 +1994,23 @@ 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 @@ -1999,7 +2031,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = gen(p, n[2], rhs) if skipTypes(n[1].typ, abstractVarRange).kind == tyCString: - r.res = "$1 += $2;" % [lhs.rdLoc, rhs.rdLoc] + 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] else: let (a, tmp) = maybeMakeTemp(p, n[1], lhs) r.res = "$1.push.apply($3, $2);" % [a, rhs.rdLoc, tmp] @@ -2040,8 +2074,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mNew, mNewFinalize: genNew(p, n) of mChr: gen(p, n[1], r) of mArrToSeq: - if needsNoCopy(p, n[1]): - gen(p, n[1], r) + # only array literals doesn't need copy + if n[1].kind == nkBracket: + genJSArrayConstr(p, n[1], r) else: var x: TCompRes gen(p, n[1], x) @@ -2050,9 +2085,23 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mDestroy: discard "ignore calls to the default destructor" of mOrd: genOrd(p, n, r) of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray: - unaryExpr(p, n, r, "", "($1).length") + 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 of mHigh: - unaryExpr(p, n, r, "", "(($1).length-1)") + 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 of mInc: if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}: binaryUintExpr(p, n, r, "+", true) @@ -2131,7 +2180,11 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = if it.kind == nkRange: gen(p, it[0], a) gen(p, it[1], b) - r.res.addf("[$1, $2]", [a.res, b.res]) + + 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]) else: gen(p, it, a) r.res.add(a.res) @@ -2144,21 +2197,26 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = r.res = tmp proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) = - 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)] + ## 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) r.res.add(a.res) - r.res.add("]") + r.res.add("])") + else: + genJSArrayConstr(p, n, r) proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes @@ -2482,7 +2540,10 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = let f = n.floatVal case classify(f) of fcNan: - r.res = rope"NaN" + if signbit(f): + r.res = rope"-NaN" + else: + r.res = rope"NaN" of fcNegZero: r.res = rope"-0.0" of fcZero: @@ -2528,7 +2589,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = let s = n[namePos].sym discard mangleName(p.module, s) r.res = s.loc.r - if lfNoDecl in s.loc.flags or s.magic != mNone: discard + if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate}: discard elif not p.g.generatedSyms.containsOrIncl(s.id): p.locals.add(genProc(p, s)) of nkType: r.res = genTypeInfo(p, n.typ) @@ -2565,7 +2626,8 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = of nkRaiseStmt: genRaiseStmt(p, n) of nkTypeSection, nkCommentStmt, nkIncludeStmt, nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, - nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: discard + nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt, + nkMixinStmt, nkBindStmt: discard of nkIteratorDef: if n[0].sym.typ.callConv == TCallingConvention.ccClosure: globalError(p.config, n.info, "Closure iterators are not supported by JS backend!") diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 95e50d00f4..6f43649a15 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -130,14 +130,14 @@ proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator) var n = newNodeI(nkRange, iter.info) n.add newIntNode(nkIntLit, -1) n.add newIntNode(nkIntLit, 0) - result = newType(tyRange, nextId(idgen), iter) + result = newType(tyRange, nextTypeId(idgen), iter) result.n = n var intType = nilOrSysInt(g) - if intType.isNil: intType = newType(tyInt, nextId(idgen), iter) + if intType.isNil: intType = newType(tyInt, nextTypeId(idgen), iter) rawAddSon(result, intType) proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym = - result = newSym(skField, getIdent(g.cache, ":state"), nextId(idgen), iter, iter.info) + result = newSym(skField, getIdent(g.cache, ":state"), nextSymId(idgen), iter, iter.info) result.typ = createClosureIterStateType(g, iter, idgen) proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType = @@ -151,7 +151,7 @@ proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym result = iter.ast[resultPos].sym else: # XXX a bit hacky: - result = newSym(skResult, getIdent(g.cache, ":result"), nextId(idgen), iter, iter.info, {}) + result = newSym(skResult, getIdent(g.cache, ":result"), nextSymId(idgen), iter, iter.info, {}) result.typ = iter.typ[0] incl(result.flags, sfUsed) iter.ast.add newSymNode(result) @@ -238,10 +238,11 @@ proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} = result = conf.backend == backendJs and not isCompileTime proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; idgen: IdGenerator; owner: PSym) = - createTypeBoundOps(g, nil, refType.lastSon, info, idgen) - createTypeBoundOps(g, nil, refType, info, idgen) - if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions: - owner.flags.incl sfInjectDestructors + if owner.kind != skMacro: + createTypeBoundOps(g, nil, refType.lastSon, info, idgen) + createTypeBoundOps(g, nil, refType, info, idgen) + if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions: + owner.flags.incl sfInjectDestructors proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode = # transforms (iter) to (let env = newClosure[iter](); (iter, env)) @@ -258,7 +259,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN addUniqueField(it.typ.skipTypes({tyOwned})[0], hp, g.cache, idgen) env = indirectAccess(newSymNode(it), hp, hp.info) else: - let e = newSym(skLet, iter.name, nextId(idgen), owner, n.info) + let e = newSym(skLet, iter.name, nextSymId(idgen), owner, n.info) e.typ = hp.typ e.flags = hp.flags env = newSymNode(e) @@ -329,7 +330,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym; info: TLineInfo): PType = result = c.ownerToType.getOrDefault(owner.id) if result.isNil: - result = newType(tyRef, nextId(c.idgen), owner) + result = newType(tyRef, nextTypeId(c.idgen), owner) let obj = createEnvObj(c.graph, c.idgen, owner, info) rawAddSon(result, obj) c.ownerToType[owner.id] = result @@ -337,7 +338,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym; proc asOwnedRef(c: var DetectionPass; t: PType): PType = if optOwnedRefs in c.graph.config.globalOptions: assert t.kind == tyRef - result = newType(tyOwned, nextId(c.idgen), t.owner) + result = newType(tyOwned, nextTypeId(c.idgen), t.owner) result.flags.incl tfHasOwned result.rawAddSon t else: @@ -346,7 +347,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, nextId(c.idgen), owner) + result = newType(tyPtr, nextTypeId(c.idgen), owner) rawAddSon(result, r.skipTypes({tyOwned, tyRef, tyPtr})) proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) = @@ -374,7 +375,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, nextId(c.idgen), obj.owner, obj.owner.info) + let result = newSym(skField, upIdent, nextSymId(c.idgen), obj.owner, obj.owner.info) result.typ = fieldType when false: if c.graph.config.selectedGC == gcDestructors: @@ -412,7 +413,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), nextId(c.idgen), fn, fn.info) + cp = newSym(skParam, getIdent(c.graph.cache, paramName), nextSymId(c.idgen), fn, fn.info) incl(cp.flags, sfFromGeneric) cp.typ = t addHiddenParam(fn, cp) @@ -496,7 +497,8 @@ 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: + nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt, + nkTypeOfExpr, nkMixinStmt, nkBindStmt: discard of nkLambdaKinds, nkIteratorDef: if n.typ != nil: @@ -538,7 +540,7 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode = result = n proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo; idgen: IdGenerator): PNode = - var v = newSym(skVar, getIdent(cache, envName), nextId(idgen), owner, info) + var v = newSym(skVar, getIdent(cache, envName), nextSymId(idgen), owner, info) v.flags = {sfShadowed, sfGeneratedOp} v.typ = typ result = newSymNode(v) @@ -562,7 +564,7 @@ proc setupEnvVar(owner: PSym; d: var DetectionPass; result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info, d.idgen) c.envVars[owner.id] = result if optOwnedRefs in d.graph.config.globalOptions: - var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), nextId d.idgen, owner, info) + var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), nextSymId d.idgen, owner, info) v.flags = {sfShadowed, sfGeneratedOp} v.typ = envVarType c.unownedEnvVars[owner.id] = newSymNode(v) @@ -613,7 +615,8 @@ proc rawClosureCreation(owner: PSym; let fieldAccess = indirectAccess(env, local, env.info) # add ``env.param = param`` result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info)) - createTypeBoundOps(d.graph, nil, fieldAccess.typ, env.info, d.idgen) + if owner.kind != skMacro: + createTypeBoundOps(d.graph, nil, fieldAccess.typ, env.info, d.idgen) if tfHasAsgn in fieldAccess.typ.flags or optSeqDestructors in d.graph.config.globalOptions: owner.flags.incl sfInjectDestructors @@ -645,7 +648,7 @@ proc closureCreationForIter(iter: PNode; d: var DetectionPass; c: var LiftingPass): PNode = result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ) let owner = iter.sym.skipGenericOwner - var v = newSym(skVar, getIdent(d.graph.cache, envName), nextId(d.idgen), owner, iter.info) + var v = newSym(skVar, getIdent(d.graph.cache, envName), nextSymId(d.idgen), owner, iter.info) incl(v.flags, sfShadowed) v.typ = asOwnedRef(d, getHiddenParam(d.graph, iter.sym).typ) var vnode: PNode @@ -750,7 +753,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass; result = accessViaEnvVar(n, owner, d, c) of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom, nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef, nkConverterDef, - nkMacroDef, nkFuncDef: + nkMacroDef, nkFuncDef, nkMixinStmt, nkBindStmt: discard of nkClosure: if n[1].kind == nkNilLit: @@ -935,7 +938,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym): let iter = op.sym let hp = getHiddenParam(g, iter) - env = newSym(skLet, iter.name, nextId(idgen), owner, body.info) + env = newSym(skLet, iter.name, nextSymId(idgen), owner, body.info) env.typ = hp.typ env.flags = hp.flags diff --git a/compiler/layouter.nim b/compiler/layouter.nim index c603c16ffc..ec9db6aad5 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -514,7 +514,8 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) = (not em.wasExportMarker or tok.tokType == tkCurlyDotLe): wrSpace em wr(em, $tok.tokType, ltSomeParLe) - rememberSplit(splitParLe) + if tok.tokType != tkCurlyDotLe: + rememberSplit(splitParLe) of closedPars: wr(em, $tok.tokType, ltSomeParRi) of tkColonColon: diff --git a/compiler/lexer.nim b/compiler/lexer.nim index b55dd35859..729ba34352 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -955,8 +955,10 @@ 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 - if L.buf[pos] in {CR, LF}: + while L.buf[pos] == ' ': + inc pos + inc toStrip + while L.buf[pos] in {CR, LF}: # skip blank lines pos = handleCRLF(L, pos) toStrip = 0 while L.buf[pos] == ' ': @@ -1028,11 +1030,17 @@ proc scanComment(L: var Lexer, tok: var Token) = inc(pos, 2) var toStrip = 0 - while L.buf[pos] == ' ': - inc pos - inc toStrip + var stripInit = false 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 @@ -1048,11 +1056,12 @@ proc scanComment(L: var Lexer, tok: var Token) = if L.buf[pos] == '#' and L.buf[pos+1] == '#': tok.literal.add "\n" inc(pos, 2) - var c = toStrip - while L.buf[pos] == ' ' and c > 0: - inc pos - dec c - inc tok.iNumber + if stripInit: + 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 diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 512fb6190f..980e77e4be 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -29,6 +29,10 @@ type 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 @@ -42,8 +46,9 @@ proc at(a, i: PNode, elemType: PType): PNode = result[1] = i result.typ = elemType -proc destructorOverriden(t: PType): bool = - t.attachedOps[attachedDestructor] != nil and sfOverriden in t.attachedOps[attachedDestructor].flags +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 s[i-1] in {'A'..'Z'}: + if i+1 >= s.len: + discard "trailing underscores should be stripped off" + elif i > 0 and s[i-1] in {'A'..'Z'}: # don't skip '_' as it's essential for e.g. 'GC_disable' result.add('_') inc i diff --git a/compiler/llstream.nim b/compiler/llstream.nim index 6df927c60b..865a98ee0d 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -20,6 +20,7 @@ when hasRstdin: import rdstdin type TLLRepl* = proc (s: PLLStream, buf: pointer, bufLen: int): int + OnPrompt* = proc() {.closure.} TLLStreamKind* = enum # enum of different stream implementations llsNone, # null stream: reading and writing has no effect llsString, # stream encapsulates a string @@ -32,6 +33,7 @@ type rd*, wr*: int # for string streams lineOffset*: int # for fake stdin line numbers repl*: TLLRepl # gives stdin control to clients + onPrompt*: OnPrompt PLLStream* = ref TLLStream @@ -55,12 +57,13 @@ proc llStreamOpen*(): PLLStream = result.kind = llsNone proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int -proc llStreamOpenStdIn*(r: TLLRepl = llReadFromStdin): PLLStream = +proc llStreamOpenStdIn*(r: TLLRepl = llReadFromStdin, onPrompt: OnPrompt = nil): PLLStream = new(result) result.kind = llsStdIn result.s = "" result.lineOffset = -1 result.repl = r + result.onPrompt = onPrompt proc llStreamClose*(s: PLLStream) = case s.kind @@ -72,10 +75,10 @@ proc llStreamClose*(s: PLLStream) = when not declared(readLineFromStdin): # fallback implementation: proc readLineFromStdin(prompt: string, line: var string): bool = - stderr.write(prompt) + stdout.write(prompt) result = readLine(stdin, line) if not result: - stderr.write("\n") + stdout.write("\n") quit(0) proc endsWith*(x: string, s: set[char]): bool = @@ -133,6 +136,7 @@ proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int = of llsFile: result = readBuffer(s.f, buf, bufLen) of llsStdIn: + if s.onPrompt!=nil: s.onPrompt() result = s.repl(s, buf, bufLen) proc llStreamReadLine*(s: PLLStream, line: var string): bool = @@ -143,11 +147,11 @@ proc llStreamReadLine*(s: PLLStream, line: var string): bool = of llsString: while s.rd < s.s.len: case s.s[s.rd] - of '\x0D': + of '\r': inc(s.rd) - if s.s[s.rd] == '\x0A': inc(s.rd) + if s.s[s.rd] == '\n': inc(s.rd) break - of '\x0A': + of '\n': inc(s.rd) break else: diff --git a/compiler/lookups.nim b/compiler/lookups.nim index fba032c1ec..15a22c7787 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -11,7 +11,8 @@ import intsets, ast, astalgo, idents, semdata, types, msgs, options, - renderer, nimfix/prettybase, lineinfos, strutils + renderer, nimfix/prettybase, lineinfos, strutils, + modulegraphs proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) @@ -107,8 +108,9 @@ proc localSearchInScope*(c: PContext, s: PIdent): PSym = scope = scope.parent result = strTableGet(scope.symbols, s) -proc initIdentIter(ti: var TIdentIter; marked: var IntSet; im: ImportedModule; name: PIdent): PSym = - result = initIdentIter(ti, im.m.tab, name) +proc initIdentIter(ti: var ModuleIter; marked: var IntSet; im: ImportedModule; name: PIdent; + g: ModuleGraph): PSym = + result = initModuleIter(ti, g, im.m, name) while result != nil: let b = case im.mode @@ -117,11 +119,12 @@ proc initIdentIter(ti: var TIdentIter; marked: var IntSet; im: ImportedModule; n of importExcept: name.id notin im.exceptSet if b and not containsOrIncl(marked, result.id): return result - result = nextIdentIter(ti, im.m.tab) + result = nextModuleIter(ti, g) -proc nextIdentIter(ti: var TIdentIter; marked: var IntSet; im: ImportedModule): PSym = +proc nextIdentIter(ti: var ModuleIter; marked: var IntSet; im: ImportedModule; + g: ModuleGraph): PSym = while true: - result = nextIdentIter(ti, im.m.tab) + result = nextModuleIter(ti, g) if result == nil: return nil case im.mode of importAll: @@ -134,17 +137,17 @@ proc nextIdentIter(ti: var TIdentIter; marked: var IntSet; im: ImportedModule): if result.name.id notin im.exceptSet and not containsOrIncl(marked, result.id): return result -iterator symbols(im: ImportedModule; marked: var IntSet; name: PIdent): PSym = - var ti: TIdentIter - var candidate = initIdentIter(ti, marked, im, name) +iterator symbols(im: ImportedModule; marked: var IntSet; name: PIdent; g: ModuleGraph): PSym = + var ti: ModuleIter + var candidate = initIdentIter(ti, marked, im, name, g) while candidate != nil: yield candidate - candidate = nextIdentIter(ti, marked, im) + candidate = nextIdentIter(ti, marked, im, g) iterator importedItems*(c: PContext; name: PIdent): PSym = var marked = initIntSet() for im in c.imports.mitems: - for s in symbols(im, marked, name): + for s in symbols(im, marked, name, c.graph): yield s proc allPureEnumFields(c: PContext; name: PIdent): seq[PSym] = @@ -169,15 +172,15 @@ iterator allSyms*(c: PContext): (PSym, int, bool) = dec scopeN isLocal = false for im in c.imports.mitems: - for s in im.m.tab.data: - if s != nil: - yield (s, scopeN, isLocal) + for s in modulegraphs.allSyms(c.graph, im.m): + assert s != nil + yield (s, scopeN, isLocal) proc someSymFromImportTable*(c: PContext; name: PIdent; ambiguous: var bool): PSym = var marked = initIntSet() result = nil for im in c.imports.mitems: - for s in symbols(im, marked, name): + for s in symbols(im, marked, name, c.graph): if result == nil: result = s else: @@ -190,14 +193,17 @@ proc searchInScopes*(c: PContext, s: PIdent; ambiguous: var bool): PSym = if result != nil: return result result = someSymFromImportTable(c, s, ambiguous) -proc debugScopes*(c: PContext; limit=0) {.deprecated.} = +proc debugScopes*(c: PContext; limit=0, max = int.high) {.deprecated.} = var i = 0 + var count = 0 for scope in allScopes(c.currentScope): echo "scope ", i for h in 0..high(scope.symbols.data): if scope.symbols.data[h] != nil: - echo scope.symbols.data[h].name.s - if i == limit: break + if count >= max: return + echo count, ": ", scope.symbols.data[h].name.s + count.inc + if i == limit: return inc i proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] = @@ -214,7 +220,7 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy if result.len == 0: var marked = initIntSet() for im in c.imports.mitems: - for s in symbols(im, marked, s): + for s in symbols(im, marked, s, c.graph): if s.kind in filter: result.add s @@ -227,7 +233,7 @@ proc errorSym*(c: PContext, n: PNode): PSym = considerQuotedIdent(c, m) else: getIdent(c.cache, "err:" & renderTree(m)) - result = newSym(skError, ident, nextId(c.idgen), getCurrOwner(c), n.info, {}) + result = newSym(skError, ident, nextSymId(c.idgen), getCurrOwner(c), n.info, {}) result.typ = errorType(c) incl(result.flags, sfDiscardable) # pretend it's from the top level scope to prevent cascading errors: @@ -240,6 +246,7 @@ type oimSymChoiceLocalLookup TOverloadIter* = object it*: TIdentIter + mit*: ModuleIter m*: PSym mode*: TOverloadIterMode symChoiceIndex*: int @@ -280,6 +287,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) = proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string; conflictsWith: TLineInfo) = + ## Emit a redefinition error if in non-interactive mode if c.config.cmd != cmdInteractive: localError(c.config, info, "redefinition of '$1'; previous declaration here: $2" % @@ -306,7 +314,7 @@ proc addDeclAt*(c: PContext; scope: PScope, sym: PSym) = proc addInterfaceDeclAux(c: PContext, sym: PSym) = if sfExported in sym.flags: # add to interface: - if c.module != nil: strTableAdd(c.module.tab, sym) + if c.module != nil: exportSym(c, sym) else: internalError(c.config, sym.info, "addInterfaceDeclAux") proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) = @@ -350,33 +358,92 @@ proc mergeShadowScope*(c: PContext) = else: c.addInterfaceDecl(sym) -when defined(nimfix): - # when we cannot find the identifier, retry with a changed identifier: - proc altSpelling(x: PIdent): PIdent = +when false: + # `nimfix` used to call `altSpelling` and prettybase.replaceDeprecated(n.info, ident, alt) + proc altSpelling(c: PContext, x: PIdent): PIdent = case x.s[0] - of 'A'..'Z': result = getIdent(toLowerAscii(x.s[0]) & x.s.substr(1)) - of 'a'..'z': result = getIdent(toLowerAscii(x.s[0]) & x.s.substr(1)) + of 'A'..'Z': result = getIdent(c.cache, toLowerAscii(x.s[0]) & x.s.substr(1)) + of 'a'..'z': result = getIdent(c.cache, toLowerAscii(x.s[0]) & x.s.substr(1)) else: result = x - template fixSpelling(n: PNode; ident: PIdent; op: untyped) = - let alt = ident.altSpelling - result = op(c, alt).skipAlias(n) - if result != nil: - prettybase.replaceDeprecated(n.info, ident, alt) - return result -else: - template fixSpelling(n: PNode; ident: PIdent; op: untyped) = discard +import std/[editdistance, heapqueue] -proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) = +type SpellCandidate = object + dist: int + depth: int + msg: string + sym: PSym + +template toOrderTup(a: SpellCandidate): auto = + # `dist` is first, to favor nearby matches + # `depth` is next, to favor nearby enclosing scopes among ties + # `sym.name.s` is last, to make the list ordered and deterministic among ties + (a.dist, a.depth, a.msg) + +proc `<`(a, b: SpellCandidate): bool = + a.toOrderTup < b.toOrderTup + +proc mustFixSpelling(c: PContext): bool {.inline.} = + result = c.config.spellSuggestMax != 0 and c.compilesContextId == 0 + # don't slowdown inside compiles() + +proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) = + ## when we cannot find the identifier, suggest nearby spellings + var list = initHeapQueue[SpellCandidate]() + let name0 = ident.s.nimIdentNormalize + + for (sym, depth, isLocal) in allSyms(c): + let depth = -depth - 1 + let dist = editDistance(name0, sym.name.s.nimIdentNormalize) + var msg: string + msg.add "\n ($1, $2): '$3'" % [$dist, $depth, sym.name.s] + addDeclaredLoc(msg, c.config, sym) # `msg` needed for deterministic ordering. + list.push SpellCandidate(dist: dist, depth: depth, msg: msg, sym: sym) + + if list.len == 0: return + let e0 = list[0] + var count = 0 + while true: + # pending https://github.com/timotheecour/Nim/issues/373 use more efficient `itemsSorted`. + if list.len == 0: break + let e = list.pop() + if c.config.spellSuggestMax == spellSuggestSecretSauce: + const + smallThres = 2 + maxCountForSmall = 4 + # avoids ton of operator matches when mis-matching short symbols such as `i` + # other heuristics could be devised, such as only suggesting operators if `name0` + # is an operator (likewise with non-operators). + if e.dist > e0.dist or (name0.len <= smallThres and count >= maxCountForSmall): break + elif count >= c.config.spellSuggestMax: break + if count == 0: + result.add "\ncandidates (edit distance, scope distance); see '--spellSuggest': " + result.add e.msg + count.inc + +proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PSym = var err = "ambiguous identifier: '" & s.name.s & "'" var i = 0 + var ignoredModules = 0 for candidate in importedItems(c, s.name): if i == 0: err.add " -- use one of the following:\n" else: err.add "\n" err.add " " & candidate.owner.name.s & "." & candidate.name.s err.add ": " & typeToString(candidate.typ) + if candidate.kind == skModule: + inc ignoredModules + else: + result = candidate inc i - localError(c.config, info, errGenerated, err) + if ignoredModules != i-1: + localError(c.config, info, errGenerated, err) + result = nil + else: + amb = false + +proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) = + var amb: bool + discard errorUseQualifier(c, info, s, amb) proc errorUseQualifier(c: PContext; info: TLineInfo; candidates: seq[PSym]) = var err = "ambiguous identifier: '" & candidates[0].name.s & "'" @@ -389,8 +456,8 @@ proc errorUseQualifier(c: PContext; info: TLineInfo; candidates: seq[PSym]) = inc i localError(c.config, info, errGenerated, err) -proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string) = - var err = "undeclared identifier: '" & name & "'" +proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extra = "") = + var err = "undeclared identifier: '" & name & "'" & extra if c.recursiveDep.len > 0: err.add "\nThis might be caused by a recursive module dependency:\n" err.add c.recursiveDep @@ -398,31 +465,31 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string) = c.recursiveDep = "" localError(c.config, info, errGenerated, err) +proc errorUndeclaredIdentifierHint*(c: PContext; n: PNode, ident: PIdent): PSym = + var extra = "" + if c.mustFixSpelling: fixSpelling(c, n, ident, extra) + errorUndeclaredIdentifier(c, n.info, ident.s, extra) + result = errorSym(c, n) + proc lookUp*(c: PContext, n: PNode): PSym = # Looks up a symbol. Generates an error in case of nil. var amb = false case n.kind of nkIdent: result = searchInScopes(c, n.ident, amb).skipAlias(n, c.config) - if result == nil: - fixSpelling(n, n.ident, searchInScopes) - errorUndeclaredIdentifier(c, n.info, n.ident.s) - result = errorSym(c, n) + if result == nil: result = errorUndeclaredIdentifierHint(c, n, n.ident) of nkSym: result = n.sym of nkAccQuoted: var ident = considerQuotedIdent(c, n) result = searchInScopes(c, ident, amb).skipAlias(n, c.config) - if result == nil: - fixSpelling(n, ident, searchInScopes) - errorUndeclaredIdentifier(c, n.info, ident.s) - result = errorSym(c, n) + if result == nil: result = errorUndeclaredIdentifierHint(c, n, ident) else: internalError(c.config, n.info, "lookUp") return if amb: #contains(c.ambiguousSymbols, result.id): - errorUseQualifier(c, n.info, result) + result = errorUseQualifier(c, n.info, result, amb) when false: if result.kind == skStub: loadStub(result) @@ -454,11 +521,9 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = errorUseQualifier(c, n.info, candidates) if result == nil and checkUndeclared in flags: - fixSpelling(n, ident, searchInScopes) - errorUndeclaredIdentifier(c, n.info, ident.s) - result = errorSym(c, n) + result = errorUndeclaredIdentifierHint(c, n, ident) elif checkAmbiguity in flags and result != nil and amb: - errorUseQualifier(c, n.info, result) + result = errorUseQualifier(c, n.info, result, amb) c.isAmbiguous = amb of nkSym: result = n.sym @@ -475,11 +540,9 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = if m == c.module: result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config) else: - result = strTableGet(m.tab, ident).skipAlias(n, c.config) + result = someSym(c.graph, m, ident).skipAlias(n, c.config) if result == nil and checkUndeclared in flags: - fixSpelling(n[1], ident, searchInScopes) - errorUndeclaredIdentifier(c, n[1].info, ident.s) - result = errorSym(c, n[1]) + result = errorUndeclaredIdentifierHint(c, n[1], ident) elif n[1].kind == nkSym: result = n[1].sym elif checkUndeclared in flags and @@ -509,7 +572,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = scope = scope.parent if scope == nil: for i in 0..c.imports.high: - result = initIdentIter(o.it, o.marked, c.imports[i], ident).skipAlias(n, c.config) + result = initIdentIter(o.mit, o.marked, c.imports[i], ident, c.graph).skipAlias(n, c.config) if result != nil: o.currentScope = nil o.importIdx = i @@ -535,7 +598,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = ident).skipAlias(n, c.config) o.mode = oimSelfModule else: - result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n, c.config) + result = initModuleIter(o.mit, c.graph, o.m, ident).skipAlias(n, c.config) else: noidentError(c.config, n[1], n) result = errorSym(c, n[1]) @@ -568,7 +631,7 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym var idx = o.importIdx+1 o.importIdx = c.imports.len # assume the other imported modules lack this symbol too while idx < c.imports.len: - result = initIdentIter(o.it, o.marked, c.imports[idx], o.it.name).skipAlias(n, c.config) + result = initIdentIter(o.mit, o.marked, c.imports[idx], o.it.name, c.graph).skipAlias(n, c.config) if result != nil: # oh, we were wrong, some other module had the symbol, so remember that: o.importIdx = idx @@ -578,7 +641,7 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym proc symChoiceExtension(o: var TOverloadIter; c: PContext; n: PNode): PSym = assert o.currentScope == nil while o.importIdx < c.imports.len: - result = initIdentIter(o.it, o.marked, c.imports[o.importIdx], o.it.name).skipAlias(n, c.config) + result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config) #while result != nil and result.id in o.marked: # result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx]) if result != nil: @@ -602,12 +665,12 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = else: o.importIdx = 0 if c.imports.len > 0: - result = initIdentIter(o.it, o.marked, c.imports[o.importIdx], o.it.name).skipAlias(n, c.config) + result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config) if result == nil: result = nextOverloadIterImports(o, c, n) break elif o.importIdx < c.imports.len: - result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx]).skipAlias(n, c.config) + result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config) if result == nil: result = nextOverloadIterImports(o, c, n) else: @@ -615,7 +678,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = of oimSelfModule: result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n, c.config) of oimOtherModule: - result = nextIdentIter(o.it, o.m.tab).skipAlias(n, c.config) + result = nextModuleIter(o.mit, c.graph).skipAlias(n, c.config) of oimSymChoice: if o.symChoiceIndex < n.len: result = n[o.symChoiceIndex].sym @@ -654,7 +717,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = incl o.marked, result.id elif o.importIdx < c.imports.len: - result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx]).skipAlias(n, c.config) + result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config) #assert result.id notin o.marked #while result != nil and result.id in o.marked: # result = nextIdentIter(o.it, c.imports[o.importIdx]).skipAlias(n, c.config) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index e9e704075a..37405d8d96 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -71,7 +71,7 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: P let value = n.lastSon result = newNodeI(nkStmtList, n.info) - var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextId(idgen), + var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen), owner, value.info, g.config.options) temp.typ = skipTypes(value.typ, abstractInst) incl(temp.flags, sfFromGeneric) @@ -91,7 +91,7 @@ proc evalOnce*(g: ModuleGraph; value: PNode; idgen: IdGenerator; owner: PSym): P ## freely, multiple times. This is frequently required and such a builtin would also be ## handy to have in macros.nim. The value that can be reused is 'result.lastSon'! result = newNodeIT(nkStmtListExpr, value.info, value.typ) - var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextId(idgen), + var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen), owner, value.info, g.config.options) temp.typ = skipTypes(value.typ, abstractInst) incl(temp.flags, sfFromGeneric) @@ -117,7 +117,7 @@ proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; o let value = n.lastSon result = newNodeI(nkStmtList, n.info) - var temp = newSym(skTemp, getIdent(g.cache, "_"), nextId(idgen), owner, value.info, owner.options) + var temp = newSym(skTemp, getIdent(g.cache, "_"), nextSymId(idgen), owner, value.info, owner.options) var v = newNodeI(nkLetSection, value.info) let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info) @@ -135,7 +135,7 @@ proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; o proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode = result = newNodeI(nkStmtList, n.info) # note: cannot use 'skTemp' here cause we really need the copy for the VM :-( - var temp = newSym(skVar, getIdent(g.cache, genPrefix), nextId(idgen), owner, n.info, owner.options) + var temp = newSym(skVar, getIdent(g.cache, genPrefix), nextSymId(idgen), owner, n.info, owner.options) temp.typ = n[1].typ incl(temp.flags, sfFromGeneric) incl(temp.flags, sfGenSym) @@ -154,7 +154,7 @@ proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNod result.add newFastAsgnStmt(n[2], tempAsNode) proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo; final=true): PType = - result = newType(tyObject, nextId(idgen), owner) + result = newType(tyObject, nextTypeId(idgen), owner) if final: rawAddSon(result, nil) incl result.flags, tfFinal @@ -162,7 +162,7 @@ proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo rawAddSon(result, getCompilerProc(g, "RootObj").typ) result.n = newNodeI(nkRecList, info) let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s), - nextId(idgen), + nextSymId(idgen), owner, info, owner.options) incl s.flags, sfAnon s.typ = result @@ -225,7 +225,7 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator) = # because of 'gensym' support, we have to mangle the name with its ID. # This is hacky but the clean solution is much more complex than it looks. var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), - nextId(idgen), s.owner, s.info, s.options) + nextSymId(idgen), s.owner, s.info, s.options) field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item) let t = skipIntLit(s.typ, idgen) field.typ = t @@ -239,7 +239,7 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator) = proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym {.discardable.} = result = lookupInRecord(obj.n, s.itemId) if result == nil: - var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), nextId(idgen), + var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), nextSymId(idgen), s.owner, s.info, s.options) field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item) let t = skipIntLit(s.typ, idgen) @@ -326,7 +326,7 @@ proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode = proc genAddrOf*(n: PNode; idgen: IdGenerator; typeKind = tyPtr): PNode = result = newNodeI(nkAddr, n.info, 1) result[0] = n - result.typ = newType(typeKind, nextId(idgen), n.typ.owner) + result.typ = newType(typeKind, nextTypeId(idgen), n.typ.owner) result.typ.rawAddSon(n.typ) proc genDeref*(n: PNode; k = nkHiddenDeref): PNode = diff --git a/compiler/macrocacheimpl.nim b/compiler/macrocacheimpl.nim index 365497e315..c869c22894 100644 --- a/compiler/macrocacheimpl.nim +++ b/compiler/macrocacheimpl.nim @@ -9,71 +9,36 @@ ## This module implements helpers for the macro cache. -import lineinfos, ast, modulegraphs, vmdef +import lineinfos, ast, vmdef + +proc append(c: PCtx; n: PNode) = + c.vmstateDiff.add((c.module, n)) proc recordInc*(c: PCtx; info: TLineInfo; key: string; by: BiggestInt) = - var recorded = newNodeI(nkCommentStmt, info) + var recorded = newNodeI(nkReplayAction, info) recorded.add newStrNode("inc", info) recorded.add newStrNode(key, info) recorded.add newIntNode(nkIntLit, by) - c.graph.recordStmt(c.graph, c.module, recorded) + c.append(recorded) proc recordPut*(c: PCtx; info: TLineInfo; key: string; k: string; val: PNode) = - var recorded = newNodeI(nkCommentStmt, info) + var recorded = newNodeI(nkReplayAction, info) recorded.add newStrNode("put", info) recorded.add newStrNode(key, info) recorded.add newStrNode(k, info) recorded.add copyTree(val) - c.graph.recordStmt(c.graph, c.module, recorded) + c.append(recorded) proc recordAdd*(c: PCtx; info: TLineInfo; key: string; val: PNode) = - var recorded = newNodeI(nkCommentStmt, info) + var recorded = newNodeI(nkReplayAction, info) recorded.add newStrNode("add", info) recorded.add newStrNode(key, info) recorded.add copyTree(val) - c.graph.recordStmt(c.graph, c.module, recorded) + c.append(recorded) proc recordIncl*(c: PCtx; info: TLineInfo; key: string; val: PNode) = - var recorded = newNodeI(nkCommentStmt, info) + var recorded = newNodeI(nkReplayAction, info) recorded.add newStrNode("incl", info) recorded.add newStrNode(key, info) recorded.add copyTree(val) - c.graph.recordStmt(c.graph, c.module, recorded) - -when false: - proc genCall3(g: ModuleGraph; m: TMagic; s: string; a, b, c: PNode): PNode = - newTree(nkStaticStmt, newTree(nkCall, createMagic(g, s, m).newSymNode, a, b, c)) - - proc genCall2(g: ModuleGraph; m: TMagic; s: string; a, b: PNode): PNode = - newTree(nkStaticStmt, newTree(nkCall, createMagic(g, s, m).newSymNode, a, b)) - - template nodeFrom(s: string): PNode = - var res = newStrNode(s, info) - res.typ = getSysType(g, info, tyString) - res - - template nodeFrom(i: BiggestInt): PNode = - var res = newIntNode(i, info) - res.typ = getSysType(g, info, tyInt) - res - - template nodeFrom(n: PNode): PNode = copyTree(n) - - template record(call) = - g.recordStmt(g, c.module, call) - - proc recordInc*(c: PCtx; info: TLineInfo; key: string; by: BiggestInt) = - let g = c.graph - record genCall2(mNccInc, "inc", nodeFrom key, nodeFrom by) - - proc recordPut*(c: PCtx; info: TLineInfo; key: string; k: string; val: PNode) = - let g = c.graph - record genCall3(mNctPut, "[]=", nodeFrom key, nodeFrom k, nodeFrom val) - - proc recordAdd*(c: PCtx; info: TLineInfo; key: string; val: PNode) = - let g = c.graph - record genCall2(mNcsAdd, "add", nodeFrom key, nodeFrom val) - - proc recordIncl*(c: PCtx; info: TLineInfo; key: string; val: PNode) = - let g = c.graph - record genCall2(mNcsIncl, "incl", nodeFrom key, nodeFrom val) + c.append(recorded) diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 71003371e8..e91bdf2726 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -17,36 +17,30 @@ export createMagic proc nilOrSysInt*(g: ModuleGraph): PType = g.sysTypes[tyInt] -proc registerSysType*(g: ModuleGraph; t: PType) = - if g.sysTypes[t.kind] == nil: g.sysTypes[t.kind] = t - proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType = - result = newType(kind, nextId(g.idgen), g.systemModule) + result = newType(kind, nextTypeId(g.idgen), g.systemModule) result.size = size result.align = size.int16 proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym = - result = strTableGet(g.systemModule.tab, getIdent(g.cache, name)) + result = systemModuleSym(g, getIdent(g.cache, name)) if result == nil: localError(g.config, info, "system module needs: " & name) - result = newSym(skError, getIdent(g.cache, name), nextId(g.idgen), g.systemModule, g.systemModule.info, {}) - result.typ = newType(tyError, nextId(g.idgen), g.systemModule) + result = newSym(skError, getIdent(g.cache, name), nextSymId(g.idgen), g.systemModule, g.systemModule.info, {}) + result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule) if result.kind == skAlias: result = result.owner proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym = - var ti: TIdentIter let id = getIdent(g.cache, name) - var r = initIdentIter(ti, g.systemModule.tab, id) - while r != nil: + for r in systemModuleSyms(g, id): if r.magic == m: # prefer the tyInt variant: if r.typ[0] != nil and r.typ[0].kind == tyInt: return r result = r - r = nextIdentIter(ti, g.systemModule.tab) if result != nil: return result localError(g.config, info, "system module needs: " & name) - result = newSym(skError, id, nextId(g.idgen), g.systemModule, g.systemModule.info, {}) - result.typ = newType(tyError, nextId(g.idgen), g.systemModule) + result = newSym(skError, id, nextSymId(g.idgen), g.systemModule, g.systemModule.info, {}) + result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule) proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType = result = getSysSym(g, info, name).typ @@ -91,24 +85,6 @@ proc resetSysTypes*(g: ModuleGraph) = for i in low(g.sysTypes)..high(g.sysTypes): g.sysTypes[i] = nil - for i in low(g.intTypeCache)..high(g.intTypeCache): - g.intTypeCache[i] = nil - -proc getIntLitType*(g: ModuleGraph; literal: PNode): PType = - # we cache some common integer literal types for performance: - let value = literal.intVal - if value >= low(g.intTypeCache) and value <= high(g.intTypeCache): - result = g.intTypeCache[value.int] - if result == nil: - let ti = getSysType(g, literal.info, tyInt) - result = copyType(ti, nextId(g.idgen), ti.owner) - result.n = literal - g.intTypeCache[value.int] = result - else: - let ti = getSysType(g, literal.info, tyInt) - result = copyType(ti, nextId(g.idgen), ti.owner) - result.n = literal - proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType = # for now we do not cache these: result = newSysType(g, tyFloat, size=8) @@ -116,50 +92,21 @@ proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType = proc skipIntLit*(t: PType; id: IdGenerator): PType {.inline.} = if t.n != nil and t.kind in {tyInt, tyFloat}: - result = copyType(t, nextId(id), t.owner) + result = copyType(t, nextTypeId(id), t.owner) result.n = nil else: result = t proc addSonSkipIntLit*(father, son: PType; id: IdGenerator) = - when not defined(nimNoNilSeqs): - if isNil(father.sons): father.sons = @[] let s = son.skipIntLit(id) father.sons.add(s) propagateToOwner(father, s) -proc setIntLitType*(g: ModuleGraph; result: PNode) = - let i = result.intVal - case g.config.target.intSize - of 8: result.typ = getIntLitType(g, result) - of 4: - if i >= low(int32) and i <= high(int32): - result.typ = getIntLitType(g, result) - else: - result.typ = getSysType(g, result.info, tyInt64) - of 2: - if i >= low(int16) and i <= high(int16): - result.typ = getIntLitType(g, result) - elif i >= low(int32) and i <= high(int32): - result.typ = getSysType(g, result.info, tyInt32) - else: - result.typ = getSysType(g, result.info, tyInt64) - of 1: - # 8 bit CPUs are insane ... - if i >= low(int8) and i <= high(int8): - result.typ = getIntLitType(g, result) - elif i >= low(int16) and i <= high(int16): - result.typ = getSysType(g, result.info, tyInt16) - elif i >= low(int32) and i <= high(int32): - result.typ = getSysType(g, result.info, tyInt32) - else: - result.typ = getSysType(g, result.info, tyInt64) - else: - internalError(g.config, result.info, "invalid int size") - proc getCompilerProc*(g: ModuleGraph; name: string): PSym = let ident = getIdent(g.cache, name) result = strTableGet(g.compilerprocs, ident) + if result == nil: + result = loadCompilerProc(g, name) proc registerCompilerProc*(g: ModuleGraph; s: PSym) = strTableAdd(g.compilerprocs, s) diff --git a/compiler/main.nim b/compiler/main.nim index 73676ffd5d..b61cdcadb1 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -19,7 +19,10 @@ import cgen, json, nversion, platform, nimconf, passaux, depends, vm, modules, - modulegraphs, tables, rod, lineinfos, pathutils, vmprofiler + modulegraphs, tables, lineinfos, pathutils, vmprofiler + +import ic / cbackend +from ic / ic import rodViewer when not defined(leanCompiler): import jsgen, docgen, docgen2 @@ -71,14 +74,15 @@ proc commandCompileToC(graph: ModuleGraph) = setOutFile(conf) extccomp.initVars(conf) semanticPasses(graph) - registerPass(graph, cgenPass) + if conf.symbolFiles == disabledSf: + registerPass(graph, cgenPass) - if {optRun, optForceFullMake} * conf.globalOptions == {optRun} or isDefined(conf, "nimBetterRun"): - let proj = changeFileExt(conf.projectFull, "") - if not changeDetectedViaJsonBuildInstructions(conf, proj): - # nothing changed - graph.config.notes = graph.config.mainPackageNotes - return + if {optRun, optForceFullMake} * conf.globalOptions == {optRun} or isDefined(conf, "nimBetterRun"): + let proj = changeFileExt(conf.projectFull, "") + if not changeDetectedViaJsonBuildInstructions(conf, proj): + # nothing changed + graph.config.notes = graph.config.mainPackageNotes + return if not extccomp.ccHasSaneOverflow(conf): conf.symbols.defineSymbol("nimEmulateOverflowChecks") @@ -86,8 +90,14 @@ proc commandCompileToC(graph: ModuleGraph) = compileProject(graph) if graph.config.errorCounter > 0: return # issue #9933 - cgenWriteModules(graph.backend, conf) - if conf.cmd != cmdTcc: + if conf.symbolFiles == disabledSf: + cgenWriteModules(graph.backend, conf) + else: + generateCode(graph) + # graph.backend can be nil under IC when nothing changed at all: + if graph.backend != nil: + cgenWriteModules(graph.backend, conf) + if conf.cmd != cmdTcc and graph.backend != nil: extccomp.callCCompiler(conf) # for now we do not support writing out a .json file with the build instructions when HCR is on if not conf.hcrOn: @@ -137,8 +147,9 @@ proc commandInteractive(graph: ModuleGraph) = else: var m = graph.makeStdinModule() incl(m.flags, sfMainModule) - var idgen = IdGenerator(module: m.itemId.module, item: m.itemId.item) - processModule(graph, m, idgen, llStreamOpenStdIn()) + var idgen = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0) + let s = llStreamOpenStdIn(onPrompt = proc() = flushDot(graph.config)) + processModule(graph, m, idgen, s) proc commandScan(cache: IdentCache, config: ConfigRef) = var f = addFileExt(AbsoluteFile mainCommandArg(config), NimExt) @@ -157,6 +168,10 @@ proc commandScan(cache: IdentCache, config: ConfigRef) = else: rawMessage(config, errGenerated, "cannot open file: " & f.string) +proc commandView(graph: ModuleGraph) = + let f = toAbsolute(mainCommandArg(graph.config), AbsoluteDir getCurrentDir()).addFileExt(RodExt) + rodViewer(f, graph.config, graph.cache) + const PrintRopeCacheStats = false @@ -164,7 +179,6 @@ proc mainCommand*(graph: ModuleGraph) = let conf = graph.config let cache = graph.cache - setupModuleCache(graph) # In "nim serve" scenario, each command must reset the registered passes clearPasses(graph) conf.lastCmdTime = epochTime() @@ -192,8 +206,6 @@ proc mainCommand*(graph: ModuleGraph) = # A better solution might be to fix system.nim undefSymbol(conf.symbols, "useNimRtl") of backendInvalid: doAssert false - if conf.selectedGC in {gcArc, gcOrc} and conf.backend != backendCpp: - conf.exc = excGoto proc compileToBackend() = customizeForBackend(conf.backend) @@ -213,18 +225,17 @@ proc mainCommand*(graph: ModuleGraph) = defineSymbol(conf.symbols, "nimdoc") body - block: ## command prepass - if conf.cmd == cmdCrun: conf.globalOptions.incl {optRun, optUseNimcache} - if conf.cmd notin cmdBackends + {cmdTcc}: customizeForBackend(backendC) - if conf.outDir.isEmpty: - # doc like commands can generate a lot of files (especially with --project) - # so by default should not end up in $PWD nor in $projectPath. - conf.outDir = block: - var ret = if optUseNimcache in conf.globalOptions: getNimcacheDir(conf) - else: conf.projectPath - doAssert ret.string.isAbsolute # `AbsoluteDir` is not a real guarantee - if conf.cmd in cmdDocLike + {cmdRst2html, cmdRst2tex}: ret = ret / htmldocsDir - ret + ## command prepass + if conf.cmd == cmdCrun: conf.globalOptions.incl {optRun, optUseNimcache} + if conf.cmd notin cmdBackends + {cmdTcc}: customizeForBackend(backendC) + if conf.outDir.isEmpty: + # doc like commands can generate a lot of files (especially with --project) + # so by default should not end up in $PWD nor in $projectPath. + var ret = if optUseNimcache in conf.globalOptions: getNimcacheDir(conf) + else: conf.projectPath + doAssert ret.string.isAbsolute # `AbsoluteDir` is not a real guarantee + if conf.cmd in cmdDocLike + {cmdRst2html, cmdRst2tex}: ret = ret / htmldocsDir + conf.outDir = ret ## process all commands case conf.cmd @@ -250,6 +261,10 @@ proc mainCommand*(graph: ModuleGraph) = if optGenIndex in conf.globalOptions and optWholeProject in conf.globalOptions: commandBuildIndex(conf, $conf.outDir) of cmdRst2html: + # XXX: why are warnings disabled by default for rst2html and rst2tex? + for warn in [warnUnknownSubstitutionX, warnLanguageXNotSupported, + warnFieldXNotSupported, warnRstStyle]: + conf.setNoteDefaults(warn, true) conf.setNoteDefaults(warnRedefinitionOfLabel, false) # similar to issue #13218 when defined(leanCompiler): quit "compiler wasn't built with documentation generator" @@ -257,6 +272,10 @@ proc mainCommand*(graph: ModuleGraph) = loadConfigs(DocConfig, cache, conf, graph.idgen) commandRst2Html(cache, conf) of cmdRst2tex: + for warn in [warnRedefinitionOfLabel, warnUnknownSubstitutionX, + warnLanguageXNotSupported, + warnFieldXNotSupported, warnRstStyle]: + conf.setNoteDefaults(warn, true) when defined(leanCompiler): quit "compiler wasn't built with documentation generator" else: @@ -314,10 +333,10 @@ proc mainCommand*(graph: ModuleGraph) = of cmdParse: wantMainModule(conf) discard parseFile(conf.projectMainIdx, cache, conf) - of cmdScan: + of cmdRod: wantMainModule(conf) - commandScan(cache, conf) - msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!") + commandView(graph) + #msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!") of cmdInteractive: commandInteractive(graph) of cmdNimscript: if conf.projectIsCmd or conf.projectIsStdin: discard diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index e3c54eeae3..de3773ca5e 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -9,44 +9,66 @@ ## This module implements the module graph data structure. The module graph ## represents a complete Nim project. Single modules can either be kept in RAM -## or stored in a Sqlite database. -## -## The caching of modules is critical for 'nimsuggest' and is tricky to get -## right. If module E is being edited, we need autocompletion (and type -## checking) for E but we don't want to recompile depending -## modules right away for faster turnaround times. Instead we mark the module's -## dependencies as 'dirty'. Let D be a dependency of E. If D is dirty, we -## need to recompile it and all of its dependencies that are marked as 'dirty'. -## 'nimsuggest sug' actually is invoked for the file being edited so we know -## its content changed and there is no need to compute any checksums. -## Instead of a recursive algorithm, we use an iterative algorithm: -## -## - If a module gets recompiled, its dependencies need to be updated. -## - Its dependent module stays the same. -## +## or stored in a rod-file. -import ast, intsets, tables, options, lineinfos, hashes, idents, - incremental, btrees, md5 +import ast, astalgo, intsets, tables, options, lineinfos, hashes, idents, + btrees, md5, ropes, msgs -# import ic / packed_ast +import ic / [packed_ast, ic] type SigHash* = distinct MD5Digest + LazySym* = object + id*: FullId + sym*: PSym + Iface* = object ## data we don't want to store directly in the ## ast.PSym type for s.kind == skModule module*: PSym ## module this "Iface" belongs to - converters*: seq[PSym] - patterns*: seq[PSym] - pureEnums*: seq[PSym] + converters*: seq[LazySym] + patterns*: seq[LazySym] + pureEnums*: seq[LazySym] + interf: TStrTable + uniqueName*: Rope + + Operators* = object + opNot*, opContains*, opLe*, opLt*, opAnd*, opOr*, opIsNil*, opEq*: PSym + opAdd*, opSub*, opMul*, opDiv*, opLen*: PSym + + FullId* = object + module*: int + packed*: PackedItemId + + LazyType* = object + id*: FullId + typ*: PType + + LazyInstantiation* = object + module*: int + sym*: FullId + concreteTypes*: seq[FullId] + inst*: PInstantiation ModuleGraph* = ref object ifaces*: seq[Iface] ## indexed by int32 fileIdx + packed*: PackedModuleGraph + encoders*: seq[PackedEncoder] + + typeInstCache*: Table[ItemId, seq[LazyType]] # A symbol's ItemId. + procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId. + attachedOps*: array[TTypeAttachedOp, Table[ItemId, PSym]] # Type ID, destructors, etc. + methodsPerType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods + enumToStringProcs*: Table[ItemId, LazySym] + + startupPackedConfig*: PackedConfig packageSyms*: TStrTable + modulesPerPackage*: Table[ItemId, TStrTable] deps*: IntSet # the dependency graph or potentially its transitive closure. importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies suggestMode*: bool # whether we are in nimsuggest mode or not. invalidTransitiveClosure: bool + systemModuleComplete*: bool inclToMod*: Table[FileIndex, FileIndex] # mapping of include file to the # first module that included it importStack*: seq[FileIndex] # The current import stack. Used for detecting recursive @@ -64,18 +86,15 @@ type sysTypes*: array[TTypeKind, PType] compilerprocs*: TStrTable exposed*: TStrTable - intTypeCache*: array[-5..64, PType] - opContains*, opNot*: PSym + packageTypes*: TStrTable emptyNode*: PNode - incr*: IncrementalCtx canonTypes*: Table[SigHash, PType] symBodyHashes*: Table[int, SigHash] # symId to digest mapping importModuleCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PSym {.nimcall.} includeFileCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PNode {.nimcall.} - recordStmt*: proc (graph: ModuleGraph; m: PSym; n: PNode) {.nimcall.} - cacheSeqs*: Table[string, PNode] # state that is shared to support the 'macrocache' API - cacheCounters*: Table[string, BiggestInt] - cacheTables*: Table[string, BTree[string, PNode]] + cacheSeqs*: Table[string, PNode] # state that is shared to support the 'macrocache' API; IC: implemented + cacheCounters*: Table[string, BiggestInt] # IC: implemented + cacheTables*: Table[string, BTree[string, PNode]] # IC: implemented passes*: seq[TPass] onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} @@ -84,6 +103,7 @@ type strongSemCheck*: proc (graph: ModuleGraph; owner: PSym; body: PNode) {.nimcall.} compatibleProps*: proc (graph: ModuleGraph; formal, actual: PType): bool {.nimcall.} idgen*: IdGenerator + operators*: Operators TPassContext* = object of RootObj # the pass's context idgen*: IdGenerator @@ -98,6 +118,14 @@ type close: TPassClose, isFrontend: bool] +proc resetForBackend*(g: ModuleGraph) = + initStrTable(g.compilerprocs) + g.typeInstCache.clear() + g.procInstCache.clear() + for a in mitems(g.attachedOps): + a.clear() + g.methodsPerType.clear() + g.enumToStringProcs.clear() const cb64 = [ @@ -133,6 +161,172 @@ proc toBase64a(s: cstring, len: int): string = result.add cb64[a shr 2] result.add cb64[(a and 3) shl 4] +template semtab*(m: PSym; g: ModuleGraph): TStrTable = + g.ifaces[m.position].interf + +proc isCachedModule(g: ModuleGraph; module: int): bool {.inline.} = + result = module < g.packed.len and g.packed[module].status == loaded + +proc isCachedModule(g: ModuleGraph; m: PSym): bool {.inline.} = + isCachedModule(g, m.position) + +proc simulateCachedModule*(g: ModuleGraph; moduleSym: PSym; m: PackedModule) = + when false: + echo "simulating ", moduleSym.name.s, " ", moduleSym.position + simulateLoadedModule(g.packed, g.config, g.cache, moduleSym, m) + +proc initEncoder*(g: ModuleGraph; module: PSym) = + let id = module.position + if id >= g.encoders.len: + setLen g.encoders, id+1 + ic.initEncoder(g.encoders[id], + g.packed[id].fromDisk, module, g.config, g.startupPackedConfig) + +type + ModuleIter* = object + fromRod: bool + modIndex: int + ti: TIdentIter + rodIt: RodIter + +proc initModuleIter*(mi: var ModuleIter; g: ModuleGraph; m: PSym; name: PIdent): PSym = + assert m.kind == skModule + mi.modIndex = m.position + mi.fromRod = isCachedModule(g, mi.modIndex) + if mi.fromRod: + result = initRodIter(mi.rodIt, g.config, g.cache, g.packed, FileIndex mi.modIndex, name) + else: + result = initIdentIter(mi.ti, g.ifaces[mi.modIndex].interf, name) + +proc nextModuleIter*(mi: var ModuleIter; g: ModuleGraph): PSym = + if mi.fromRod: + result = nextRodIter(mi.rodIt, g.packed) + else: + result = nextIdentIter(mi.ti, g.ifaces[mi.modIndex].interf) + +iterator allSyms*(g: ModuleGraph; m: PSym): PSym = + if isCachedModule(g, m): + var rodIt: RodIter + var r = initRodIterAllSyms(rodIt, g.config, g.cache, g.packed, FileIndex m.position) + while r != nil: + yield r + r = nextRodIter(rodIt, g.packed) + else: + for s in g.ifaces[m.position].interf.data: + if s != nil: + yield s + +proc someSym*(g: ModuleGraph; m: PSym; name: PIdent): PSym = + if isCachedModule(g, m): + result = interfaceSymbol(g.config, g.cache, g.packed, FileIndex(m.position), name) + else: + result = strTableGet(g.ifaces[m.position].interf, name) + +proc systemModuleSym*(g: ModuleGraph; name: PIdent): PSym = + result = someSym(g, g.systemModule, name) + +iterator systemModuleSyms*(g: ModuleGraph; name: PIdent): PSym = + var mi: ModuleIter + var r = initModuleIter(mi, g, g.systemModule, name) + while r != nil: + yield r + r = nextModuleIter(mi, g) + +proc resolveType(g: ModuleGraph; t: var LazyType): PType = + result = t.typ + if result == nil and isCachedModule(g, t.id.module): + result = loadTypeFromId(g.config, g.cache, g.packed, t.id.module, t.id.packed) + t.typ = result + assert result != nil + +proc resolveSym(g: ModuleGraph; t: var LazySym): PSym = + result = t.sym + if result == nil and isCachedModule(g, t.id.module): + result = loadSymFromId(g.config, g.cache, g.packed, t.id.module, t.id.packed) + t.sym = result + assert result != nil + +proc resolveInst(g: ModuleGraph; t: var LazyInstantiation): PInstantiation = + result = t.inst + if result == nil and isCachedModule(g, t.module): + result = PInstantiation(sym: loadSymFromId(g.config, g.cache, g.packed, t.sym.module, t.sym.packed)) + result.concreteTypes = newSeq[PType](t.concreteTypes.len) + for i in 0..high(result.concreteTypes): + result.concreteTypes[i] = loadTypeFromId(g.config, g.cache, g.packed, + t.concreteTypes[i].module, t.concreteTypes[i].packed) + t.inst = result + assert result != nil + +iterator typeInstCacheItems*(g: ModuleGraph; s: PSym): PType = + if g.typeInstCache.contains(s.itemId): + let x = addr(g.typeInstCache[s.itemId]) + for t in mitems(x[]): + yield resolveType(g, t) + +iterator procInstCacheItems*(g: ModuleGraph; s: PSym): PInstantiation = + if g.procInstCache.contains(s.itemId): + let x = addr(g.procInstCache[s.itemId]) + for t in mitems(x[]): + yield resolveInst(g, t) + +proc getAttachedOp*(g: ModuleGraph; t: PType; op: TTypeAttachedOp): PSym = + ## returns the requested attached operation for type `t`. Can return nil + ## if no such operation exists. + result = g.attachedOps[op].getOrDefault(t.itemId) + +proc setAttachedOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) = + ## we also need to record this to the packed module. + g.attachedOps[op][t.itemId] = value + +proc setAttachedOpPartial*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) = + ## we also need to record this to the packed module. + g.attachedOps[op][t.itemId] = value + # XXX Also add to the packed module! + +proc completePartialOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) = + if g.config.symbolFiles != disabledSf: + assert module < g.encoders.len + assert isActive(g.encoders[module]) + toPackedGeneratedProcDef(value, g.encoders[module], g.packed[module].fromDisk) + +proc getToStringProc*(g: ModuleGraph; t: PType): PSym = + result = resolveSym(g, g.enumToStringProcs[t.itemId]) + assert result != nil + +proc setToStringProc*(g: ModuleGraph; t: PType; value: PSym) = + g.enumToStringProcs[t.itemId] = LazySym(sym: value) + +iterator methodsForGeneric*(g: ModuleGraph; t: PType): (int, PSym) = + if g.methodsPerType.contains(t.itemId): + for it in mitems g.methodsPerType[t.itemId]: + yield (it[0], resolveSym(g, it[1])) + +proc addMethodToGeneric*(g: ModuleGraph; module: int; t: PType; col: int; m: PSym) = + g.methodsPerType.mgetOrPut(t.itemId, @[]).add (col, LazySym(sym: m)) + +proc hasDisabledAsgn*(g: ModuleGraph; t: PType): bool = + let op = getAttachedOp(g, t, attachedAsgn) + result = op != nil and sfError in op.flags + +proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) = + for k in low(TTypeAttachedOp)..high(TTypeAttachedOp): + let op = getAttachedOp(g, src, k) + if op != nil: + setAttachedOp(g, module, dest, k, op) + +proc loadCompilerProc*(g: ModuleGraph; name: string): PSym = + if g.config.symbolFiles == disabledSf: return nil + + # slow, linear search, but the results are cached: + for module in 0..high(g.packed): + #if isCachedModule(g, module): + let x = searchForCompilerproc(g.packed[module], name) + if x >= 0: + result = loadSymFromId(g.config, g.cache, g.packed, module, toPackedItemId(x)) + if result != nil: + strTableAdd(g.compilerprocs, result) + return result + proc `$`*(u: SigHash): string = toBase64a(cast[cstring](unsafeAddr u), sizeof(u)) @@ -175,22 +369,52 @@ else: proc stopCompile*(g: ModuleGraph): bool {.inline.} = result = g.doStopCompile != nil and g.doStopCompile() -proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = - result = newSym(skProc, getIdent(g.cache, name), nextId(g.idgen), nil, unknownLineInfo, {}) +proc createMagic*(g: ModuleGraph; idgen: IdGenerator; name: string, m: TMagic): PSym = + result = newSym(skProc, getIdent(g.cache, name), nextSymId(idgen), nil, unknownLineInfo, {}) result.magic = m result.flags = {sfNeverRaises} +proc createMagic(g: ModuleGraph; name: string, m: TMagic): PSym = + result = createMagic(g, g.idgen, name, m) + proc registerModule*(g: ModuleGraph; m: PSym) = assert m != nil assert m.kind == skModule if m.position >= g.ifaces.len: setLen(g.ifaces, m.position + 1) - g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[]) + + if m.position >= g.packed.len: + setLen(g.packed, m.position + 1) + + g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[], + uniqueName: rope(uniqueModuleName(g.config, FileIndex(m.position)))) + initStrTable(g.ifaces[m.position].interf) + +proc registerModuleById*(g: ModuleGraph; m: FileIndex) = + registerModule(g, g.packed[int m].module) + +proc initOperators(g: ModuleGraph): Operators = + # These are safe for IC. + result.opLe = createMagic(g, "<=", mLeI) + result.opLt = createMagic(g, "<", mLtI) + result.opAnd = createMagic(g, "and", mAnd) + result.opOr = createMagic(g, "or", mOr) + result.opIsNil = createMagic(g, "isnil", mIsNil) + result.opEq = createMagic(g, "==", mEqI) + result.opAdd = createMagic(g, "+", mAddI) + result.opSub = createMagic(g, "-", mSubI) + result.opMul = createMagic(g, "*", mMulI) + result.opDiv = createMagic(g, "div", mDivI) + result.opLen = createMagic(g, "len", mLengthSeq) + result.opNot = createMagic(g, "not", mNot) + result.opContains = createMagic(g, "contains", mInSet) proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result = ModuleGraph() - result.idgen = IdGenerator(module: -1'i32, item: 0'i32) + # A module ID of -1 means that the symbol is not attached to a module at all, + # but to the module graph: + result.idgen = IdGenerator(module: -1'i32, symId: 0'i32, typeId: 0'i32) initStrTable(result.packageSyms) result.deps = initIntSet() result.importDeps = initTable[FileIndex, seq[FileIndex]]() @@ -203,17 +427,14 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result.methods = @[] initStrTable(result.compilerprocs) initStrTable(result.exposed) - result.opNot = createMagic(result, "not", mNot) - result.opContains = createMagic(result, "contains", mInSet) + initStrTable(result.packageTypes) result.emptyNode = newNode(nkEmpty) - init(result.incr) - result.recordStmt = proc (graph: ModuleGraph; m: PSym; n: PNode) {.nimcall.} = - discard result.cacheSeqs = initTable[string, PNode]() result.cacheCounters = initTable[string, BiggestInt]() result.cacheTables = initTable[string, BTree[string, PNode]]() result.canonTypes = initTable[SigHash, PType]() result.symBodyHashes = initTable[int, SigHash]() + result.operators = initOperators(result) proc resetAllModules*(g: ModuleGraph) = initStrTable(g.packageSyms) @@ -228,14 +449,16 @@ proc resetAllModules*(g: ModuleGraph) = initStrTable(g.exposed) proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym = - if fileIdx.int32 >= 0 and fileIdx.int32 < g.ifaces.len: - result = g.ifaces[fileIdx.int32].module + if fileIdx.int32 >= 0: + if isCachedModule(g, fileIdx.int32): + result = g.packed[fileIdx.int32].module + elif fileIdx.int32 < g.ifaces.len: + result = g.ifaces[fileIdx.int32].module proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) = assert m.position == m.info.fileIndex.int32 - addModuleDep(g.incr, g.config, m.info.fileIndex, dep, isIncludeFile = false) if g.suggestMode: g.deps.incl m.position.dependsOn(dep.int) # we compute the transitive closure later when querying the graph lazily. @@ -243,7 +466,6 @@ proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) = #invalidTransitiveClosure = true proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) = - addModuleDep(g.incr, g.config, module, includeFile, isIncludeFile = true) discard hasKeyOrPut(g.inclToMod, includeFile, module) proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex = @@ -284,3 +506,19 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) = proc isDirty*(g: ModuleGraph; m: PSym): bool = result = g.suggestMode and sfDirty in m.flags + +proc getBody*(g: ModuleGraph; s: PSym): PNode {.inline.} = + result = s.ast[bodyPos] + if result == nil and g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}: + result = loadProcBody(g.config, g.cache, g.packed, s) + s.ast[bodyPos] = result + assert result != nil + +proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex; + cachedModules: var seq[FileIndex]): PSym = + ## Returns 'nil' if the module needs to be recompiled. + if g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}: + result = moduleFromRodFile(g.packed, g.config, g.cache, fileIdx, cachedModules) + +proc configComplete*(g: ModuleGraph) = + rememberStartupConfig(g.startupPackedConfig, g.config) diff --git a/compiler/modules.nim b/compiler/modules.nim index 132f3788d3..7d7a2b6f72 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -11,9 +11,11 @@ import ast, astalgo, magicsys, msgs, options, - idents, lexer, passes, syntaxes, llstream, modulegraphs, rod, + idents, lexer, passes, syntaxes, llstream, modulegraphs, lineinfos, pathutils, tables +import ic / replayer + proc resetSystemArtifacts*(g: ModuleGraph) = magicsys.resetSysTypes(g) @@ -31,13 +33,14 @@ proc getPackage(graph: ModuleGraph; fileIdx: FileIndex): PSym = pck = getPackageName(graph.config, filename.string) pck2 = if pck.len > 0: pck else: "unknown" pack = getIdent(graph.cache, pck2) - var packSym = graph.packageSyms.strTableGet(pack) - if packSym == nil: - packSym = newSym(skPackage, getIdent(graph.cache, pck2), packageId(), nil, info) - initStrTable(packSym.tab) - graph.packageSyms.strTableAdd(packSym) + result = graph.packageSyms.strTableGet(pack) + if result == nil: + result = newSym(skPackage, getIdent(graph.cache, pck2), packageId(), nil, info) + #initStrTable(packSym.tab) + graph.packageSyms.strTableAdd(result) else: - let existing = strTableGet(packSym.tab, name) + let modules = graph.modulesPerPackage.getOrDefault(result.itemId) + let existing = if modules.data.len > 0: strTableGet(modules, name) else: nil if existing != nil and existing.info.fileIndex != info.fileIndex: when false: # we used to produce an error: @@ -48,26 +51,26 @@ proc getPackage(graph: ModuleGraph; fileIdx: FileIndex): PSym = # but starting with version 0.20 we now produce a fake Nimble package instead # to resolve the conflicts: let pck3 = fakePackageName(graph.config, filename) - # this makes the new `packSym`'s owner be the original `packSym` - packSym = newSym(skPackage, getIdent(graph.cache, pck3), packageId(), packSym, info) - initStrTable(packSym.tab) - graph.packageSyms.strTableAdd(packSym) - result = packSym + # this makes the new `result`'s owner be the original `result` + result = newSym(skPackage, getIdent(graph.cache, pck3), packageId(), result, info) + #initStrTable(packSym.tab) + graph.packageSyms.strTableAdd(result) proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) = let packSym = getPackage(graph, fileIdx) result.owner = packSym result.position = int fileIdx - graph.registerModule(result) - - initStrTable(result.tab) + #initStrTable(result.tab(graph)) when false: strTableAdd(result.tab, result) # a module knows itself # This is now implemented via # c.moduleScope.addSym(module) # a module knows itself # in sem.nim, around line 527 - strTableAdd(packSym.tab, result) + + if graph.modulesPerPackage.getOrDefault(packSym.itemId).data.len == 0: + graph.modulesPerPackage[packSym.itemId] = newStrTable() + graph.modulesPerPackage[packSym.itemId].strTableAdd(result) proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = let filename = AbsoluteFile toFullPath(graph.config, fileIdx) @@ -79,6 +82,7 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = if not isNimIdentifier(result.name.s): rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s) partialInitModule(result, graph, fileIdx, filename) + graph.registerModule(result) proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): PSym = var flags = flags @@ -92,19 +96,26 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput) discard processModule(graph, result, idGeneratorFromModule(result), s) if result == nil: + var cachedModules: seq[FileIndex] + result = moduleFromRodFile(graph, fileIdx, cachedModules) let filename = AbsoluteFile toFullPath(graph.config, fileIdx) - result = loadModuleSym(graph, fileIdx, filename) if result == nil: result = newModule(graph, fileIdx) result.flags.incl flags registerModule(graph, result) + processModuleAux() else: + if sfSystemModule in flags: + graph.systemModule = result partialInitModule(result, graph, fileIdx, filename) - processModuleAux() + for m in cachedModules: + registerModuleById(graph, m) + replayStateChanges(graph.packed[m.int].module, graph) + replayGenericCacheInformation(graph, m.int) elif graph.isDirty(result): result.flags.excl sfDirty # reset module fields: - initStrTable(result.tab) + initStrTable(result.semtab(graph)) result.ast = nil processModuleAux() graph.markClientsDirty(fileIdx) @@ -150,6 +161,8 @@ proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) = connectCallbacks(graph) let conf = graph.config wantMainModule(conf) + configComplete(graph) + let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim") let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx conf.projectMainIdx2 = projectFile diff --git a/compiler/msgs.nim b/compiler/msgs.nim index d027ce960e..bbe40507f6 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -19,9 +19,11 @@ template instLoc(): InstantiationInfo = instantiationInfo(-2, fullPaths = true) template toStdOrrKind(stdOrr): untyped = if stdOrr == stdout: stdOrrStdout else: stdOrrStderr -template flushDot(conf, stdOrr) = +proc flushDot*(conf: ConfigRef) = ## safe to call multiple times - let stdOrrKind = stdOrr.toStdOrrKind() + # xxx one edge case not yet handled is when `printf` is called at CT with `compiletimeFFI`. + let stdOrr = if optStdout in conf.globalOptions: stdout else: stderr + let stdOrrKind = toStdOrrKind(stdOrr) if stdOrrKind in conf.lastMsgWasDot: conf.lastMsgWasDot.excl stdOrrKind write(stdOrr, "\n") @@ -113,6 +115,7 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool else: isKnownFile = false result = conf.m.fileInfos.len.FileIndex + #echo "ID ", result.int, " ", canon2 conf.m.fileInfos.add(newFileInfo(canon, if pseudoPath: RelativeFile filename else: relativeTo(canon, conf.projectPath))) conf.m.filenameToIndexTbl[canon2] = result @@ -311,12 +314,12 @@ proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) = conf.writelnHook(s) elif optStdout in conf.globalOptions or msgStdout in flags: if eStdOut in conf.m.errorOutputs: - flushDot(conf, stdout) + flushDot(conf) writeLine(stdout, s) flushFile(stdout) else: if eStdErr in conf.m.errorOutputs: - flushDot(conf, stderr) + flushDot(conf) writeLine(stderr, s) # On Windows stderr is fully-buffered when piped, regardless of C std. when defined(windows): @@ -368,11 +371,11 @@ template styledMsgWriteln*(args: varargs[typed]) = callIgnoringStyle(callWritelnHook, nil, args) elif optStdout in conf.globalOptions: if eStdOut in conf.m.errorOutputs: - flushDot(conf, stdout) + flushDot(conf) callIgnoringStyle(writeLine, stdout, args) flushFile(stdout) elif eStdErr in conf.m.errorOutputs: - flushDot(conf, stderr) + flushDot(conf) if optUseColors in conf.globalOptions: callStyledWriteLineStderr(args) else: @@ -411,7 +414,7 @@ proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) if conf.cmd == cmdIdeTools: log(s) quit(conf, msg) if msg >= errMin and msg <= errMax or - (msg in warnMin..warnMax and msg in conf.warningAsErrors): + (msg in warnMin..hintMax and msg in conf.warningAsErrors): inc(conf.errorCounter) conf.exitcode = 1'i8 if conf.errorCounter >= conf.errorMax: @@ -458,7 +461,7 @@ proc numLines*(conf: ConfigRef, fileIdx: FileIndex): int = if result == 0: try: for line in lines(toFullPathConsiderDirty(conf, fileIdx).string): - addSourceLine conf, fileIdx, line.string + addSourceLine conf, fileIdx, line except IOError: discard result = conf.m.fileInfos[fileIdx.int32].lines.len @@ -520,7 +523,11 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, of hintMin..hintMax: sev = Severity.Hint ignoreMsg = not conf.hasHint(msg) - title = HintTitle + if msg in conf.warningAsErrors: + ignoreMsg = false + title = ErrorTitle + else: + title = HintTitle color = HintColor inc(conf.hintCounter) @@ -584,6 +591,9 @@ template localError*(conf: ConfigRef; info: TLineInfo, format: string, params: o template message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = liMessage(conf, info, msg, arg, doNothing, instLoc()) +proc warningDeprecated*(conf: ConfigRef, info: TLineInfo = gCmdLineInfo, msg = "") {.inline.} = + message(conf, info, warnDeprecated, msg) + proc internalErrorImpl(conf: ConfigRef; info: TLineInfo, errMsg: string, info2: InstantiationInfo) = if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return writeContext(conf, info) @@ -621,3 +631,28 @@ template listMsg(title, r) = proc listWarnings*(conf: ConfigRef) = listMsg("Warnings:", warnMin..warnMax) proc listHints*(conf: ConfigRef) = listMsg("Hints:", hintMin..hintMax) + +proc uniqueModuleName*(conf: ConfigRef; fid: FileIndex): string = + ## The unique module name is guaranteed to only contain {'A'..'Z', 'a'..'z', '0'..'9', '_'} + ## so that it is useful as a C identifier snippet. + let path = AbsoluteFile toFullPath(conf, fid) + let rel = + if path.string.startsWith(conf.libpath.string): + relativeTo(path, conf.libpath).string + else: + relativeTo(path, conf.projectPath).string + let trunc = if rel.endsWith(".nim"): rel.len - len(".nim") else: rel.len + result = newStringOfCap(trunc) + for i in 0.. nilability +# a = b +# nilability a <- nilability b +# deref a +# if Nil error is nil +# if MaybeNil error might be nil, hint add if isNil +# if Safe fine +# fun(arg: A) +# nilability arg <- for ref MaybeNil, for not nil or others Safe +# map is env? +# a or b +# each one forks a different env +# result = union(envL, envR) +# a and b +# b forks a's env +# if a: code +# result = union(previousEnv after not a, env after code) +# if a: b else: c +# result = union(env after b, env after c) +# result = b +# nilability result <- nilability b, if return type is not nil and result not safe, error +# return b +# as result = b +# try: a except: b finally: c +# in b and c env is union of all possible try first n lines, after union of a and b and c +# keep in mind canRaise and finally +# case a: of b: c +# similar to if +# call(arg) +# if it returns ref, assume it's MaybeNil: hint that one can add not nil to the return type +# call(var arg) # zahary comment +# if arg is ref, assume it's MaybeNil after call +# loop +# union of env for 0, 1, 2 iterations as Herb Sutter's paper +# why 2? +# return +# if something: stop (break return etc) +# is equivalent to if something: .. else: remain +# new(ref) +# ref becomes Safe +# objConstr(a: b) +# returns safe +# each check returns its nilability and map + +type + SeqOfDistinct[T, U] = distinct seq[U] + +# TODO use distinct base type instead of int? +func `[]`[T, U](a: SeqOfDistinct[T, U], index: T): U = + (seq[U])(a)[index.int] + +proc `[]=`[T, U](a: var SeqOfDistinct[T, U], index: T, value: U) = + ((seq[U])(a))[index.int] = value + +func `[]`[T, U](a: var SeqOfDistinct[T, U], index: T): var U = + (seq[U])(a)[index.int] + +func len[T, U](a: SeqOfDistinct[T, U]): T = + (seq[U])(a).len.T + +func low[T, U](a: SeqOfDistinct[T, U]): T = + (seq[U])(a).low.T + +func high[T, U](a: SeqOfDistinct[T, U]): T = + (seq[U])(a).high.T + +proc setLen[T, U](a: var SeqOfDistinct[T, U], length: T) = + ((seq[U])(a)).setLen(length.Natural) + + +proc newSeqOfDistinct[T, U](length: T = 0.T): SeqOfDistinct[T, U] = + (SeqOfDistinct[T, U])(newSeq[U](length.int)) + +func newSeqOfDistinct[T, U](length: int = 0): SeqOfDistinct[T, U] = + # newSeqOfDistinct(length.T) + # ? newSeqOfDistinct[T, U](length.T) + (SeqOfDistinct[T, U])(newSeq[U](length)) + +iterator items[T, U](a: SeqOfDistinct[T, U]): U = + for element in (seq[U])(a): + yield element + +iterator pairs[T, U](a: SeqOfDistinct[T, U]): (T, U) = + for i, element in (seq[U])(a): + yield (i.T, element) + +func `$`[T, U](a: SeqOfDistinct[T, U]): string = + $((seq[U])(a)) + +proc add*[T, U](a: var SeqOfDistinct[T, U], value: U) = + ((seq[U])(a)).add(value) + +type + ## a hashed representation of a node: should be equal for structurally equal nodes + Symbol = distinct int + + ## the index of an expression in the pre-indexed sequence of those + ExprIndex = distinct int16 + + ## the set index + SetIndex = distinct int + + ## transition kind: + ## what was the reason for changing the nilability of an expression + ## useful for error messages and showing why an expression is being detected as nil / maybe nil + TransitionKind = enum TArg, TAssign, TType, TNil, TVarArg, TResult, TSafe, TPotentialAlias, TDependant + + ## keep history for each transition + History = object + info: TLineInfo ## the location + nilability: Nilability ## the nilability + kind: TransitionKind ## what kind of transition was that + node: PNode ## the node of the expression + + ## the context for the checker: an instance for each procedure + NilCheckerContext = ref object + # abstractTime: AbstractTime + # partitions: Partitions + # symbolGraphs: Table[Symbol, ] + symbolIndices: Table[Symbol, ExprIndex] ## index for each symbol + expressions: SeqOfDistinct[ExprIndex, PNode] ## a sequence of pre-indexed expressions + dependants: SeqOfDistinct[ExprIndex, IntSet] ## expr indices for expressions which are compound and based on others + warningLocations: HashSet[TLineInfo] ## warning locations to check we don't warn twice for stuff like warnings in for loops + idgen: IdGenerator ## id generator + config: ConfigRef ## the config of the compiler + + ## a map that is containing the current nilability for usually a branch + ## and is pointing optionally to a parent map: they make a stack of maps + NilMap = ref object + expressions: SeqOfDistinct[ExprIndex, Nilability] ## the expressions with the same order as in NilCheckerContext + history: SeqOfDistinct[ExprIndex, seq[History]] ## history for each of them + # what about gc and refs? + setIndices: SeqOfDistinct[ExprIndex, SetIndex] ## set indices for each expression + sets: SeqOfDistinct[SetIndex, IntSet] ## disjoint sets with the aliased expressions + parent: NilMap ## the parent map + + ## Nilability : if a value is nilable. + ## we have maybe nil and nil, so we can differentiate between + ## cases where we know for sure a value is nil and not + ## otherwise we can have Safe, MaybeNil + ## Parent: is because we just use a sequence with the same length + ## instead of a table, and we need to check if something was initialized + ## at all: if Parent is set, then you need to check the parent nilability + ## if the parent is nil, then for now we return MaybeNil + ## unreachable is the result of add(Safe, Nil) and others + ## it is a result of no states left, so it's usually e.g. in unreachable else branches? + Nilability* = enum Parent, Safe, MaybeNil, Nil, Unreachable + + ## check + Check = object + nilability: Nilability + map: NilMap + elements: seq[(PNode, Nilability)] + + +# useful to have known resultId so we can set it in the beginning and on return +const resultId: Symbol = (-1).Symbol +const resultExprIndex: ExprIndex = 0.ExprIndex +const noSymbol = (-2).Symbol + +func `<`*(a: ExprIndex, b: ExprIndex): bool = + a.int16 < b.int16 + +func `<=`*(a: ExprIndex, b: ExprIndex): bool = + a.int16 <= b.int16 + +func `>`*(a: ExprIndex, b: ExprIndex): bool = + a.int16 > b.int16 + +func `>=`*(a: ExprIndex, b: ExprIndex): bool = + a.int16 >= b.int16 + +func `==`*(a: ExprIndex, b: ExprIndex): bool = + a.int16 == b.int16 + +func `$`*(a: ExprIndex): string = + $(a.int16) + +func `+`*(a: ExprIndex, b: ExprIndex): ExprIndex = + (a.int16 + b.int16).ExprIndex + +# TODO overflowing / < 0? +func `-`*(a: ExprIndex, b: ExprIndex): ExprIndex = + (a.int16 - b.int16).ExprIndex + +func `$`*(a: SetIndex): string = + $(a.int) + +func `==`*(a: SetIndex, b: SetIndex): bool = + a.int == b.int + +func `+`*(a: SetIndex, b: SetIndex): SetIndex = + (a.int + b.int).SetIndex + +# TODO over / under limit? +func `-`*(a: SetIndex, b: SetIndex): SetIndex = + (a.int - b.int).SetIndex + +proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check +proc checkCondition(n: PNode, ctx: NilCheckerContext, map: NilMap, reverse: bool, base: bool): NilMap + +# the NilMap structure + +proc newNilMap(parent: NilMap = nil, count: int = -1): NilMap = + var expressionsCount = 0 + if count != -1: + expressionsCount = count + elif not parent.isNil: + expressionsCount = parent.expressions.len.int + result = NilMap( + expressions: newSeqOfDistinct[ExprIndex, Nilability](expressionsCount), + history: newSeqOfDistinct[ExprIndex, seq[History]](expressionsCount), + setIndices: newSeqOfDistinct[ExprIndex, SetIndex](expressionsCount), + parent: parent) + if parent.isNil: + for i, expr in result.expressions: + result.setIndices[i] = i.SetIndex + var newSet = initIntSet() + newSet.incl(i.int) + result.sets.add(newSet) + else: + for i, exprs in parent.sets: + result.sets.add(exprs) + for i, index in parent.setIndices: + result.setIndices[i] = index + # result.sets = parent.sets + # if not parent.isNil: + # # optimize []? + # result.expressions = parent.expressions + # result.history = parent.history + # result.sets = parent.sets + # result.base = if parent.isNil: result else: parent.base + +proc `[]`(map: NilMap, index: ExprIndex): Nilability = + if index < 0.ExprIndex or index >= map.expressions.len: + return MaybeNil + var now = map + while not now.isNil: + if now.expressions[index] != Parent: + return now.expressions[index] + now = now.parent + return MaybeNil + +proc history(map: NilMap, index: ExprIndex): seq[History] = + if index < map.expressions.len: + map.history[index] + else: + @[] + + +# helpers for debugging + +# import macros + +# echo-s only when nilDebugInfo is defined +# macro aecho*(a: varargs[untyped]): untyped = +# var e = nnkCall.newTree(ident"echo") +# for b in a: +# e.add(b) +# result = quote: +# when defined(nilDebugInfo): +# `e` + +# end of helpers for debugging + + +proc symbol(n: PNode): Symbol +func `$`(map: NilMap): string +proc reverseDirect(map: NilMap): NilMap +proc checkBranch(n: PNode, ctx: NilCheckerContext, map: NilMap): Check +proc hasUnstructuredControlFlowJump(n: PNode): bool + +proc symbol(n: PNode): Symbol = + ## returns a Symbol for each expression + ## the goal is to get an unique Symbol + ## but we have to ensure hashTree does it as we expect + case n.kind: + of nkIdent: + # TODO ensure no idents get passed to symbol + result = noSymbol + of nkSym: + if n.sym.kind == skResult: # credit to disruptek for showing me that + result = resultId + else: + result = n.sym.id.Symbol + of nkHiddenAddr, nkAddr: + result = symbol(n[0]) + else: + result = hashTree(n).Symbol + # echo "symbol ", n, " ", n.kind, " ", result.int + +func `$`(map: NilMap): string = + var now = map + var stack: seq[NilMap] = @[] + while not now.isNil: + stack.add(now) + now = now.parent + result.add("### start\n") + for i in 0 .. stack.len - 1: + now = stack[i] + result.add(" ###\n") + for index, value in now.expressions: + result.add(&" {index} {value}\n") + result.add "### end\n" + +proc namedMapDebugInfo(ctx: NilCheckerContext, map: NilMap): string = + result = "" + var now = map + var stack: seq[NilMap] = @[] + while not now.isNil: + stack.add(now) + now = now.parent + result.add("### start\n") + for i in 0 .. stack.len - 1: + now = stack[i] + result.add(" ###\n") + for index, value in now.expressions: + let name = ctx.expressions[index] + result.add(&" {name} {index} {value}\n") + result.add("### end\n") + +proc namedSetsDebugInfo(ctx: NilCheckerContext, map: NilMap): string = + result = "### sets " + for index, setIndex in map.setIndices: + var aliasSet = map.sets[setIndex] + result.add("{") + let expressions = aliasSet.mapIt($ctx.expressions[it.ExprIndex]) + result.add(join(expressions, ", ")) + result.add("} ") + result.add("\n") + +proc namedMapAndSetsDebugInfo(ctx: NilCheckerContext, map: NilMap): string = + result = namedMapDebugInfo(ctx, map) & namedSetsDebugInfo(ctx, map) + + + +const noExprIndex = (-1).ExprIndex +const noSetIndex = (-1).SetIndex + +proc `==`(a: Symbol, b: Symbol): bool = + a.int == b.int + +func `$`(a: Symbol): string = + $(a.int) + +template isConstBracket(n: PNode): bool = + n.kind == nkBracketExpr and n[1].kind in nkLiterals + +proc index(ctx: NilCheckerContext, n: PNode): ExprIndex = + # echo "n ", n, " ", n.kind + let a = symbol(n) + if ctx.symbolIndices.hasKey(a): + return ctx.symbolIndices[a] + else: + #for a, e in ctx.expressions: + # echo a, " ", e + #echo n.kind + # internalError(ctx.config, n.info, "expected " & $a & " " & $n & " to have a index") + return noExprIndex + # + #ctx.symbolIndices[symbol(n)] + + +proc aliasSet(ctx: NilCheckerContext, map: NilMap, n: PNode): IntSet = + result = map.sets[map.setIndices[ctx.index(n)]] + +proc aliasSet(ctx: NilCheckerContext, map: NilMap, index: ExprIndex): IntSet = + result = map.sets[map.setIndices[index]] + + + +proc store(map: NilMap, ctx: NilCheckerContext, index: ExprIndex, value: Nilability, kind: TransitionKind, info: TLineInfo, node: PNode = nil) = + if index == noExprIndex: + return + map.expressions[index] = value + map.history[index].add(History(info: info, kind: kind, node: node, nilability: value)) + #echo node, " ", index, " ", value + #echo ctx.namedMapAndSetsDebugInfo(map) + #for a, b in map.sets: + # echo a, " ", b + # echo map + + var exprAliases = aliasSet(ctx, map, index) + for a in exprAliases: + if a.ExprIndex != index: + #echo "alias ", a, " ", index + map.expressions[a.ExprIndex] = value + if value == Safe: + map.history[a.ExprIndex] = @[] + else: + map.history[a.ExprIndex].add(History(info: info, kind: TPotentialAlias, node: node, nilability: value)) + +proc moveOut(ctx: NilCheckerContext, map: NilMap, target: PNode) = + #echo "move out ", target + var targetIndex = ctx.index(target) + var targetSetIndex = map.setIndices[targetIndex] + if targetSetIndex != noSetIndex: + var targetSet = map.sets[targetSetIndex] + if targetSet.len > 1: + var other: ExprIndex + + for element in targetSet: + if element.ExprIndex != targetIndex: + other = element.ExprIndex + break + # map.sets[element].excl(targetIndex) + map.sets[map.setIndices[other]].excl(targetIndex.int) + var newSet = initIntSet() + newSet.incl(targetIndex.int) + map.sets.add(newSet) + map.setIndices[targetIndex] = map.sets.len - 1.SetIndex + +proc moveOutDependants(ctx: NilCheckerContext, map: NilMap, node: PNode) = + let index = ctx.index(node) + for dependant in ctx.dependants[index]: + moveOut(ctx, map, ctx.expressions[dependant.ExprIndex]) + +proc storeDependants(ctx: NilCheckerContext, map: NilMap, node: PNode, value: Nilability) = + let index = ctx.index(node) + for dependant in ctx.dependants[index]: + map.store(ctx, dependant.ExprIndex, value, TDependant, node.info, node) + +proc move(ctx: NilCheckerContext, map: NilMap, target: PNode, assigned: PNode) = + #echo "move ", target, " ", assigned + var targetIndex = ctx.index(target) + var assignedIndex: ExprIndex + var targetSetIndex = map.setIndices[targetIndex] + var assignedSetIndex: SetIndex + if assigned.kind == nkSym: + assignedIndex = ctx.index(assigned) + assignedSetIndex = map.setIndices[assignedIndex] + else: + assignedIndex = noExprIndex + assignedSetIndex = noSetIndex + if assignedIndex == noExprIndex: + moveOut(ctx, map, target) + elif targetSetIndex != assignedSetIndex: + map.sets[targetSetIndex].excl(targetIndex.int) + map.sets[assignedSetIndex].incl(targetIndex.int) + map.setIndices[targetIndex] = assignedSetIndex + +# proc hasKey(map: NilMap, ): bool = +# var now = map +# result = false +# while not now.isNil: +# if now.locals.hasKey(graphIndex): +# return true +# now = now.previous + +iterator pairs(map: NilMap): (ExprIndex, Nilability) = + for index, value in map.expressions: + yield (index, map[index]) + +proc copyMap(map: NilMap): NilMap = + if map.isNil: + return nil + result = newNilMap(map.parent) # no need for copy? if we change only this + result.expressions = map.expressions + result.history = map.history + result.sets = map.sets + result.setIndices = map.setIndices + +using + n: PNode + conf: ConfigRef + ctx: NilCheckerContext + map: NilMap + +proc typeNilability(typ: PType): Nilability + +# maybe: if canRaise, return MaybeNil ? +# no, because the target might be safe already +# with or without an exception +proc checkCall(n, ctx, map): Check = + # checks each call + # special case for new(T) -> result is always Safe + # for the others it depends on the return type of the call + # check args and handle possible mutations + + var isNew = false + result.map = map + for i, child in n: + discard check(child, ctx, map) + + if i > 0: + # var args make a new map with MaybeNil for our node + # as it might have been mutated + # TODO similar for normal refs and fields: find dependent exprs: brackets + + if child.kind == nkHiddenAddr and not child.typ.isNil and child.typ.kind == tyVar and child.typ[0].kind == tyRef: + if not isNew: + result.map = newNilMap(map) + isNew = true + # result.map[$child] = MaybeNil + var arg = child + while arg.kind == nkHiddenAddr: + arg = arg[0] + let a = ctx.index(arg) + if a != noExprIndex: + moveOut(ctx, result.map, arg) + moveOutDependants(ctx, result.map, arg) + result.map.store(ctx, a, MaybeNil, TVarArg, n.info, arg) + storeDependants(ctx, result.map, arg, MaybeNil) + elif not child.typ.isNil and child.typ.kind == tyRef: + if child.kind in {nkSym, nkDotExpr} or isConstBracket(child): + let a = ctx.index(child) + if ctx.dependants[a].len > 0: + if not isNew: + result.map = newNilMap(map) + isNew = true + moveOutDependants(ctx, result.map, child) + storeDependants(ctx, result.map, child, MaybeNil) + + if n[0].kind == nkSym and n[0].sym.magic == mNew: + # new hidden deref? + var value = if n[1].kind == nkHiddenDeref: n[1][0] else: n[1] + let b = ctx.index(value) + result.map.store(ctx, b, Safe, TAssign, value.info, value) + result.nilability = Safe + else: + # echo "n ", n, " ", n.typ.isNil + if not n.typ.isNil: + result.nilability = typeNilability(n.typ) + else: + result.nilability = Safe + # echo result.map + +template event(b: History): string = + case b.kind: + of TArg: "param with nilable type" + of TNil: "it returns true for isNil" + of TAssign: "assigns a value which might be nil" + of TVarArg: "passes it as a var arg which might change to nil" + of TResult: "it is nil by default" + of TType: "it has ref type" + of TSafe: "it is safe here as it returns false for isNil" + of TPotentialAlias: "it might be changed directly or through an alias" + of TDependant: "it might be changed because its base might be changed" + +proc derefWarning(n, ctx, map; kind: Nilability) = + ## a warning for potentially unsafe dereference + if n.info in ctx.warningLocations: + return + ctx.warningLocations.incl(n.info) + var a: seq[History] + if n.kind == nkSym: + a = history(map, ctx.index(n)) + var res = "" + var issue = case kind: + of Nil: "it is nil" + of MaybeNil: "it might be nil" + of Unreachable: "it is unreachable" + else: "" + res.add("can't deref " & $n & ", " & issue) + if a.len > 0: + res.add("\n") + for b in a: + res.add(" " & event(b) & " on line " & $b.info.line & ":" & $b.info.col) + message(ctx.config, n.info, warnStrictNotNil, res) + +proc handleNilability(check: Check; n, ctx, map) = + ## handle the check: + ## register a warning(error?) for Nil/MaybeNil + case check.nilability: + of Nil: + derefWarning(n, ctx, map, Nil) + of MaybeNil: + derefWarning(n, ctx, map, MaybeNil) + of Unreachable: + derefWarning(n, ctx, map, Unreachable) + else: + when defined(nilDebugInfo): + message(ctx.config, n.info, hintUser, "can deref " & $n) + +proc checkDeref(n, ctx, map): Check = + ## check dereference: deref n should be ok only if n is Safe + result = check(n[0], ctx, map) + + handleNilability(result, n[0], ctx, map) + + +proc checkRefExpr(n, ctx; check: Check): Check = + ## check ref expressions: TODO not sure when this happens + result = check + if n.typ.kind != tyRef: + result.nilability = typeNilability(n.typ) + elif tfNotNil notin n.typ.flags: + # echo "ref key ", n, " ", n.kind + if n.kind in {nkSym, nkDotExpr} or isConstBracket(n): + let key = ctx.index(n) + result.nilability = result.map[key] + elif n.kind == nkBracketExpr: + # sometimes false positive + result.nilability = MaybeNil + else: + # sometimes maybe false positive + result.nilability = MaybeNil + +proc checkDotExpr(n, ctx, map): Check = + ## check dot expressions: make sure we can dereference the base + result = check(n[0], ctx, map) + result = checkRefExpr(n, ctx, result) + +proc checkBracketExpr(n, ctx, map): Check = + ## check bracket expressions: make sure we can dereference the base + result = check(n[0], ctx, map) + # if might be deref: [] == *(a + index) for cstring + handleNilability(result, n[0], ctx, map) + result = check(n[1], ctx, result.map) + result = checkRefExpr(n, ctx, result) + # echo n, " ", result.nilability + + +template union(l: Nilability, r: Nilability): Nilability = + ## unify two states + if l == r: + l + else: + MaybeNil + +template add(l: Nilability, r: Nilability): Nilability = + if l == r: # Safe Safe -> Safe etc + l + elif l == Parent: # Parent Safe -> Safe etc + r + elif r == Parent: # Safe Parent -> Safe etc + l + elif l == Unreachable or r == Unreachable: # Safe Unreachable -> Unreachable etc + Unreachable + elif l == MaybeNil: # Safe MaybeNil -> Safe etc + r + elif r == MaybeNil: # MaybeNil Nil -> Nil etc + l + else: # Safe Nil -> Unreachable etc + Unreachable + +proc findCommonParent(l: NilMap, r: NilMap): NilMap = + result = l.parent + while not result.isNil: + var rparent = r.parent + while not rparent.isNil: + if result == rparent: + return result + rparent = rparent.parent + result = result.parent + +proc union(ctx: NilCheckerContext, l: NilMap, r: NilMap): NilMap = + ## unify two maps from different branches + ## combine their locals + ## what if they are from different parts of the same tree + ## e.g. + ## a -> b -> c + ## -> b1 + ## common then? + ## + if l.isNil: + return r + elif r.isNil: + return l + + let common = findCommonParent(l, r) + result = newNilMap(common, ctx.expressions.len.int) + + for index, value in l: + let h = history(r, index) + let info = if h.len > 0: h[^1].info else: TLineInfo(line: 0) # assert h.len > 0 + # echo "history", name, value, r[name], h[^1].info.line + result.store(ctx, index, union(value, r[index]), TAssign, info) + +proc add(ctx: NilCheckerContext, l: NilMap, r: NilMap): NilMap = + #echo "add " + #echo namedMapDebugInfo(ctx, l) + #echo " : " + #echo namedMapDebugInfo(ctx, r) + if l.isNil: + return r + elif r.isNil: + return l + + let common = findCommonParent(l, r) + result = newNilMap(common, ctx.expressions.len.int) + + for index, value in l: + let h = history(r, index) + let info = if h.len > 0: h[^1].info else: TLineInfo(line: 0) + # TODO: refactor and also think: is TAssign a good one + result.store(ctx, index, add(value, r[index]), TAssign, info) + + #echo "result" + #echo namedMapDebugInfo(ctx, result) + #echo "" + #echo "" + + +proc checkAsgn(target: PNode, assigned: PNode; ctx, map): Check = + ## check assignment + ## update map based on `assigned` + if assigned.kind != nkEmpty: + result = check(assigned, ctx, map) + else: + result = Check(nilability: typeNilability(target.typ), map: map) + + # we need to visit and check those, but we don't use the result for now + # is it possible to somehow have another event happen here? + discard check(target, ctx, map) + + if result.map.isNil: + result.map = map + if target.kind in {nkSym, nkDotExpr} or isConstBracket(target): + let t = ctx.index(target) + move(ctx, map, target, assigned) + case assigned.kind: + of nkNilLit: + result.map.store(ctx, t, Nil, TAssign, target.info, target) + else: + result.map.store(ctx, t, result.nilability, TAssign, target.info, target) + moveOutDependants(ctx, map, target) + storeDependants(ctx, map, target, MaybeNil) + if assigned.kind in {nkObjConstr, nkTupleConstr}: + for (element, value) in result.elements: + var elementNode = nkDotExpr.newTree(nkHiddenDeref.newTree(target), element) + if symbol(elementNode) in ctx.symbolIndices: + var elementIndex = ctx.index(elementNode) + result.map.store(ctx, elementIndex, value, TAssign, target.info, elementNode) + + +proc checkReturn(n, ctx, map): Check = + ## check return + # return n same as result = n; return ? + result = check(n[0], ctx, map) + result.map.store(ctx, resultExprIndex, result.nilability, TAssign, n.info) + + +proc checkIf(n, ctx, map): Check = + ## check branches based on condition + var mapIf: NilMap = map + + # first visit the condition + + # the structure is not If(Elif(Elif, Else), Else) + # it is + # If(Elif, Elif, Else) + + var mapCondition = checkCondition(n.sons[0].sons[0], ctx, mapIf, false, true) + + # the state of the conditions: negating conditions before the current one + var layerHistory = newNilMap(mapIf) + # the state after branch effects + var afterLayer: NilMap + # the result nilability for expressions + var nilability = Safe + + for branch in n.sons: + var branchConditionLayer = newNilMap(layerHistory) + var branchLayer: NilMap + var code: PNode + if branch.kind in {nkIfStmt, nkElifBranch}: + var mapCondition = checkCondition(branch[0], ctx, branchConditionLayer, false, true) + let reverseMapCondition = reverseDirect(mapCondition) + layerHistory = ctx.add(layerHistory, reverseMapCondition) + branchLayer = mapCondition + code = branch[1] + else: + branchLayer = layerHistory + code = branch + + let branchCheck = checkBranch(code, ctx, branchLayer) + # handles nil afterLayer -> returns branchCheck.map + afterLayer = ctx.union(afterLayer, branchCheck.map) + nilability = if n.kind == nkIfStmt: Safe else: union(nilability, branchCheck.nilability) + if n.sons.len > 1: + result.map = afterLayer + result.nilability = nilability + else: + if not hasUnstructuredControlFlowJump(n[0][1]): + # here it matters what happend inside, because + # we might continue in the parent branch after entering this one + # either we enter the branch, so we get mapIf and effect of branch -> afterLayer + # or we dont , so we get mapIf and (not condition) effect -> layerHistory + result.map = ctx.union(layerHistory, afterLayer) + result.nilability = Safe # no expr? + else: + # similar to else: because otherwise we are jumping out of + # the branch, so no union with the mapIf (we dont continue if the condition was true) + # here it also doesn't matter for the parent branch what happened in the branch, e.g. assigning to nil + # as if we continue there, we haven't entered the branch probably + # so we don't do an union with afterLayer + # layerHistory has the effect of mapIf and (not condition) + result.map = layerHistory + result.nilability = Safe + +proc checkFor(n, ctx, map): Check = + ## check for loops + ## try to repeat the unification of the code twice + ## to detect what can change after a several iterations + ## approach based on discussions with Zahary/Araq + ## similar approach used for other loops + var m = map.copyMap() + var map0 = map.copyMap() + #echo namedMapDebugInfo(ctx, map) + m = check(n.sons[2], ctx, map).map.copyMap() + if n[0].kind == nkSym: + m.store(ctx, ctx.index(n[0]), typeNilability(n[0].typ), TAssign, n[0].info) + # echo namedMapDebugInfo(ctx, map) + var check2 = check(n.sons[2], ctx, m) + var map2 = check2.map + + result.map = ctx.union(map0, m) + result.map = ctx.union(result.map, map2) + result.nilability = Safe + +# check: +# while code: +# code2 + +# if code: +# code2 +# if code: +# code2 + +# if code: +# code2 + +# check(code), check(code2 in code's map) + +proc checkWhile(n, ctx, map): Check = + ## check while loops + ## try to repeat the unification of the code twice + var m = checkCondition(n[0], ctx, map, false, false) + var map0 = map.copyMap() + m = check(n.sons[1], ctx, m).map + var map1 = m.copyMap() + var check2 = check(n.sons[1], ctx, m) + var map2 = check2.map + + result.map = ctx.union(map0, map1) + result.map = ctx.union(result.map, map2) + result.nilability = Safe + +proc checkInfix(n, ctx, map): Check = + ## check infix operators in condition + ## a and b : map is based on a; next b + ## a or b : map is an union of a and b's + ## a == b : use checkCondition + ## else: no change, just check args + if n[0].kind == nkSym: + var mapL: NilMap + var mapR: NilMap + if n[0].sym.magic notin {mAnd, mEqRef}: + mapL = checkCondition(n[1], ctx, map, false, false) + mapR = checkCondition(n[2], ctx, map, false, false) + case n[0].sym.magic: + of mOr: + result.map = ctx.union(mapL, mapR) + of mAnd: + result.map = checkCondition(n[1], ctx, map, false, false) + result.map = checkCondition(n[2], ctx, result.map, false, false) + of mEqRef: + if n[2].kind == nkIntLit: + if $n[2] == "true": + result.map = checkCondition(n[1], ctx, map, false, false) + elif $n[2] == "false": + result.map = checkCondition(n[1], ctx, map, true, false) + elif n[1].kind == nkIntLit: + if $n[1] == "true": + result.map = checkCondition(n[2], ctx, map, false, false) + elif $n[1] == "false": + result.map = checkCondition(n[2], ctx, map, true, false) + + if result.map.isNil: + result.map = map + else: + result.map = map + else: + result.map = map + result.nilability = Safe + +proc checkIsNil(n, ctx, map; isElse: bool = false): Check = + ## check isNil calls + ## update the map depending on if it is not isNil or isNil + result.map = newNilMap(map) + let value = n[1] + result.map.store(ctx, ctx.index(n[1]), if not isElse: Nil else: Safe, TArg, n.info, n) + +proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode = + var name = case magic: + of mEqRef: "==" + of mAnd: "and" + of mOr: "or" + else: "" + + var cache = newIdentCache() + var op = newSym(skVar, cache.getIdent(name), nextSymId ctx.idgen, nil, r.info) + + op.magic = magic + result = nkInfix.newTree( + newSymNode(op, r.info), + l, + r) + result.typ = newType(tyBool, nextTypeId ctx.idgen, nil) + +proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode = + var cache = newIdentCache() + var op = newSym(skVar, cache.getIdent("not"), nextSymId ctx.idgen, nil, node.info) + + op.magic = mNot + result = nkPrefix.newTree( + newSymNode(op, node.info), + node) + result.typ = newType(tyBool, nextTypeId ctx.idgen, nil) + +proc infixEq(ctx: NilCheckerContext, l: PNode, r: PNode): PNode = + infix(ctx, l, r, mEqRef) + +proc infixOr(ctx: NilCheckerContext, l: PNode, r: PNode): PNode = + infix(ctx, l, r, mOr) + +proc checkCase(n, ctx, map): Check = + # case a: + # of b: c + # of b2: c2 + # is like + # if a == b: + # c + # elif a == b2: + # c2 + # also a == true is a , a == false is not a + let base = n[0] + result.map = map.copyMap() + result.nilability = Safe + var a: PNode + for child in n: + case child.kind: + of nkOfBranch: + if child.len < 2: + # echo "case with of with < 2 ", n + continue # TODO why does this happen + let branchBase = child[0] # TODO a, b or a, b..c etc + let code = child[^1] + let test = infixEq(ctx, base, branchBase) + if a.isNil: + a = test + else: + a = infixOr(ctx, a, test) + let conditionMap = checkCondition(test, ctx, map.copyMap(), false, false) + let newCheck = checkBranch(code, ctx, conditionMap) + result.map = ctx.union(result.map, newCheck.map) + result.nilability = union(result.nilability, newCheck.nilability) + of nkElifBranch: + discard "TODO: maybe adapt to be similar to checkIf" + of nkElse: + let mapElse = checkCondition(prefixNot(ctx, a), ctx, map.copyMap(), false, false) + let newCheck = checkBranch(child[0], ctx, mapElse) + result.map = ctx.union(result.map, newCheck.map) + result.nilability = union(result.nilability, newCheck.nilability) + else: + discard + +# notes +# try: +# a +# b +# except: +# c +# finally: +# d +# +# if a doesnt raise, this is not an exit point: +# so find what raises and update the map with that +# (a, b); c; d +# if nothing raises, except shouldn't happen +# .. might be a false positive tho, if canRaise is not conservative? +# so don't visit it +# +# nested nodes can raise as well: I hope nim returns canRaise for +# their parents +# +# a lot of stuff can raise +proc checkTry(n, ctx, map): Check = + var newMap = map.copyMap() + var currentMap = map + # we don't analyze except if nothing canRaise in try + var canRaise = false + var hasFinally = false + # var tryNodes: seq[PNode] + # if n[0].kind == nkStmtList: + # tryNodes = toSeq(n[0]) + # else: + # tryNodes = @[n[0]] + # for i, child in tryNodes: + # let (childNilability, childMap) = check(child, conf, currentMap) + # echo childMap + # currentMap = childMap + # # TODO what about nested + # if child.canRaise: + # newMap = union(newMap, childMap) + # canRaise = true + # else: + # newMap = childMap + let tryCheck = check(n[0], ctx, currentMap) + newMap = ctx.union(currentMap, tryCheck.map) + canRaise = n[0].canRaise + + var afterTryMap = newMap + for a, branch in n: + if a > 0: + case branch.kind: + of nkFinally: + newMap = ctx.union(afterTryMap, newMap) + let childCheck = check(branch[0], ctx, newMap) + newMap = ctx.union(newMap, childCheck.map) + hasFinally = true + of nkExceptBranch: + if canRaise: + let childCheck = check(branch[^1], ctx, newMap) + newMap = ctx.union(newMap, childCheck.map) + else: + discard + if not hasFinally: + # we might have not hit the except branches + newMap = ctx.union(afterTryMap, newMap) + result = Check(nilability: Safe, map: newMap) + +proc hasUnstructuredControlFlowJump(n: PNode): bool = + ## if the node contains a direct stop + ## as a continue/break/raise/return: then it means + ## we should reverse some of the map in the code after the condition + ## similar to else + # echo "n ", n, " ", n.kind + case n.kind: + of nkStmtList: + for child in n: + if hasUnstructuredControlFlowJump(child): + return true + of nkReturnStmt, nkBreakStmt, nkContinueStmt, nkRaiseStmt: + return true + of nkIfStmt, nkIfExpr, nkElifExpr, nkElse: + return false + else: + discard + return false + +proc reverse(value: Nilability): Nilability = + case value: + of Nil: Safe + of MaybeNil: MaybeNil + of Safe: Nil + of Parent: Parent + of Unreachable: Unreachable + +proc reverse(kind: TransitionKind): TransitionKind = + case kind: + of TNil: TSafe + of TSafe: TNil + of TPotentialAlias: TPotentialAlias + else: + kind + # raise newException(ValueError, "expected TNil or TSafe") + +proc reverseDirect(map: NilMap): NilMap = + # we create a new layer + # reverse the values only in this layer: + # because conditions should've stored their changes there + # b: Safe (not b.isNil) + # b: Parent Parent + # b: Nil (b.isNil) + + # layer block + # [ Parent ] [ Parent ] + # if -> if state + # layer -> reverse + # older older0 new + # older new + # [ b Nil ] [ Parent ] + # elif + # [ b Nil, c Nil] [ Parent ] + # + + # if b.isNil: + # # [ b Safe] + # c = A() # Safe + # elif not b.isNil: + # # [ b Safe ] + [b Nil] MaybeNil Unreachable + # # Unreachable defer can't deref b, it is unreachable + # discard + # else: + # b + + +# if + + + + # if: we just pass the map with a new layer for its block + # elif: we just pass the original map but with a new layer is the reverse of the previous popped layer (?) + # elif: + # else: we just pass the original map but with a new layer which is initialized as the reverse of the + # top layer of else + # else: + # + # [ b MaybeNil ] [b Parent] [b Parent] [b Safe] [b Nil] [] + # Safe + # c == 1 + # b Parent + # c == 2 + # b Parent + # not b.isNil + # b Safe + # c == 3 + # b Nil + # (else) + # b Nil + + result = map.copyMap() + for index, value in result.expressions: + result.expressions[index] = reverse(value) + if result.history[index].len > 0: + result.history[index][^1].kind = reverse(result.history[index][^1].kind) + result.history[index][^1].nilability = result.expressions[index] + +proc checkCondition(n, ctx, map; reverse: bool, base: bool): NilMap = + ## check conditions : used for if, some infix operators + ## isNil(a) + ## it returns a new map: you need to reverse all the direct elements for else + + # echo "condition ", n, " ", n.kind + if n.kind == nkCall: + result = newNilMap(map) + for element in n: + if element.kind == nkHiddenDeref and n[0].kind == nkSym and n[0].sym.magic == mIsNil: + result = check(element[0], ctx, result).map + else: + result = check(element, ctx, result).map + + if n[0].kind == nkSym and n[0].sym.magic == mIsNil: + # isNil(arg) + var arg = n[1] + while arg.kind == nkHiddenDeref: + arg = arg[0] + if arg.kind in {nkSym, nkDotExpr} or isConstBracket(arg): + let a = ctx.index(arg) + result.store(ctx, a, if not reverse: Nil else: Safe, if not reverse: TNil else: TSafe, n.info, arg) + else: + discard + else: + discard + elif n.kind == nkPrefix and n[0].kind == nkSym and n[0].sym.magic == mNot: + result = checkCondition(n[1], ctx, map, not reverse, false) + elif n.kind == nkInfix: + result = newNilMap(map) + result = checkInfix(n, ctx, result).map + else: + result = check(n, ctx, map).map + result = newNilMap(map) + assert not result.isNil + assert not result.parent.isNil + +proc checkResult(n, ctx, map) = + let resultNilability = map[resultExprIndex] + case resultNilability: + of Nil: + message(ctx.config, n.info, warnStrictNotNil, "return value is nil") + of MaybeNil: + message(ctx.config, n.info, warnStrictNotNil, "return value might be nil") + of Unreachable: + message(ctx.config, n.info, warnStrictNotNil, "return value is unreachable") + of Safe, Parent: + discard + +proc checkBranch(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = + result = check(n, ctx, map) + + +# Faith! + +proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = + assert not map.isNil + + # echo "check n ", n, " ", n.kind + # echo "map ", namedMapDebugInfo(ctx, map) + case n.kind: + of nkSym: + result = Check(nilability: map[ctx.index(n)], map: map) + of nkCallKinds: + if n.sons[0].kind == nkSym: + let callSym = n.sons[0].sym + case callSym.magic: + of mAnd, mOr: + result = checkInfix(n, ctx, map) + of mIsNil: + result = checkIsNil(n, ctx, map) + else: + result = checkCall(n, ctx, map) + else: + result = checkCall(n, ctx, map) + of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkExprColonExpr, nkExprEqExpr, + nkCast: + result = check(n.sons[1], ctx, map) + of nkStmtList, nkStmtListExpr, nkChckRangeF, nkChckRange64, nkChckRange, + nkBracket, nkCurly, nkPar, nkTupleConstr, nkClosure, nkObjConstr, nkElse: + result.map = map + if n.kind in {nkObjConstr, nkTupleConstr}: + # TODO deeper nested elements? + # A(field: B()) # + # field: Safe -> + var elements: seq[(PNode, Nilability)] + for i, child in n: + result = check(child, ctx, result.map) + if i > 0: + if child.kind == nkExprColonExpr: + elements.add((child[0], result.nilability)) + result.elements = elements + result.nilability = Safe + else: + for child in n: + result = check(child, ctx, result.map) + + of nkDotExpr: + result = checkDotExpr(n, ctx, map) + of nkDerefExpr, nkHiddenDeref: + result = checkDeref(n, ctx, map) + of nkAddr, nkHiddenAddr: + result = check(n.sons[0], ctx, map) + of nkIfStmt, nkIfExpr: + result = checkIf(n, ctx, map) + of nkAsgn: + result = checkAsgn(n[0], n[1], ctx, map) + of nkVarSection: + result.map = map + for child in n: + result = checkAsgn(child[0], child[2], ctx, result.map) + of nkForStmt: + result = checkFor(n, ctx, map) + of nkCaseStmt: + result = checkCase(n, ctx, map) + of nkReturnStmt: + result = checkReturn(n, ctx, map) + of nkBracketExpr: + result = checkBracketExpr(n, ctx, map) + of nkTryStmt: + result = checkTry(n, ctx, map) + of nkWhileStmt: + result = checkWhile(n, ctx, map) + of 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: + + discard "don't follow this : same as varpartitions" + result = Check(nilability: Nil, map: map) + else: + + var elementMap = map.copyMap() + var elementCheck: Check + elementCheck.map = elementMap + for element in n: + elementCheck = check(element, ctx, elementCheck.map) + + result = Check(nilability: Nil, map: elementCheck.map) + + + + +proc typeNilability(typ: PType): Nilability = + assert not typ.isNil + # echo "typeNilability ", $typ.flags, " ", $typ.kind + result = if tfNotNil in typ.flags: + Safe + elif typ.kind in {tyRef, tyCString, tyPtr, tyPointer}: + # + # tyVar ? tyVarargs ? tySink ? tyLent ? + # TODO spec? tests? + MaybeNil + else: + Safe + # echo " result ", result + +proc preVisitNode(ctx: NilCheckerContext, node: PNode, conf: ConfigRef) = + # echo "visit node ", node + if node.kind in {nkSym, nkDotExpr} or isConstBracket(node): + let nodeSymbol = symbol(node) + if not ctx.symbolIndices.hasKey(nodeSymbol): + ctx.symbolIndices[nodeSymbol] = ctx.expressions.len + ctx.expressions.add(node) + if node.kind in {nkDotExpr, nkBracketExpr}: + if node.kind == nkDotExpr and (not node.typ.isNil and node.typ.kind == tyRef and tfNotNil notin node.typ.flags) or + node.kind == nkBracketExpr: + let index = ctx.symbolIndices[nodeSymbol] + var baseIndex = noExprIndex + # deref usually? + # ok, we hit another case + var base = if node[0].kind notin {nkSym, nkIdent}: node[0][0] else: node[0] + if base.kind != nkIdent: + let baseSymbol = symbol(base) + if not ctx.symbolIndices.hasKey(baseSymbol): + baseIndex = ctx.expressions.len # next visit should add it + else: + baseIndex = ctx.symbolIndices[baseSymbol] + if ctx.dependants.len <= baseIndex: + ctx.dependants.setLen(baseIndex + 1.ExprIndex) + ctx.dependants[baseIndex].incl(index.int) + case node.kind: + of nkSym, nkEmpty, nkNilLit, nkType, nkIdent, nkCharLit .. nkUInt64Lit, nkFloatLit .. nkFloat64Lit, nkStrLit .. nkTripleStrLit: + discard + of nkDotExpr: + # visit only the base + ctx.preVisitNode(node[0], conf) + else: + for element in node: + ctx.preVisitNode(element, conf) + +proc preVisit(ctx: NilCheckerContext, s: PSym, body: PNode, conf: ConfigRef) = + ctx.symbolIndices = {resultId: resultExprIndex}.toTable() + var cache = newIdentCache() + ctx.expressions = SeqOfDistinct[ExprIndex, PNode](@[newIdentNode(cache.getIdent("result"), s.ast.info)]) + var emptySet: IntSet # set[ExprIndex] + ctx.dependants = SeqOfDistinct[ExprIndex, IntSet](@[emptySet]) + for i, arg in s.typ.n.sons: + if i > 0: + if arg.kind != nkSym: + continue + let argSymbol = symbol(arg) + if not ctx.symbolIndices.hasKey(argSymbol): + ctx.symbolIndices[argSymbol] = ctx.expressions.len + ctx.expressions.add(arg) + ctx.preVisitNode(body, conf) + if ctx.dependants.len < ctx.expressions.len: + ctx.dependants.setLen(ctx.expressions.len) + # echo ctx.symbolIndices + # echo ctx.expressions + # echo ctx.dependants + +proc checkNil*(s: PSym; body: PNode; conf: ConfigRef, idgen: IdGenerator) = + let line = s.ast.info.line + let fileIndex = s.ast.info.fileIndex.int + var filename = conf.m.fileInfos[fileIndex].fullPath.string + + var context = NilCheckerContext(config: conf, idgen: idgen) + context.preVisit(s, body, conf) + var map = newNilMap(nil, context.symbolIndices.len) + + for i, child in s.typ.n.sons: + if i > 0: + if child.kind != nkSym: + continue + map.store(context, context.index(child), typeNilability(child.typ), TArg, child.info, child) + + map.store(context, resultExprIndex, if not s.typ[0].isNil and s.typ[0].kind == tyRef: Nil else: Safe, TResult, s.ast.info) + + # echo "checking ", s.name.s, " ", filename + + let res = check(body, context, map) + var canCheck = resultExprIndex in res.map.history.low .. res.map.history.high + if res.nilability == Safe and canCheck and res.map.history[resultExprIndex].len <= 1: + res.map.store(context, resultExprIndex, Safe, TAssign, s.ast.info) + else: + if res.nilability == Safe: + res.map.store(context, resultExprIndex, Safe, TAssign, s.ast.info) + + # TODO check for nilability result + # (ANotNil, BNotNil) : + # do we check on asgn nilability at all? + + if not s.typ[0].isNil and s.typ[0].kind == tyRef and tfNotNil in s.typ[0].flags: + checkResult(s.ast, context, res.map) diff --git a/compiler/nim.cfg b/compiler/nim.cfg index cb586a9cb0..40e93d523c 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -4,10 +4,8 @@ hint[XDeclaredButNotUsed]:off define:booting define:nimcore -#define:nimIncremental -#import:"$projectpath/testability" -#define:staticSqlite +#import:"$projectpath/testability" @if windows: cincludes: "$lib/wrappers/libffi/common" diff --git a/compiler/nim.nim b/compiler/nim.nim index 46654e352f..df06a83a9b 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -95,9 +95,15 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = var cmdPrefix = "" case conf.backend of backendC, backendCpp, backendObjc: discard - of backendJs: cmdPrefix = findNodeJs() & " " + of backendJs: + # D20210217T215950:here this flag is needed for node < v15.0.0, otherwise + # tasyncjs_fail` would fail, refs https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode + cmdPrefix = findNodeJs() & " --unhandled-rejections=strict " else: doAssert false, $conf.backend + # No space before command otherwise on windows you'd get a cryptic: + # `The parameter is incorrect` execExternalProgram(conf, cmdPrefix & output.quoteShell & ' ' & conf.arguments) + # execExternalProgram(conf, cmdPrefix & ' ' & output.quoteShell & ' ' & conf.arguments) of cmdDocLike, cmdRst2html, cmdRst2tex: # bugfix(cmdRst2tex was missing) if conf.arguments.len > 0: # reserved for future use @@ -110,7 +116,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = when declared(GC_setMaxPause): GC_setMaxPause 2_000 -when compileOption("gc", "v2") or compileOption("gc", "refc"): +when compileOption("gc", "refc"): # the new correct mark&sweet collector is too slow :-/ GC_disableMarkAndSweep() diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 01a79c1e36..1691e7ccfc 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -281,6 +281,8 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: if optSkipProjConfigFile notin conf.globalOptions: readConfigFile(pd / cfg) + if cfg == DefaultConfig: + runNimScriptIfExists(pd / DefaultConfigNims) if conf.projectName.len != 0: # new project wide config file: @@ -289,8 +291,6 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: projectConfig = changeFileExt(conf.projectFull, "nim.cfg") readConfigFile(projectConfig) - if cfg == DefaultConfig: - runNimScriptIfExists(pd / DefaultConfigNims) let scriptFile = conf.projectFull.changeFileExt("nims") let scriptIsProj = scriptFile == conf.projectFull diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index b931298527..9be595ccec 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -12,7 +12,7 @@ import ast, astalgo, modules, passes, condsyms, options, sem, llstream, lineinfos, vm, vmdef, modulegraphs, idents, os, pathutils, - passaux, scriptconfig + passaux, scriptconfig, std/compilesettings type Interpreter* = ref object ## Use Nim as an interpreter with this object @@ -24,11 +24,8 @@ type iterator exportedSymbols*(i: Interpreter): PSym = assert i != nil assert i.mainModule != nil, "no main module selected" - var it: TTabIter - var s = initTabIter(it, i.mainModule.tab) - while s != nil: + for s in modulegraphs.allSyms(i.graph, i.mainModule): yield s - s = nextIter(it, i.mainModule.tab) proc selectUniqueSymbol*(i: Interpreter; name: string; symKinds: set[TSymKind] = {skLet, skVar}): PSym = @@ -37,14 +34,14 @@ proc selectUniqueSymbol*(i: Interpreter; name: string; assert i != nil assert i.mainModule != nil, "no main module selected" let n = getIdent(i.graph.cache, name) - var it: TIdentIter - var s = initIdentIter(it, i.mainModule.tab, n) + var it: ModuleIter + var s = initModuleIter(it, i.graph, i.mainModule, n) result = nil while s != nil: if s.kind in symKinds: if result == nil: result = s else: return nil # ambiguous - s = nextIdentIter(it, i.mainModule.tab) + s = nextModuleIter(it, i.graph) proc selectRoutine*(i: Interpreter; name: string): PSym = ## Selects a declared routine (proc/func/etc) from the main module. @@ -70,7 +67,7 @@ proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) = ## This can also be used to *reload* the script. assert i != nil assert i.mainModule != nil, "no main module selected" - initStrTable(i.mainModule.tab) + initStrTable(i.mainModule.semtab(i.graph)) i.mainModule.ast = nil let s = if scriptStream != nil: scriptStream @@ -95,10 +92,9 @@ proc findNimStdLib*(): string = return "" proc findNimStdLibCompileTime*(): string = - ## Same as ``findNimStdLib`` but uses source files used at compile time, + ## Same as `findNimStdLib` but uses source files used at compile time, ## and asserts on error. - const exe = getCurrentCompilerExe() - result = exe.splitFile.dir.parentDir / "lib" + result = querySetting(libPath) doAssert fileExists(result / "system.nim"), "result:" & result proc createInterpreter*(scriptName: string; diff --git a/compiler/nimfix/nimfix.nim b/compiler/nimfix/nimfix.nim index 4d93279c99..30c138f793 100644 --- a/compiler/nimfix/nimfix.nim +++ b/compiler/nimfix/nimfix.nim @@ -103,7 +103,7 @@ proc handleCmdLine(config: ConfigRef) = processCmdLine(passCmd2, "", config) mainCommand() -when compileOption("gc", "v2") or compileOption("gc", "refc"): +when compileOption("gc", "refc"): GC_disableMarkAndSweep() condsyms.initDefines() diff --git a/compiler/nimpaths.nim b/compiler/nimpaths.nim index 7b2216080b..71bb9a7d7a 100644 --- a/compiler/nimpaths.nim +++ b/compiler/nimpaths.nim @@ -3,7 +3,8 @@ Represents absolute paths, but using a symbolic variables (eg $nimr) which can b resolved at runtime; this avoids hardcoding at compile time absolute paths so that the project root can be relocated. -xxx consider some refactoring with $nim/testament/lib/stdtest/specialpaths.nim; +xxx factor pending https://github.com/timotheecour/Nim/issues/616, see also +$nim/testament/lib/stdtest/specialpaths.nim specialpaths is simpler because it doesn't need variables to be relocatable at runtime (eg for use in testament) diff --git a/compiler/optimizer.nim b/compiler/optimizer.nim index 5d1139bfdb..744c82ab50 100644 --- a/compiler/optimizer.nim +++ b/compiler/optimizer.nim @@ -150,7 +150,8 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) = of 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: + nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, + nkTypeOfExpr, nkMixinStmt, nkBindStmt: discard "do not follow the construct" of nkAsgn, nkFastAsgn: @@ -249,7 +250,8 @@ proc opt(c: Con; n, parent: PNode; parentPos: int) = of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, - nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr: + nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr, + nkMixinStmt, nkBindStmt: parent[parentPos] = n else: diff --git a/compiler/options.nim b/compiler/options.nim index 73c4c627df..a2d6a51b36 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -19,7 +19,7 @@ const useEffectSystem* = true useWriteTracking* = false hasFFI* = defined(nimHasLibFFI) - copyrightYear* = "2020" + copyrightYear* = "2021" type # please make sure we have under 32 options # (improves code efficiency a lot!) @@ -39,7 +39,6 @@ type # please make sure we have under 32 options # evaluation optTrMacros, # en/disable pattern matching optMemTracker, - optNilSeqs, optSinkInference # 'sink T' inference optCursorInference @@ -68,7 +67,6 @@ type # please make sure we have under 32 options optThreads, # support for multi-threading optStdout, # output to stdout optThreadAnalysis, # thread analysis pass - optTaintMode, # taint mode turned on optTlsEmulation, # thread var emulation turned on optGenIndex # generate index file for documentation; optEmbedOrigSrc # embed the original source in the generated code @@ -103,8 +101,23 @@ type # please make sure we have under 32 options TGlobalOptions* = set[TGlobalOption] const - harmlessOptions* = {optForceFullMake, optNoLinking, optRun, - optUseColors, optStdout} + harmlessOptions* = {optForceFullMake, optNoLinking, optRun, optUseColors, optStdout} + genSubDir* = RelativeDir"nimcache" + NimExt* = "nim" + RodExt* = "rod" + HtmlExt* = "html" + JsonExt* = "json" + TagsExt* = "tags" + TexExt* = "tex" + IniExt* = "ini" + DefaultConfig* = RelativeFile"nim.cfg" + DefaultConfigNims* = RelativeFile"config.nims" + DocConfig* = RelativeFile"nimdoc.cfg" + DocTexConfig* = RelativeFile"nimdoc.tex.cfg" + htmldocsDir* = htmldocsDirname.RelativeDir + docRootDefault* = "@default" # using `@` instead of `$` to avoid shell quoting complications + oKeepVariableNames* = true + spellSuggestSecretSauce* = -1 type TBackend* = enum @@ -124,7 +137,7 @@ type cmdTcc # run the project via TCC backend cmdCheck # semantic checking for whole project cmdParse # parse a single file (for debugging) - cmdScan # scan a single file (for debugging) + cmdRod # .rod to some text representation (for debugging) cmdIdeTools # ide tools (e.g. nimsuggest) cmdNimscript # evaluate nimscript cmdDoc0 @@ -176,7 +189,8 @@ type ## Note: this feature can't be localized with {.push.} vmopsDanger, strictFuncs, - views + views, + strictNotNil LegacyFeature* = enum allowSemcheckedAstModification, @@ -189,7 +203,7 @@ type ## are not anymore. SymbolFilesOption* = enum - disabledSf, writeOnlySf, readOnlySf, v2Sf + disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest TSystemCC* = enum ccNone, ccGcc, ccNintendoSwitch, ccLLVM_Gcc, ccCLang, ccBcc, ccVcc, @@ -269,6 +283,7 @@ type numberOfProcessors*: int # number of processors lastCmdTime*: float # when caas is enabled, we measure each command symbolFiles*: SymbolFilesOption + spellSuggestMax*: int # max number of spelling suggestions for typos cppDefines*: HashSet[string] # (*) headerFile*: string @@ -367,8 +382,11 @@ proc setNote*(conf: ConfigRef, note: TNoteKind, enabled = true) = if enabled: incl(conf.notes, note) else: excl(conf.notes, note) proc hasHint*(conf: ConfigRef, note: TNoteKind): bool = + # ternary states instead of binary states would simplify logic if optHints notin conf.options: false - elif note in {hintConf}: # could add here other special notes like hintSource + elif note in {hintConf, hintProcessing}: + # could add here other special notes like hintSource + # these notes apply globally. note in conf.mainPackageNotes else: note in conf.notes @@ -377,11 +395,12 @@ proc hasWarn*(conf: ConfigRef, note: TNoteKind): bool = proc hcrOn*(conf: ConfigRef): bool = return optHotCodeReloading in conf.globalOptions -template depConfigFields*(fn) {.dirty.} = - fn(target) - fn(options) - fn(globalOptions) - fn(selectedGC) +when false: + template depConfigFields*(fn) {.dirty.} = # deadcode + fn(target) + fn(options) + fn(globalOptions) + fn(selectedGC) const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel} @@ -424,6 +443,9 @@ template newPackageCache*(): untyped = proc newProfileData(): ProfileData = ProfileData(data: newTable[TLineInfo, ProfileInfo]()) +const foreignPackageNotesDefault* = { + hintProcessing, warnUnknownMagic, hintQuitCalled, hintExecuting, hintUser, warnUser} + proc newConfigRef*(): ConfigRef = result = ConfigRef( selectedGC: gcRefc, @@ -435,8 +457,7 @@ proc newConfigRef*(): ConfigRef = arcToExpand: newStringTable(modeStyleInsensitive), m: initMsgConfig(), cppDefines: initHashSet[string](), - headerFile: "", features: {}, legacyFeatures: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic, - hintQuitCalled, hintExecuting}, + headerFile: "", features: {}, legacyFeatures: {}, foreignPackageNotes: foreignPackageNotesDefault, notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1], configVars: newStringTable(modeStyleInsensitive), symbols: newStringTable(modeStyleInsensitive), @@ -477,6 +498,7 @@ proc newConfigRef*(): ConfigRef = suggestMaxResults: 10_000, maxLoopIterationsVM: 10_000_000, vmProfileData: newProfileData(), + spellSuggestMax: spellSuggestSecretSauce, ) setTargetFromSystem(result.target) # enable colors by default on terminals @@ -490,8 +512,7 @@ proc newPartialConfigRef*(): ConfigRef = verbosity: 1, options: DefaultOptions, globalOptions: DefaultGlobalOptions, - foreignPackageNotes: {hintProcessing, warnUnknownMagic, - hintQuitCalled, hintExecuting}, + foreignPackageNotes: foreignPackageNotesDefault, notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1]) proc cppDefine*(c: ConfigRef; define: string) = @@ -555,23 +576,6 @@ template compilationCachePresent*(conf: ConfigRef): untyped = template optPreserveOrigSource*(conf: ConfigRef): untyped = optEmbedOrigSrc in conf.globalOptions -const - genSubDir* = RelativeDir"nimcache" - NimExt* = "nim" - RodExt* = "rod" - HtmlExt* = "html" - JsonExt* = "json" - TagsExt* = "tags" - TexExt* = "tex" - IniExt* = "ini" - DefaultConfig* = RelativeFile"nim.cfg" - DefaultConfigNims* = RelativeFile"config.nims" - DocConfig* = RelativeFile"nimdoc.cfg" - DocTexConfig* = RelativeFile"nimdoc.tex.cfg" - htmldocsDir* = htmldocsDirname.RelativeDir - docRootDefault* = "@default" # using `@` instead of `$` to avoid shell quoting complications - oKeepVariableNames* = true - proc mainCommandArg*(conf: ConfigRef): string = ## This is intended for commands like check or parse ## which will work on the main project file unless @@ -718,6 +722,10 @@ proc completeGeneratedFilePath*(conf: ConfigRef; f: AbsoluteFile, result = subdir / RelativeFile f.string.splitPath.tail #echo "completeGeneratedFilePath(", f, ") = ", result +proc toRodFile*(conf: ConfigRef; f: AbsoluteFile; ext = RodExt): AbsoluteFile = + result = changeFileExt(completeGeneratedFilePath(conf, + withPackageName(conf, f)), ext) + proc rawFindFile(conf: ConfigRef; f: RelativeFile; suppressStdlib: bool): AbsoluteFile = for it in conf.searchPaths: if suppressStdlib and it.string.startsWith(conf.libpath.string): diff --git a/compiler/packagehandling.nim b/compiler/packagehandling.nim index a781f1d519..4af0c28fa9 100644 --- a/compiler/packagehandling.nim +++ b/compiler/packagehandling.nim @@ -44,7 +44,8 @@ proc fakePackageName*(conf: ConfigRef; path: AbsoluteFile): string = # in different directory get different name and they can be # placed in a directory. # foo-#head/../bar becomes @foo-@hhead@s..@sbar - result = "@m" & relativeTo(path, conf.projectPath).string.multiReplace({$os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"}) + result = "@m" & relativeTo(path, conf.projectPath).string.multiReplace( + {$os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"}) proc demanglePackageName*(path: string): string = result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@c": ":"}) diff --git a/compiler/parser.nim b/compiler/parser.nim index 01ec6fe956..fe857c81bb 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -164,8 +164,6 @@ proc validInd(p: var Parser): bool {.inline.} = proc rawSkipComment(p: var Parser, node: PNode) = if p.tok.tokType == tkComment: if node != nil: - when not defined(nimNoNilSeqs): - if node.comment == nil: node.comment = "" when defined(nimpretty): if p.tok.commentOffsetB > p.tok.commentOffsetA: node.comment.add fileSection(p.lex.config, p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB) @@ -1310,6 +1308,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode = #| | IND{=} 'of' exprList ':' stmt #| | IND{=} 'elif' expr ':' stmt #| | IND{=} 'except' exprList ':' stmt + #| | IND{=} 'finally' ':' stmt #| | IND{=} 'else' ':' stmt )* result = x if p.tok.indent >= 0: return @@ -1364,6 +1363,9 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode = of tkExcept: nextBlock = newNodeP(nkExceptBranch, p) exprList(p, tkColon, nextBlock) + of tkFinally: + nextBlock = newNodeP(nkFinally, p) + getTok(p) of tkElse: nextBlock = newNodeP(nkElse, p) getTok(p) @@ -1374,7 +1376,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode = nextBlock.flags.incl nfBlockArg result.add nextBlock - if nextBlock.kind == nkElse: break + if nextBlock.kind in {nkElse, nkFinally}: break else: if openingParams.kind != nkEmpty: parMessage(p, "expected ':'") @@ -1998,12 +2000,18 @@ proc parseTypeClass(p: var Parser): PNode = #| &IND{>} stmt result = newNodeP(nkTypeClassTy, p) getTok(p) - var args = newNodeP(nkArgList, p) - result.add(args) - args.add(p.parseTypeClassParam) - while p.tok.tokType == tkComma: - getTok(p) + if p.tok.tokType == tkComment: + skipComment(p, result) + + if p.tok.indent < 0: + var args = newNodeP(nkArgList, p) + result.add(args) args.add(p.parseTypeClassParam) + while p.tok.tokType == tkComma: + getTok(p) + args.add(p.parseTypeClassParam) + else: + result.add(p.emptyNode) # see ast.isNewStyleConcept if p.tok.tokType == tkCurlyDotLe and p.validInd: result.add(parsePragma(p)) else: diff --git a/compiler/passes.nim b/compiler/passes.nim index f266d2a6b7..11799b1222 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -13,7 +13,7 @@ import options, ast, llstream, msgs, idents, - syntaxes, modulegraphs, reorder, rod, + syntaxes, modulegraphs, reorder, lineinfos, pathutils type @@ -108,7 +108,14 @@ proc prepareConfigNotes(graph: ModuleGraph; module: PSym) = graph.config.notes = graph.config.foreignPackageNotes proc moduleHasChanged*(graph: ModuleGraph; module: PSym): bool {.inline.} = - result = module.id >= 0 or isDefined(graph.config, "nimBackendAssumesChange") + result = true + #module.id >= 0 or isDefined(graph.config, "nimBackendAssumesChange") + +proc partOfStdlib(x: PSym): bool = + var it = x.owner + while it != nil and it.kind == skPackage and it.owner != nil: + it = it.owner + result = it != nil and it.name.s == "stdlib" proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; stream: PLLStream): bool {.discardable.} = @@ -119,88 +126,65 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; s: PLLStream fileIdx = module.fileIdx prepareConfigNotes(graph, module) - if module.id < 0: - # new module caching mechanism: - for i in 0.. 0: - result = (renderNoComments notin g.flags) or - (renderDocComments in g.flags) +proc shouldRenderComment(g: TSrcGen): bool {.inline.} = + (renderNoComments notin g.flags or renderDocComments in g.flags) + +proc shouldRenderComment(g: TSrcGen, n: PNode): bool {.inline.} = + shouldRenderComment(g) and n.comment.len > 0 proc gcom(g: var TSrcGen, n: PNode) = assert(n != nil) @@ -430,7 +430,7 @@ proc lsons(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int = proc lsub(g: TSrcGen; n: PNode): int = # computes the length of a tree if isNil(n): return 0 - if n.comment.len > 0: return MaxLineLen + 1 + if shouldRenderComment(g, n): return MaxLineLen + 1 case n.kind of nkEmpty: result = 0 of nkTripleStrLit: @@ -598,7 +598,7 @@ proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0, if c: if g.tokens.len > oldLen: putWithSpace(g, separator, $separator) - if hasCom(n[i]): + if shouldRenderComment(g) and hasCom(n[i]): gcoms(g) optNL(g, ind) @@ -639,7 +639,7 @@ proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TokType, dedent(g) proc longMode(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): bool = - result = n.comment.len > 0 + result = shouldRenderComment(g, n) if not result: # check further for i in start..n.len + theEnd: @@ -820,14 +820,28 @@ proc gTypeClassTy(g: var TSrcGen, n: PNode) = dedent(g) proc gblock(g: var TSrcGen, n: PNode) = + # you shouldn't simplify it to `n.len < 2` + # because the following codes should be executed + # even when block stmt has only one child for getting + # better error messages. + if n.len == 0: + return + var c: TContext initContext(c) + if n[0].kind != nkEmpty: putWithSpace(g, tkBlock, "block") gsub(g, n[0]) else: put(g, tkBlock, "block") + + # block stmt should have two children + if n.len == 1: + return + putWithSpace(g, tkColon, ":") + if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) gcoms(g) @@ -966,7 +980,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = if isNil(n): return var a: TContext - if n.comment.len > 0: pushCom(g, n) + if shouldRenderComment(g, n): pushCom(g, n) case n.kind # atoms: of nkTripleStrLit: put(g, tkTripleStrLit, atom(g, n)) of nkEmpty: discard @@ -1129,9 +1143,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gcomma(g, n) put(g, tkParRi, ")") of nkObjDownConv, nkObjUpConv: + let typ = if (n.typ != nil) and (n.typ.sym != nil): n.typ.sym.name.s else: "" + put(g, tkParLe, typ & "(") if n.len >= 1: gsub(g, n[0]) - put(g, tkParLe, "(") - gcomma(g, n, 1) put(g, tkParRi, ")") of nkClosedSymChoice, nkOpenSymChoice: if renderIds in g.flags: @@ -1633,7 +1647,7 @@ proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string = proc `$`*(n: PNode): string = n.renderTree -proc renderModule*(n: PNode, infile, outfile: string, +proc renderModule*(n: PNode, outfile: string, renderFlags: TRenderFlags = {}; fid = FileIndex(-1); conf: ConfigRef = nil) = diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 72f8666a2e..d2b89f3921 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -105,6 +105,7 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev decl(a[1]) else: for i in 0..') - -proc encodeType(g: ModuleGraph, 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(g.config, "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.uniqueId, result) - if t.id != t.uniqueId: - result.add('+') - encodeVInt(t.id, result) - if t.n != nil: - encodeNode(g, 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 != 2: - result.add('=') - encodeVInt(t.align, result) - if t.lockLevel.ord != UnspecifiedLockLevel.ord: - result.add('\14') - encodeVInt(t.lockLevel.int16, result) - if t.paddingAtEnd != 0: - result.add('\15') - encodeVInt(t.paddingAtEnd, result) - for a in t.attachedOps: - result.add('\16') - if a == nil: - encodeVInt(-1, result) - else: - encodeVInt(a.id, result) - pushSym(w, a) - for i, s in items(t.methods): - result.add('\19') - encodeVInt(i, result) - result.add('\20') - encodeVInt(s.id, result) - pushSym(w, s) - encodeLoc(g, t.loc, result) - if t.typeInst != nil: - result.add('\21') - encodeVInt(t.typeInst.uniqueId, result) - pushType(w, t.typeInst) - for i in 0.. 100_000: - doAssert false, "loop never ends!" - if w.sstack.len > 0: - let s = w.sstack.pop() - when false: - echo "popped ", s.name.s, " ", s.id - storeSym(g, s) - elif w.tstack.len > 0: - let t = w.tstack.pop() - storeType(g, t) - when false: - echo "popped type ", typeToString(t), " ", t.uniqueId - else: - break - inc i - -proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) = - if g.config.symbolFiles == disabledSf: return - var buf = newStringOfCap(160) - encodeNode(g, module.info, n, buf) - db.exec(sql"insert into toplevelstmts(module, position, data) values (?, ?, ?)", - abs(module.id), module.offset, buf) - inc module.offset - transitiveClosure(g) - -proc recordStmt*(g: ModuleGraph; module: PSym; n: PNode) = - storeNode(g, module, n) - -proc storeFilename(g: ModuleGraph; fullpath: AbsoluteFile; fileIdx: FileIndex) = - let id = db.getValue(sql"select id from filenames where fullpath = ?", fullpath.string) - if id.len == 0: - let fullhash = hashFileCached(g.config, fileIdx, fullpath) - db.exec(sql"insert into filenames(nimid, fullpath, fullhash) values (?, ?, ?)", - int(fileIdx), fullpath.string, fullhash) - -proc storeRemaining*(g: ModuleGraph; module: PSym) = - if g.config.symbolFiles == disabledSf: return - var stillForwarded: seq[PSym] = @[] - for s in w.forwardedSyms: - if sfForward notin s.flags: - storeSym(g, s) - else: - stillForwarded.add s - swap w.forwardedSyms, stillForwarded - transitiveClosure(g) - var nimid = 0 - for x in items(g.config.m.fileInfos): - storeFilename(g, x.fullPath, FileIndex(nimid)) - inc nimid - -# ---------------- decoder ----------------------------------- - -type - BlobReader = object - s: string - pos: int - -using - b: var BlobReader - g: ModuleGraph - -proc loadSym(g; id: int, info: TLineInfo): PSym -proc loadType(g; id: int, info: TLineInfo): PType - -proc decodeLineInfo(g; b; info: var TLineInfo) = - if b.s[b.pos] == '?': - inc(b.pos) - if b.s[b.pos] == ',': info.col = -1'i16 - else: info.col = int16(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == ',': - inc(b.pos) - if b.s[b.pos] == ',': info.line = 0'u16 - else: info.line = uint16(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == ',': - inc(b.pos) - #info.fileIndex = fromDbFileId(g.incr, g.config, decodeVInt(b.s, b.pos)) - info.fileIndex = FileIndex decodeVInt(b.s, b.pos) - -proc skipNode(b) = - # ')' itself cannot be part of a string literal so that this is correct. - assert b.s[b.pos] == '(' - var par = 0 - var pos = b.pos+1 - while true: - case b.s[pos] - of ')': - if par == 0: break - dec par - of '(': inc par - else: discard - inc pos - b.pos = pos+1 # skip ')' - -proc decodeNodeLazyBody(g; b; fInfo: TLineInfo, - belongsTo: PSym): PNode = - result = nil - if b.s[b.pos] == '(': - inc(b.pos) - if b.s[b.pos] == ')': - inc(b.pos) - return # nil node - result = newNodeI(TNodeKind(decodeVInt(b.s, b.pos)), fInfo) - decodeLineInfo(g, b, result.info) - if b.s[b.pos] == '$': - inc(b.pos) - result.flags = cast[TNodeFlags](int32(decodeVInt(b.s, b.pos))) - if b.s[b.pos] == '^': - inc(b.pos) - var id = decodeVInt(b.s, b.pos) - result.typ = loadType(g, id, result.info) - case result.kind - of nkCharLit..nkUInt64Lit: - if b.s[b.pos] == '!': - inc(b.pos) - result.intVal = decodeVBiggestInt(b.s, b.pos) - of nkFloatLit..nkFloat64Lit: - if b.s[b.pos] == '!': - inc(b.pos) - var fl = decodeStr(b.s, b.pos) - result.floatVal = parseFloat(fl) - of nkStrLit..nkTripleStrLit: - if b.s[b.pos] == '!': - inc(b.pos) - result.strVal = decodeStr(b.s, b.pos) - else: - result.strVal = "" - of nkIdent: - if b.s[b.pos] == '!': - inc(b.pos) - var fl = decodeStr(b.s, b.pos) - result.ident = g.cache.getIdent(fl) - else: - internalError(g.config, result.info, "decodeNode: nkIdent") - of nkSym: - if b.s[b.pos] == '!': - inc(b.pos) - var id = decodeVInt(b.s, b.pos) - result.sym = loadSym(g, id, result.info) - else: - internalError(g.config, result.info, "decodeNode: nkSym") - else: - var i = 0 - while b.s[b.pos] != ')': - when false: - if belongsTo != nil and i == bodyPos: - addSonNilAllowed(result, nil) - belongsTo.offset = b.pos - skipNode(b) - else: - discard - addSonNilAllowed(result, decodeNodeLazyBody(g, b, result.info, nil)) - inc i - if b.s[b.pos] == ')': inc(b.pos) - else: internalError(g.config, result.info, "decodeNode: ')' missing") - else: - internalError(g.config, fInfo, "decodeNode: '(' missing " & $b.pos) - -proc decodeNode(g; b; fInfo: TLineInfo): PNode = - result = decodeNodeLazyBody(g, b, fInfo, nil) - -proc decodeLoc(g; b; loc: var TLoc, info: TLineInfo) = - if b.s[b.pos] == '<': - inc(b.pos) - if b.s[b.pos] in {'0'..'9', 'a'..'z', 'A'..'Z'}: - loc.k = TLocKind(decodeVInt(b.s, b.pos)) - else: - loc.k = low(loc.k) - if b.s[b.pos] == '*': - inc(b.pos) - loc.storage = TStorageLoc(decodeVInt(b.s, b.pos)) - else: - loc.storage = low(loc.storage) - if b.s[b.pos] == '$': - inc(b.pos) - loc.flags = cast[TLocFlags](int32(decodeVInt(b.s, b.pos))) - else: - loc.flags = {} - if b.s[b.pos] == '^': - inc(b.pos) - loc.lode = decodeNode(g, b, info) - # rrGetType(b, decodeVInt(b.s, b.pos), info) - else: - loc.lode = nil - if b.s[b.pos] == '!': - inc(b.pos) - loc.r = rope(decodeStr(b.s, b.pos)) - else: - loc.r = nil - if b.s[b.pos] == '>': inc(b.pos) - else: internalError(g.config, info, "decodeLoc " & b.s[b.pos]) - -proc loadBlob(g; query: SqlQuery; id: int): BlobReader = - let blob = db.getValue(query, id) - if blob.len == 0: - internalError(g.config, "symbolfiles: cannot find ID " & $ id) - result = BlobReader(pos: 0) - shallowCopy(result.s, blob) - # ensure we can read without index checks: - result.s.add '\0' - -proc loadType(g; id: int; info: TLineInfo): PType = - result = g.incr.r.types.getOrDefault(id) - if result != nil: return result - var b = loadBlob(g, sql"select data from types where nimid = ?", id) - - if b.s[b.pos] == '[': - inc(b.pos) - if b.s[b.pos] == ']': - inc(b.pos) - return # nil type - new(result) - result.kind = TTypeKind(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == '+': - inc(b.pos) - result.uniqueId = decodeVInt(b.s, b.pos) - setId(result.uniqueId) - #if debugIds: registerID(result) - else: - internalError(g.config, info, "decodeType: no id") - if b.s[b.pos] == '+': - inc(b.pos) - result.id = decodeVInt(b.s, b.pos) - else: - result.id = result.uniqueId - # here this also avoids endless recursion for recursive type - g.incr.r.types.add(result.uniqueId, result) - if b.s[b.pos] == '(': result.n = decodeNode(g, b, unknownLineInfo) - if b.s[b.pos] == '$': - inc(b.pos) - result.flags = cast[TTypeFlags](int32(decodeVInt(b.s, b.pos))) - if b.s[b.pos] == '?': - inc(b.pos) - result.callConv = TCallingConvention(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == '*': - inc(b.pos) - result.owner = loadSym(g, decodeVInt(b.s, b.pos), info) - if b.s[b.pos] == '&': - inc(b.pos) - result.sym = loadSym(g, decodeVInt(b.s, b.pos), info) - if b.s[b.pos] == '/': - inc(b.pos) - result.size = decodeVInt(b.s, b.pos) - else: - result.size = -1 - if b.s[b.pos] == '=': - inc(b.pos) - result.align = decodeVInt(b.s, b.pos).int16 - else: - result.align = 2 - - if b.s[b.pos] == '\14': - inc(b.pos) - result.lockLevel = decodeVInt(b.s, b.pos).TLockLevel - else: - result.lockLevel = UnspecifiedLockLevel - - if b.s[b.pos] == '\15': - inc(b.pos) - result.paddingAtEnd = decodeVInt(b.s, b.pos).int16 - - for a in low(result.attachedOps)..high(result.attachedOps): - if b.s[b.pos] == '\16': - inc(b.pos) - let id = decodeVInt(b.s, b.pos) - if id >= 0: - result.attachedOps[a] = loadSym(g, id, info) - - while b.s[b.pos] == '\19': - inc(b.pos) - let x = decodeVInt(b.s, b.pos) - doAssert b.s[b.pos] == '\20' - inc(b.pos) - let y = loadSym(g, decodeVInt(b.s, b.pos), info) - result.methods.add((x, y)) - decodeLoc(g, b, result.loc, info) - if b.s[b.pos] == '\21': - inc(b.pos) - let d = decodeVInt(b.s, b.pos) - result.typeInst = loadType(g, d, info) - while b.s[b.pos] == '^': - inc(b.pos) - if b.s[b.pos] == '(': - inc(b.pos) - if b.s[b.pos] == ')': inc(b.pos) - else: internalError(g.config, info, "decodeType ^(" & b.s[b.pos]) - rawAddSon(result, nil) - else: - let d = decodeVInt(b.s, b.pos) - result.sons.add loadType(g, d, info) - -proc decodeLib(g; b; info: TLineInfo): PLib = - result = nil - if b.s[b.pos] == '|': - new(result) - inc(b.pos) - result.kind = TLibKind(decodeVInt(b.s, b.pos)) - if b.s[b.pos] != '|': internalError(g.config, "decodeLib: 1") - inc(b.pos) - result.name = rope(decodeStr(b.s, b.pos)) - if b.s[b.pos] != '|': internalError(g.config, "decodeLib: 2") - inc(b.pos) - result.path = decodeNode(g, b, info) - -proc decodeInstantiations(g; b; info: TLineInfo; - s: var seq[PInstantiation]) = - while b.s[b.pos] == '\15': - inc(b.pos) - var ii: PInstantiation - new ii - ii.sym = loadSym(g, decodeVInt(b.s, b.pos), info) - ii.concreteTypes = @[] - while b.s[b.pos] == '\17': - inc(b.pos) - ii.concreteTypes.add loadType(g, decodeVInt(b.s, b.pos), info) - if b.s[b.pos] == '\20': - inc(b.pos) - ii.compilesId = decodeVInt(b.s, b.pos) - s.add ii - -proc loadSymFromBlob(g; b; info: TLineInfo): PSym = - if b.s[b.pos] == '{': - inc(b.pos) - if b.s[b.pos] == '}': - inc(b.pos) - return # nil sym - var k = TSymKind(decodeVInt(b.s, b.pos)) - var id: int - if b.s[b.pos] == '+': - inc(b.pos) - id = decodeVInt(b.s, b.pos) - setId(id) - else: - internalError(g.config, info, "decodeSym: no id") - var ident: PIdent - if b.s[b.pos] == '&': - inc(b.pos) - ident = g.cache.getIdent(decodeStr(b.s, b.pos)) - else: - internalError(g.config, info, "decodeSym: no ident") - #echo "decoding: {", ident.s - result = PSym(id: id, kind: k, name: ident) - # read the rest of the symbol description: - g.incr.r.syms.add(result.id, result) - if b.s[b.pos] == '^': - inc(b.pos) - result.typ = loadType(g, decodeVInt(b.s, b.pos), info) - decodeLineInfo(g, b, result.info) - if b.s[b.pos] == '*': - inc(b.pos) - result.owner = loadSym(g, decodeVInt(b.s, b.pos), result.info) - if b.s[b.pos] == '$': - inc(b.pos) - result.flags = cast[TSymFlags](decodeVBiggestInt(b.s, b.pos)) - if b.s[b.pos] == '@': - inc(b.pos) - result.magic = TMagic(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == '!': - inc(b.pos) - result.options = cast[TOptions](int32(decodeVInt(b.s, b.pos))) - if b.s[b.pos] == '%': - inc(b.pos) - result.position = decodeVInt(b.s, b.pos) - if b.s[b.pos] == '`': - inc(b.pos) - result.offset = decodeVInt(b.s, b.pos) - else: - result.offset = -1 - decodeLoc(g, b, result.loc, result.info) - result.annex = decodeLib(g, b, info) - if b.s[b.pos] == '#': - inc(b.pos) - result.constraint = decodeNode(g, b, unknownLineInfo) - case result.kind - of skType, skGenericParam: - while b.s[b.pos] == '\14': - inc(b.pos) - result.typeInstCache.add loadType(g, decodeVInt(b.s, b.pos), result.info) - of routineKinds: - decodeInstantiations(g, b, result.info, result.procInstCache) - if b.s[b.pos] == '\16': - inc(b.pos) - result.gcUnsafetyReason = loadSym(g, decodeVInt(b.s, b.pos), result.info) - if b.s[b.pos] == '\24': - inc b.pos - result.transformedBody = decodeNode(g, b, result.info) - #result.transformedBody = nil - of skModule, skPackage: - decodeInstantiations(g, b, result.info, result.usedGenerics) - of skLet, skVar, skField, skForVar: - if b.s[b.pos] == '\18': - inc(b.pos) - result.guard = loadSym(g, decodeVInt(b.s, b.pos), result.info) - if b.s[b.pos] == '\19': - inc(b.pos) - result.bitsize = decodeVInt(b.s, b.pos).int16 - else: discard - - if b.s[b.pos] == '(': - #if result.kind in routineKinds: - # result.ast = nil - #else: - result.ast = decodeNode(g, b, result.info) - if sfCompilerProc in result.flags: - registerCompilerProc(g, result) - #echo "loading ", result.name.s - -proc loadSym(g; id: int; info: TLineInfo): PSym = - result = g.incr.r.syms.getOrDefault(id) - if result != nil: return result - var b = loadBlob(g, sql"select data from syms where nimid = ?", id) - result = loadSymFromBlob(g, b, info) - doAssert id == result.id, "symbol ID is not consistent!" - -proc registerModule*(g; module: PSym) = - g.incr.r.syms.add(abs module.id, module) - -proc loadModuleSymTab(g; module: PSym) = - ## goal: fill module.tab - g.incr.r.syms.add(module.id, module) - for row in db.fastRows(sql"select nimid, data from syms where module = ? and exported = 1", abs(module.id)): - let id = parseInt(row[0]) - var s = g.incr.r.syms.getOrDefault(id) - if s == nil: - var b = BlobReader(pos: 0) - shallowCopy(b.s, row[1]) - # ensure we can read without index checks: - b.s.add '\0' - s = loadSymFromBlob(g, b, module.info) - assert s != nil - if s.kind != skField: - strTableAdd(module.tab, s) - if sfSystemModule in module.flags: - g.systemModule = module - -proc replay(g: ModuleGraph; module: PSym; n: PNode) = - # XXX check if we need to replay nkStaticStmt here. - case n.kind - #of nkStaticStmt: - #evalStaticStmt(module, g, n[0], module) - #of nkVarSection, nkLetSection: - # nkVarSections are already covered by the vmgen which produces nkStaticStmt - of nkMethodDef: - methodDef(g, n[namePos].sym, fromCache=true) - of nkCommentStmt: - # pragmas are complex and can be user-overriden via templates. So - # instead of using the original ``nkPragma`` nodes, we rely on the - # fact that pragmas.nim was patched to produce specialized recorded - # statements for us in the form of ``nkCommentStmt`` with (key, value) - # pairs. Ordinary nkCommentStmt nodes never have children so this is - # not ambiguous. - # 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 - of nkImportStmt: - for x in n: - internalAssert g.config, x.kind == nkSym - let modpath = AbsoluteFile toFullPath(g.config, x.sym.info) - let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, modpath)) - internalAssert g.config, imported.id < 0 - of nkStmtList, nkStmtListExpr: - for x in n: replay(g, module, x) - of nkExportStmt: - for x in n: - doAssert x.kind == nkSym - strTableAdd(module.tab, x.sym) - else: discard "nothing to do for this node" - -proc loadNode*(g: ModuleGraph; module: PSym): PNode = - loadModuleSymTab(g, module) - result = newNodeI(nkStmtList, module.info) - for row in db.rows(sql"select data from toplevelstmts where module = ? order by position asc", - abs module.id): - var b = BlobReader(pos: 0) - # ensure we can read without index checks: - b.s = row[0] & '\0' - result.add decodeNode(g, b, module.info) - db.exec(sql"insert into controlblock(idgen) values (?)", gFrontEndId) - replay(g, module, result) - -proc setupModuleCache*(g: ModuleGraph) = - # historical note: there used to be a `rodfiles` dir with special tests - # for incremental compilation via symbol files. This was likely replaced by ic. - if g.config.symbolFiles == disabledSf: return - g.recordStmt = recordStmt - let dbfile = getNimcacheDir(g.config) / RelativeFile"rodfiles.db" - if g.config.symbolFiles == writeOnlySf: - removeFile(dbfile) - createDir getNimcacheDir(g.config) - let ec = encodeConfig(g) - if not fileExists(dbfile): - db = open(connection=string dbfile, user="nim", password="", - database="nim") - createDb(db) - db.exec(sql"insert into config(config) values (?)", ec) - else: - db = open(connection=string dbfile, user="nim", password="", - database="nim") - let oldConfig = db.getValue(sql"select config from config") - g.incr.configChanged = oldConfig != ec - # ensure the filename IDs stay consistent: - for row in db.rows(sql"select fullpath, nimid from filenames order by nimid"): - let id = fileInfoIdx(g.config, AbsoluteFile row[0]) - doAssert id.int == parseInt(row[1]) - db.exec(sql"update config set config = ?", ec) - db.exec(sql"pragma journal_mode=off") - # This MUST be turned off, otherwise it's way too slow even for testing purposes: - db.exec(sql"pragma SYNCHRONOUS=off") - db.exec(sql"pragma LOCKING_MODE=exclusive") - let lastId = db.getValue(sql"select max(idgen) from controlblock") - if lastId.len > 0: - idgen.setId(parseInt lastId) diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index 7070e6c3f8..353992fcac 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -8,7 +8,7 @@ # ## Serialization utilities for the compiler. -import strutils, math +import std/[strutils, math] # bcc on windows doesn't have C99 functions when defined(windows) and defined(bcc): @@ -33,10 +33,19 @@ when defined(windows) and defined(bcc): proc c_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf", header: "", nodecl, varargs.} + +when not declared(signbit): + proc c_signbit(x: SomeFloat): cint {.importc: "signbit", header: "".} + proc signbit*(x: SomeFloat): bool {.inline.} = + result = c_signbit(x) != 0 + proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string = case classify(f) of fcNan: - result = "NAN" + if signbit(f): + result = "-NAN" + else: + result = "NAN" of fcNegZero: result = "-0.0" & literalPostfix of fcZero: diff --git a/compiler/sem.nim b/compiler/sem.nim index e95f3799c5..5593f8b02c 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -16,10 +16,8 @@ import procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch, intsets, transf, vmdef, vm, aliases, cgmeth, lambdalifting, evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, - lowerings, plugins/active, rod, lineinfos, strtabs, int128, - isolation_check, typeallowed - -from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward + lowerings, plugins/active, lineinfos, strtabs, int128, + isolation_check, typeallowed, modulegraphs, enumtostr, concepts when defined(nimfix): import nimfix/prettybase @@ -38,7 +36,6 @@ proc semProcBody(c: PContext, n: PNode): PNode proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode proc changeType(c: PContext; n: PNode, newType: PType, check: bool) -proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode proc semTypeNode(c: PContext, n: PNode, prev: PType): PType proc semStmt(c: PContext, n: PNode; flags: TExprFlags): PNode proc semOpAux(c: PContext, n: PNode) @@ -83,7 +80,7 @@ proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode = if x.kind in {nkPar, nkTupleConstr, nkCurly} and formal.kind != tyUntyped: changeType(c, x, formal, check=true) result = arg - result = skipHiddenSubConv(result, c.idgen) + result = skipHiddenSubConv(result, c.graph, c.idgen) proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = @@ -124,8 +121,8 @@ proc commonType*(c: PContext; x, y: PType): PType = # turn any concrete typedesc into the abstract typedesc type if a.len == 0: result = a else: - result = newType(tyTypeDesc, nextId(c.idgen), a.owner) - rawAddSon(result, newType(tyNone, nextId(c.idgen), a.owner)) + result = newType(tyTypeDesc, nextTypeId(c.idgen), a.owner) + rawAddSon(result, newType(tyNone, nextTypeId(c.idgen), a.owner)) elif b.kind in {tyArray, tySet, tySequence} and a.kind == b.kind: # check for seq[empty] vs. seq[int] @@ -137,7 +134,10 @@ proc commonType*(c: PContext; x, y: PType): PType = let aEmpty = isEmptyContainer(a[i]) let bEmpty = isEmptyContainer(b[i]) if aEmpty != bEmpty: - if nt.isNil: nt = copyType(a, nextId(c.idgen), a.owner) + if nt.isNil: + nt = copyType(a, nextTypeId(c.idgen), a.owner) + copyTypeProps(c.graph, c.idgen.module, nt, a) + nt[i] = if aEmpty: b[i] else: a[i] if not nt.isNil: result = nt #elif b[idx].kind == tyEmpty: return x @@ -146,7 +146,7 @@ proc commonType*(c: PContext; x, y: PType): PType = # range[0..4]. But then why is (range[0..4], 6) not range[0..6]? # But then why is (2,4) not range[2..4]? But I think this would break # too much code. So ... it's the same range or the base type. This means - # type(if b: 0 else 1) == int and not range[0..1]. For now. In the long + # typeof(if b: 0 else 1) == int and not range[0..1]. For now. In the long # run people expect ranges to work properly within a tuple. if not sameType(a, b): result = skipTypes(a, {tyRange}).skipIntLit(c.idgen) @@ -176,7 +176,7 @@ proc commonType*(c: PContext; x, y: PType): PType = # ill-formed AST, no need for additional tyRef/tyPtr if k != tyNone and x.kind != tyGenericInst: let r = result - result = newType(k, nextId(c.idgen), r.owner) + result = newType(k, nextTypeId(c.idgen), r.owner) result.addSonSkipIntLit(r, c.idgen) proc endsInNoReturn(n: PNode): bool = @@ -193,7 +193,7 @@ proc commonType*(c: PContext; x: PType, y: PNode): PType = commonType(c, x, y.typ) proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = - result = newSym(kind, considerQuotedIdent(c, n), nextId c.idgen, getCurrOwner(c), n.info) + result = newSym(kind, considerQuotedIdent(c, n), nextSymId c.idgen, getCurrOwner(c), n.info) when defined(nimsuggest): suggestDecl(c, n, result) @@ -216,7 +216,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = # template; we must fix it here: see #909 result.owner = getCurrOwner(c) else: - result = newSym(kind, considerQuotedIdent(c, n), nextId c.idgen, getCurrOwner(c), n.info) + result = newSym(kind, considerQuotedIdent(c, n), nextSymId c.idgen, getCurrOwner(c), n.info) #if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule: # incl(result.flags, sfGlobal) when defined(nimsuggest): @@ -255,7 +255,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, proc symFromType(c: PContext; t: PType, info: TLineInfo): PSym = if t.sym != nil: return t.sym - result = newSym(skType, getIdent(c.cache, "AnonType"), nextId c.idgen, t.owner, info) + result = newSym(skType, getIdent(c.cache, "AnonType"), nextSymId c.idgen, t.owner, info) result.flags.incl sfAnon result.typ = t @@ -504,6 +504,8 @@ proc addCodeForGenerics(c: PContext, n: PNode) = proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = var c = newContext(graph, module) c.idgen = idgen + c.enforceVoidContext = newType(tyTyped, nextTypeId(idgen), nil) + if c.p != nil: internalError(graph.config, module.info, "sem.myOpen") c.semConstExpr = semConstExpr c.semExpr = semExpr @@ -559,6 +561,7 @@ proc isEmptyTree(n: PNode): bool = proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = if c.topStmts == 0 and not isImportSystemStmt(c.graph, n): if sfSystemModule notin c.module.flags and not isEmptyTree(n): + assert c.graph.systemModule != nil c.moduleScope.addSym c.graph.systemModule # import the "System" identifier importAllSymbols(c, c.graph.systemModule) inc c.topStmts @@ -616,7 +619,7 @@ proc myProcess(context: PPassContext, n: PNode): PNode {.nosinks.} = else: result = newNodeI(nkEmpty, n.info) #if c.config.cmd == cmdIdeTools: findSuggest(c, n) - rod.storeNode(c.graph, c.module, result) + storeRodNode(c, result) proc reportUnusedModules(c: PContext) = for i in 0..high(c.unusedImports): @@ -638,7 +641,7 @@ proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = result.add(c.module.ast) popOwner(c) popProcCon(c) - storeRemaining(c.graph, c.module) + saveRodFile(c) const semPass* = makePass(myOpen, myProcess, myClose, isFrontend = true) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 1e8da02988..99979c3821 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -407,6 +407,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode, if overloadsState == csEmpty and result.state == csEmpty: if efNoUndeclared notin flags: # for tests/pragmas/tcustom_pragma.nim + # xxx adapt/use errorUndeclaredIdentifierHint(c, n, f.ident) localError(c.config, n.info, getMsgDiagnostic(c, flags, n, f)) return elif result.state != csMatch: @@ -444,7 +445,7 @@ proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) = let a = if a.kind == nkHiddenDeref: a[0] else: a if a.kind == nkHiddenCallConv and a[0].kind == nkSym: let s = a[0].sym - if s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty: + if s.isGenericRoutineStrict: let finalCallee = generateInstance(c, s, x.bindings, a.info) a[0].sym = finalCallee a[0].typ = finalCallee.typ @@ -523,7 +524,7 @@ proc semResolvedCall(c: PContext, x: TCandidate, if result.typ.kind == tyError: incl result.typ.flags, tfCheckedForDestructor return let gp = finalCallee.ast[genericParamsPos] - if gp.kind != nkEmpty: + if gp.isGenericParams: if x.calleeSym.kind notin {skMacro, skTemplate}: if x.calleeSym.magic in {mArrGet, mArrPut}: finalCallee = x.calleeSym @@ -685,9 +686,9 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym = var x: PType if param.typ.kind == tyVar: x = newTypeS(param.typ.kind, c) - x.addSonSkipIntLit(t.baseOfDistinct(c.idgen), c.idgen) + x.addSonSkipIntLit(t.baseOfDistinct(c.graph, c.idgen), c.idgen) else: - x = t.baseOfDistinct(c.idgen) + x = t.baseOfDistinct(c.graph, c.idgen) call.add(newNodeIT(nkEmpty, fn.info, x)) if hasDistinct: let filter = if fn.kind in {skProc, skFunc}: {skProc, skFunc} else: {fn.kind} diff --git a/compiler/semdata.nim b/compiler/semdata.nim index a6660e14c7..5cd440cc12 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -9,9 +9,13 @@ ## This module contains the data structures for the semantic checking phase. +import std / tables + import intsets, options, ast, astalgo, msgs, idents, renderer, - magicsys, vmdef, modulegraphs, lineinfos, sets + magicsys, vmdef, modulegraphs, lineinfos, sets, pathutils + +import ic / ic type TOptionEntry* = object # entries to put on a stack for pragma parsing @@ -38,6 +42,7 @@ type mappingExists*: bool mapping*: TIdTable caseContext*: seq[tuple[n: PNode, idx: int]] + localBindStmts*: seq[PNode] TMatchedConcept* = object candidateType*: PType @@ -77,9 +82,9 @@ type case mode*: ImportMode of importAll: discard of importSet: - imported*: IntSet + imported*: IntSet # of PIdent.id of importExcept: - exceptSet*: IntSet + exceptSet*: IntSet # of PIdent.id PContext* = ref TContext TContext* = object of TPassContext # a context represents the module @@ -91,6 +96,9 @@ type imports*: seq[ImportedModule] # scope for all imported symbols topLevelScope*: PScope # scope for all top-level symbols p*: PProcCon # procedure context + intTypeCache*: array[-5..32, PType] # cache some common integer types + # to avoid type allocations + nilTypeCache*: PType matchedConcept*: ptr TMatchedConcept # the current concept being matched friendModules*: seq[PSym] # friend modules; may access private data; # this is used so that generic instantiations @@ -145,18 +153,57 @@ type suggestionsMade*: bool isAmbiguous*: bool # little hack features*: set[Feature] - inTypeContext*: int - typesWithOps*: seq[(PType, PType)] #\ - # We need to instantiate the type bound ops lazily after - # the generic type has been constructed completely. See - # tests/destructor/topttree.nim for an example that - # would otherwise fail. + inTypeContext*, inConceptDecl*: int unusedImports*: seq[(PSym, TLineInfo)] exportIndirections*: HashSet[(int, int)] lastTLineInfo*: TLineInfo template config*(c: PContext): ConfigRef = c.graph.config +proc getIntLitType*(c: PContext; literal: PNode): PType = + # we cache some common integer literal types for performance: + let value = literal.intVal + if value >= low(c.intTypeCache) and value <= high(c.intTypeCache): + result = c.intTypeCache[value.int] + if result == nil: + let ti = getSysType(c.graph, literal.info, tyInt) + result = copyType(ti, nextTypeId(c.idgen), ti.owner) + result.n = literal + c.intTypeCache[value.int] = result + else: + let ti = getSysType(c.graph, literal.info, tyInt) + result = copyType(ti, nextTypeId(c.idgen), ti.owner) + result.n = literal + +proc setIntLitType*(c: PContext; result: PNode) = + let i = result.intVal + case c.config.target.intSize + of 8: result.typ = getIntLitType(c, result) + of 4: + if i >= low(int32) and i <= high(int32): + result.typ = getIntLitType(c, result) + else: + result.typ = getSysType(c.graph, result.info, tyInt64) + of 2: + if i >= low(int16) and i <= high(int16): + result.typ = getIntLitType(c, result) + elif i >= low(int32) and i <= high(int32): + result.typ = getSysType(c.graph, result.info, tyInt32) + else: + result.typ = getSysType(c.graph, result.info, tyInt64) + of 1: + # 8 bit CPUs are insane ... + if i >= low(int8) and i <= high(int8): + result.typ = getIntLitType(c, result) + elif i >= low(int16) and i <= high(int16): + result.typ = getSysType(c.graph, result.info, tyInt16) + elif i >= low(int32) and i <= high(int32): + result.typ = getSysType(c.graph, result.info, tyInt32) + else: + result.typ = getSysType(c.graph, result.info, tyInt64) + else: + internalError(c.config, result.info, "invalid int size") + proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = result.genericSym = s result.inst = inst @@ -247,7 +294,6 @@ proc popOptionEntry*(c: PContext) = proc newContext*(graph: ModuleGraph; module: PSym): PContext = new(result) - result.enforceVoidContext = PType(kind: tyTyped) result.optionStack = @[newOptionEntry(graph.config)] result.libs = @[] result.module = module @@ -262,24 +308,64 @@ proc newContext*(graph: ModuleGraph; module: PSym): PContext = result.cache = graph.cache result.graph = graph initStrTable(result.signatures) - result.typesWithOps = @[] result.features = graph.config.features + if graph.config.symbolFiles != disabledSf: + let id = module.position + assert graph.packed[id].status in {undefined, outdated} + graph.packed[id].status = storing + graph.packed[id].module = module + initEncoder graph, module -proc inclSym(sq: var seq[PSym], s: PSym) = +template packedRepr*(c): untyped = c.graph.packed[c.module.position].fromDisk +template encoder*(c): untyped = c.graph.encoders[c.module.position] + +proc addIncludeFileDep*(c: PContext; f: FileIndex) = + if c.config.symbolFiles != disabledSf: + addIncludeFileDep(c.encoder, c.packedRepr, f) + +proc addImportFileDep*(c: PContext; f: FileIndex) = + if c.config.symbolFiles != disabledSf: + addImportFileDep(c.encoder, c.packedRepr, f) + +proc addPragmaComputation*(c: PContext; n: PNode) = + if c.config.symbolFiles != disabledSf: + addPragmaComputation(c.encoder, c.packedRepr, n) + +proc inclSym(sq: var seq[PSym], s: PSym): bool = for i in 0.. we don't want the restriction # to 'skIterator' anymore; skIterator is preferred in sigmatch already # for typeof support. - # for ``type(countup(1,3))``, see ``tests/ttoseq``. + # for ``typeof(countup(1,3))``, see ``tests/ttoseq``. result = semOverloadedCall(c, n, nOrig, {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate, skIterator}, flags) else: @@ -888,6 +897,9 @@ proc setGenericParams(c: PContext, n: PNode) = n[i].typ = semTypeNode(c, n[i], nil) proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode = + if efNoSemCheck notin flags and n.typ != nil and n.typ.kind == tyError: + return errorNode(c, n) + result = n let callee = result[0].sym case callee.kind @@ -1015,7 +1027,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = proc buildEchoStmt(c: PContext, n: PNode): PNode = # we MUST not check 'n' for semantics again here! But for now we give up: result = newNodeI(nkCall, n.info) - var e = strTableGet(c.graph.systemModule.tab, getIdent(c.cache, "echo")) + let e = systemModuleSym(c.graph, getIdent(c.cache, "echo")) if e != nil: result.add(newSymNode(e)) else: @@ -1073,7 +1085,7 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, s = newNodeIT(nkCurly, n.info, setType) for j in 0.. argB: argA else: argB, n, g) + result = newIntNodeT(if argA > argB: argA else: argB, n, idgen, g) of mShlI: case skipTypes(n.typ, abstractRange).kind - of tyInt8: result = newIntNodeT(toInt128(toInt8(getInt(a)) shl toInt64(getInt(b))), n, g) - of tyInt16: result = newIntNodeT(toInt128(toInt16(getInt(a)) shl toInt64(getInt(b))), n, g) - of tyInt32: result = newIntNodeT(toInt128(toInt32(getInt(a)) shl toInt64(getInt(b))), n, g) - of tyInt64: result = newIntNodeT(toInt128(toInt64(getInt(a)) shl toInt64(getInt(b))), n, g) + of tyInt8: result = newIntNodeT(toInt128(toInt8(getInt(a)) shl toInt64(getInt(b))), n, idgen, g) + of tyInt16: result = newIntNodeT(toInt128(toInt16(getInt(a)) shl toInt64(getInt(b))), n, idgen, g) + of tyInt32: result = newIntNodeT(toInt128(toInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g) + of tyInt64: result = newIntNodeT(toInt128(toInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g) of tyInt: if g.config.target.intSize == 4: - result = newIntNodeT(toInt128(toInt32(getInt(a)) shl toInt64(getInt(b))), n, g) + result = newIntNodeT(toInt128(toInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g) else: - result = newIntNodeT(toInt128(toInt64(getInt(a)) shl toInt64(getInt(b))), n, g) - of tyUInt8: result = newIntNodeT(toInt128(toUInt8(getInt(a)) shl toInt64(getInt(b))), n, g) - of tyUInt16: result = newIntNodeT(toInt128(toUInt16(getInt(a)) shl toInt64(getInt(b))), n, g) - of tyUInt32: result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl toInt64(getInt(b))), n, g) - of tyUInt64: result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl toInt64(getInt(b))), n, g) + result = newIntNodeT(toInt128(toInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g) + of tyUInt8: result = newIntNodeT(toInt128(toUInt8(getInt(a)) shl toInt64(getInt(b))), n, idgen, g) + of tyUInt16: result = newIntNodeT(toInt128(toUInt16(getInt(a)) shl toInt64(getInt(b))), n, idgen, g) + of tyUInt32: result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g) + of tyUInt64: result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g) of tyUInt: if g.config.target.intSize == 4: - result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl toInt64(getInt(b))), n, g) + result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g) else: - result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl toInt64(getInt(b))), n, g) + result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g) else: internalError(g.config, n.info, "constant folding for shl") of mShrI: var a = cast[uint64](getInt(a)) @@ -192,75 +203,75 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = # unsigned and 64 bit integers don't need masking discard let c = cast[BiggestInt](a shr b) - result = newIntNodeT(toInt128(c), n, g) + result = newIntNodeT(toInt128(c), n, idgen, g) of mAshrI: case skipTypes(n.typ, abstractRange).kind - of tyInt8: result = newIntNodeT(toInt128(ashr(toInt8(getInt(a)), toInt8(getInt(b)))), n, g) - of tyInt16: result = newIntNodeT(toInt128(ashr(toInt16(getInt(a)), toInt16(getInt(b)))), n, g) - of tyInt32: result = newIntNodeT(toInt128(ashr(toInt32(getInt(a)), toInt32(getInt(b)))), n, g) + of tyInt8: result = newIntNodeT(toInt128(ashr(toInt8(getInt(a)), toInt8(getInt(b)))), n, idgen, g) + of tyInt16: result = newIntNodeT(toInt128(ashr(toInt16(getInt(a)), toInt16(getInt(b)))), n, idgen, g) + of tyInt32: result = newIntNodeT(toInt128(ashr(toInt32(getInt(a)), toInt32(getInt(b)))), n, idgen, g) of tyInt64, tyInt: - result = newIntNodeT(toInt128(ashr(toInt64(getInt(a)), toInt64(getInt(b)))), n, g) + result = newIntNodeT(toInt128(ashr(toInt64(getInt(a)), toInt64(getInt(b)))), n, idgen, g) else: internalError(g.config, n.info, "constant folding for ashr") of mDivI: let argA = getInt(a) let argB = getInt(b) if argB != Zero and (argA != firstOrd(g.config, n.typ) or argB != NegOne): - result = newIntNodeT(argA div argB, n, g) + result = newIntNodeT(argA div argB, n, idgen, g) of mModI: let argA = getInt(a) let argB = getInt(b) if argB != Zero and (argA != firstOrd(g.config, n.typ) or argB != NegOne): - result = newIntNodeT(argA mod argB, n, g) + result = newIntNodeT(argA mod argB, n, idgen, g) of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n, g) of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n, g) of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g) of mDivF64: result = newFloatNodeT(getFloat(a) / getFloat(b), n, g) - of mIsNil: result = newIntNodeT(toInt128(ord(a.kind == nkNilLit)), n, g) + of mIsNil: result = newIntNodeT(toInt128(ord(a.kind == nkNilLit)), n, idgen, g) of mLtI, mLtB, mLtEnum, mLtCh: - result = newIntNodeT(toInt128(ord(getOrdValue(a) < getOrdValue(b))), n, g) + result = newIntNodeT(toInt128(ord(getOrdValue(a) < getOrdValue(b))), n, idgen, g) of mLeI, mLeB, mLeEnum, mLeCh: - result = newIntNodeT(toInt128(ord(getOrdValue(a) <= getOrdValue(b))), n, g) + result = newIntNodeT(toInt128(ord(getOrdValue(a) <= getOrdValue(b))), n, idgen, g) of mEqI, mEqB, mEqEnum, mEqCh: - result = newIntNodeT(toInt128(ord(getOrdValue(a) == getOrdValue(b))), n, g) - of mLtF64: result = newIntNodeT(toInt128(ord(getFloat(a) < getFloat(b))), n, g) - of mLeF64: result = newIntNodeT(toInt128(ord(getFloat(a) <= getFloat(b))), n, g) - of mEqF64: result = newIntNodeT(toInt128(ord(getFloat(a) == getFloat(b))), n, g) - of mLtStr: result = newIntNodeT(toInt128(ord(getStr(a) < getStr(b))), n, g) - of mLeStr: result = newIntNodeT(toInt128(ord(getStr(a) <= getStr(b))), n, g) - of mEqStr: result = newIntNodeT(toInt128(ord(getStr(a) == getStr(b))), n, g) + result = newIntNodeT(toInt128(ord(getOrdValue(a) == getOrdValue(b))), n, idgen, g) + of mLtF64: result = newIntNodeT(toInt128(ord(getFloat(a) < getFloat(b))), n, idgen, g) + of mLeF64: result = newIntNodeT(toInt128(ord(getFloat(a) <= getFloat(b))), n, idgen, g) + of mEqF64: result = newIntNodeT(toInt128(ord(getFloat(a) == getFloat(b))), n, idgen, g) + of mLtStr: result = newIntNodeT(toInt128(ord(getStr(a) < getStr(b))), n, idgen, g) + of mLeStr: result = newIntNodeT(toInt128(ord(getStr(a) <= getStr(b))), n, idgen, g) + of mEqStr: result = newIntNodeT(toInt128(ord(getStr(a) == getStr(b))), n, idgen, g) of mLtU: - result = newIntNodeT(toInt128(ord(`<%`(toInt64(getOrdValue(a)), toInt64(getOrdValue(b))))), n, g) + result = newIntNodeT(toInt128(ord(`<%`(toInt64(getOrdValue(a)), toInt64(getOrdValue(b))))), n, idgen, g) of mLeU: - result = newIntNodeT(toInt128(ord(`<=%`(toInt64(getOrdValue(a)), toInt64(getOrdValue(b))))), n, g) - of mBitandI, mAnd: result = newIntNodeT(bitand(a.getInt, b.getInt), n, g) - of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, g) - of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, g) + result = newIntNodeT(toInt128(ord(`<=%`(toInt64(getOrdValue(a)), toInt64(getOrdValue(b))))), n, idgen, g) + of mBitandI, mAnd: result = newIntNodeT(bitand(a.getInt, b.getInt), n, idgen, g) + of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, idgen, g) + of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, idgen, g) of mAddU: let val = maskBytes(getInt(a) + getInt(b), int(n.typ.size)) - result = newIntNodeT(val, n, g) + result = newIntNodeT(val, n, idgen, g) of mSubU: let val = maskBytes(getInt(a) - getInt(b), int(n.typ.size)) - result = newIntNodeT(val, n, g) + result = newIntNodeT(val, n, idgen, g) # echo "subU: ", val, " n: ", n, " result: ", val of mMulU: let val = maskBytes(getInt(a) * getInt(b), int(n.typ.size)) - result = newIntNodeT(val, n, g) + result = newIntNodeT(val, n, idgen, g) of mModU: let argA = maskBytes(getInt(a), int(a.typ.size)) let argB = maskBytes(getInt(b), int(a.typ.size)) if argB != Zero: - result = newIntNodeT(argA mod argB, n, g) + result = newIntNodeT(argA mod argB, n, idgen, g) of mDivU: let argA = maskBytes(getInt(a), int(a.typ.size)) let argB = maskBytes(getInt(b), int(a.typ.size)) if argB != Zero: - result = newIntNodeT(argA div argB, n, g) - of mLeSet: result = newIntNodeT(toInt128(ord(containsSets(g.config, a, b))), n, g) - of mEqSet: result = newIntNodeT(toInt128(ord(equalSets(g.config, a, b))), n, g) + result = newIntNodeT(argA div argB, n, idgen, g) + of mLeSet: result = newIntNodeT(toInt128(ord(containsSets(g.config, a, b))), n, idgen, g) + of mEqSet: result = newIntNodeT(toInt128(ord(equalSets(g.config, a, b))), n, idgen, g) of mLtSet: result = newIntNodeT(toInt128(ord( - containsSets(g.config, a, b) and not equalSets(g.config, a, b))), n, g) + containsSets(g.config, a, b) and not equalSets(g.config, a, b))), n, idgen, g) of mMulSet: result = nimsets.intersectSets(g.config, a, b) result.info = n.info @@ -271,7 +282,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = result = nimsets.diffSets(g.config, a, b) result.info = n.info of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n, g) - of mInSet: result = newIntNodeT(toInt128(ord(inSet(a, b))), n, g) + of mInSet: result = newIntNodeT(toInt128(ord(inSet(a, b))), n, idgen, g) of mRepr: # BUGFIX: we cannot eval mRepr here for reasons that I forgot. discard @@ -294,13 +305,13 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = result = copyTree(a) result.typ = n.typ of mCompileOption: - result = newIntNodeT(toInt128(ord(commands.testCompileOption(g.config, a.getStr, n.info))), n, g) + result = newIntNodeT(toInt128(ord(commands.testCompileOption(g.config, a.getStr, n.info))), n, idgen, g) of mCompileOptionArg: result = newIntNodeT(toInt128(ord( - testCompileOptionArg(g.config, getStr(a), getStr(b), n.info))), n, g) + testCompileOptionArg(g.config, getStr(a), getStr(b), n.info))), n, idgen, g) of mEqProc: result = newIntNodeT(toInt128(ord( - exprStructuralEquivalent(a, b, strictSymEquality=true))), n, g) + exprStructuralEquivalent(a, b, strictSymEquality=true))), n, idgen, g) else: discard proc getConstIfExpr(c: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = @@ -346,7 +357,7 @@ proc magicCall(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = if n.len > 3: c = getConstExpr(m, n[3], idgen, g) if c == nil: return - result = evalOp(s.magic, n, a, b, c, g) + result = evalOp(s.magic, n, a, b, c, idgen, g) proc getAppType(n: PNode; g: ModuleGraph): PNode = if g.config.globalOptions.contains(optGenDynLib): @@ -363,7 +374,7 @@ proc rangeCheck(n: PNode, value: Int128; g: ModuleGraph) = localError(g.config, n.info, "cannot convert " & $value & " to " & typeToString(n.typ)) -proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode = +proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): PNode = let dstTyp = skipTypes(n.typ, abstractRange - {tyTypeDesc}) let srcTyp = skipTypes(a.typ, abstractRange - {tyTypeDesc}) @@ -377,9 +388,9 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode = of tyBool: case srcTyp.kind of tyFloat..tyFloat64: - result = newIntNodeT(toInt128(getFloat(a) != 0.0), n, g) + result = newIntNodeT(toInt128(getFloat(a) != 0.0), n, idgen, g) of tyChar, tyUInt..tyUInt64, tyInt..tyInt64: - result = newIntNodeT(toInt128(a.getOrdValue != 0), n, g) + result = newIntNodeT(toInt128(a.getOrdValue != 0), n, idgen, g) of tyBool, tyEnum: # xxx shouldn't we disallow `tyEnum`? result = a result.typ = n.typ @@ -387,11 +398,11 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode = of tyInt..tyInt64, tyUInt..tyUInt64: case srcTyp.kind of tyFloat..tyFloat64: - result = newIntNodeT(toInt128(getFloat(a)), n, g) + result = newIntNodeT(toInt128(getFloat(a)), n, idgen, g) of tyChar, tyUInt..tyUInt64, tyInt..tyInt64: var val = a.getOrdValue if check: rangeCheck(n, val, g) - result = newIntNodeT(val, n, g) + result = newIntNodeT(val, n, idgen, g) if dstTyp.kind in {tyUInt..tyUInt64}: result.transitionIntKind(nkUIntLit) else: @@ -476,7 +487,7 @@ proc foldConStrStr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode proc newSymNodeTypeDesc*(s: PSym; idgen: IdGenerator; info: TLineInfo): PNode = result = newSymNode(s, info) if s.typ.kind != tyTypeDesc: - result.typ = newType(tyTypeDesc, idgen.nextId, s.owner) + result.typ = newType(tyTypeDesc, idgen.nextTypeId, s.owner) result.typ.addSonSkipIntLit(s.typ, idgen) else: result.typ = s.typ @@ -488,13 +499,13 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode var s = n.sym case s.kind of skEnumField: - result = newIntNodeT(toInt128(s.position), n, g) + result = newIntNodeT(toInt128(s.position), n, idgen, g) of skConst: case s.magic - of mIsMainModule: result = newIntNodeT(toInt128(ord(sfMainModule in m.flags)), n, g) + of mIsMainModule: result = newIntNodeT(toInt128(ord(sfMainModule in m.flags)), n, idgen, g) of mCompileDate: result = newStrNodeT(getDateStr(), n, g) of mCompileTime: result = newStrNodeT(getClockStr(), n, g) - of mCpuEndian: result = newIntNodeT(toInt128(ord(CPU[g.config.target.targetCPU].endian)), n, g) + of mCpuEndian: result = newIntNodeT(toInt128(ord(CPU[g.config.target.targetCPU].endian)), n, idgen, g) of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.targetOS].name), n, g) of mHostCPU: result = newStrNodeT(platform.CPU[g.config.target.targetCPU].name.toLowerAscii, n, g) of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.hostOS].name), n, g) @@ -503,7 +514,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode of mIntDefine: if isDefined(g.config, s.name.s): try: - result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseInt), n, g) + result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseInt), n, idgen, g) except ValueError: localError(g.config, s.info, "{.intdefine.} const was set to an invalid integer: '" & @@ -518,7 +529,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode of mBoolDefine: if isDefined(g.config, s.name.s): try: - result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseBool.int), n, g) + result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseBool.int), n, idgen, g) except ValueError: localError(g.config, s.info, "{.booldefine.} const was set to an invalid bool: '" & @@ -564,30 +575,30 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode if skipTypes(n[1].typ, abstractVarRange).kind in tyFloat..tyFloat64: result = newFloatNodeT(firstFloat(n[1].typ), n, g) else: - result = newIntNodeT(firstOrd(g.config, n[1].typ), n, g) + result = newIntNodeT(firstOrd(g.config, n[1].typ), n, idgen, g) of mHigh: if skipTypes(n[1].typ, abstractVar+{tyUserTypeClassInst}).kind notin {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}: if skipTypes(n[1].typ, abstractVarRange).kind in tyFloat..tyFloat64: result = newFloatNodeT(lastFloat(n[1].typ), n, g) else: - result = newIntNodeT(lastOrd(g.config, skipTypes(n[1].typ, abstractVar)), n, g) + result = newIntNodeT(lastOrd(g.config, skipTypes(n[1].typ, abstractVar)), n, idgen, g) else: var a = getArrayConstr(m, n[1], idgen, g) if a.kind == nkBracket: # we can optimize it away: - result = newIntNodeT(toInt128(a.len-1), n, g) + result = newIntNodeT(toInt128(a.len-1), n, idgen, g) of mLengthOpenArray: var a = getArrayConstr(m, n[1], idgen, g) if a.kind == nkBracket: # we can optimize it away! This fixes the bug ``len(134)``. - result = newIntNodeT(toInt128(a.len), n, g) + result = newIntNodeT(toInt128(a.len), n, idgen, g) else: result = magicCall(m, n, idgen, g) of mLengthArray: # It doesn't matter if the argument is const or not for mLengthArray. # This fixes bug #544. - result = newIntNodeT(lengthOrd(g.config, n[1].typ), n, g) + result = newIntNodeT(lengthOrd(g.config, n[1].typ), n, idgen, g) of mSizeOf: result = foldSizeOf(g.config, n, nil) of mAlignOf: @@ -670,7 +681,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode of nkHiddenStdConv, nkHiddenSubConv, nkConv: var a = getConstExpr(m, n[1], idgen, g) if a == nil: return - result = foldConv(n, a, g, check=true) + result = foldConv(n, a, idgen, g, check=true) of nkDerefExpr, nkHiddenDeref: let a = getConstExpr(m, n[0], idgen, g) if a != nil and a.kind == nkNilLit: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 0d80da9a64..dfbb022c89 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -472,7 +472,7 @@ proc semGenericStmt(c: PContext, n: PNode, flags, ctx) if n[paramsPos].kind != nkEmpty: if n[paramsPos][0].kind != nkEmpty: - addPrelimDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nextId c.idgen, nil, n.info)) + addPrelimDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nextSymId c.idgen, nil, n.info)) n[paramsPos] = semGenericStmt(c, n[paramsPos], flags, ctx) n[pragmasPos] = semGenericStmt(c, n[pragmasPos], flags, ctx) var body: PNode @@ -481,7 +481,7 @@ proc semGenericStmt(c: PContext, n: PNode, if sfGenSym in s.flags and s.ast == nil: body = n[bodyPos] else: - body = s.getBody + body = getBody(c.graph, s) else: body = n[bodyPos] n[bodyPos] = semGenericStmtScope(c, body, flags, ctx) closeScope(c) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 8f2f51ae85..68ab2a310a 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -62,30 +62,29 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym for i, a in n.pairs: internalAssert c.config, a.kind == nkSym var q = a.sym - if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic}+tyTypeClasses: - continue - let symKind = if q.typ.kind == tyStatic: skConst else: skType - var s = newSym(symKind, q.name, nextId c.idgen, getCurrOwner(c), q.info) - s.flags.incl {sfUsed, sfFromGeneric} - var t = PType(idTableGet(pt, q.typ)) - if t == nil: - if tfRetType in q.typ.flags: - # keep the generic type and allow the return type to be bound - # later by semAsgn in return type inference scenario - t = q.typ - else: - localError(c.config, a.info, errCannotInstantiateX % s.name.s) + if q.typ.kind in {tyTypeDesc, tyGenericParam, tyStatic, tyConcept}+tyTypeClasses: + let symKind = if q.typ.kind == tyStatic: skConst else: skType + var s = newSym(symKind, q.name, nextSymId(c.idgen), getCurrOwner(c), q.info) + s.flags.incl {sfUsed, sfFromGeneric} + var t = PType(idTableGet(pt, q.typ)) + if t == nil: + if tfRetType in q.typ.flags: + # keep the generic type and allow the return type to be bound + # later by semAsgn in return type inference scenario + t = q.typ + else: + localError(c.config, a.info, errCannotInstantiateX % s.name.s) + t = errorType(c) + elif t.kind in {tyGenericParam, tyConcept}: + localError(c.config, a.info, errCannotInstantiateX % q.name.s) t = errorType(c) - elif t.kind == tyGenericParam: - localError(c.config, a.info, errCannotInstantiateX % q.name.s) - t = errorType(c) - elif t.kind == tyGenericInvocation: - #t = instGenericContainer(c, a, t) - t = generateTypeInstance(c, pt, a, t) - #t = ReplaceTypeVarsT(cl, t) - s.typ = t - if t.kind == tyStatic: s.ast = t.n - yield s + elif t.kind == tyGenericInvocation: + #t = instGenericContainer(c, a, t) + t = generateTypeInstance(c, pt, a, t) + #t = ReplaceTypeVarsT(cl, t) + s.typ = t + if t.kind == tyStatic: s.ast = t.n + yield s proc sameInstantiation(a, b: TInstantiation): bool = if a.concreteTypes.len == b.concreteTypes.len: @@ -95,9 +94,9 @@ proc sameInstantiation(a, b: TInstantiation): bool = ExactGcSafety}): return result = true -proc genericCacheGet(genericSym: PSym, entry: TInstantiation; +proc genericCacheGet(g: ModuleGraph; genericSym: PSym, entry: TInstantiation; id: CompilesId): PSym = - for inst in genericSym.procInstCache: + for inst in procInstCacheItems(g, genericSym): if (inst.compilesId == 0 or inst.compilesId == id) and sameInstantiation(entry, inst[]): return inst.sym @@ -118,7 +117,7 @@ proc freshGenSyms(c: PContext; n: PNode, owner, orig: PSym, symMap: var TIdTable n.sym = x elif s.owner == nil or s.owner.kind == skPackage: #echo "copied this ", s.name.s - x = copySym(s, nextId c.idgen) + x = copySym(s, nextSymId c.idgen) x.owner = owner idTablePut(symMap, s, x) n.sym = x @@ -160,7 +159,7 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) = pushInfoContext(c.config, oldPrc.info) openScope(c) var n = oldPrc.ast - n[bodyPos] = copyTree(s.getBody) + n[bodyPos] = copyTree(getBody(c.graph, s)) instantiateBody(c, n, oldPrc.typ.n, oldPrc, s) closeScope(c) popInfoContext(c.config) @@ -200,7 +199,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType, var param: PSym template paramSym(kind): untyped = - newSym(kind, genParam.sym.name, nextId c.idgen, genericTyp.sym, genParam.sym.info) + newSym(kind, genParam.sym.name, nextSymId c.idgen, genericTyp.sym, genParam.sym.info) if genParam.kind == tyStatic: param = paramSym skConst @@ -232,11 +231,11 @@ proc instantiateProcType(c: PContext, pt: TIdTable, # time adding the instantiated proc params into the current scope. # This is necessary, because the instantiation process may refer to # these params in situations like this: - # proc foo[Container](a: Container, b: a.type.Item): type(b.x) + # proc foo[Container](a: Container, b: a.type.Item): typeof(b.x) # # Alas, doing this here is probably not enough, because another # proc signature could appear in the params: - # proc foo[T](a: proc (x: T, b: type(x.y)) + # proc foo[T](a: proc (x: T, b: typeof(x.y)) # # The solution would be to move this logic into semtypinst, but # at this point semtypinst have to become part of sem, because it @@ -270,7 +269,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable, internalAssert c.config, originalParams[i].kind == nkSym let oldParam = originalParams[i].sym - let param = copySym(oldParam, nextId c.idgen) + let param = copySym(oldParam, nextSymId c.idgen) param.owner = prc param.typ = result[i] @@ -319,6 +318,14 @@ proc instantiateProcType(c: PContext, pt: TIdTable, prc.typ = result popInfoContext(c.config) +proc fillMixinScope(c: PContext) = + var p = c.p + while p != nil: + for bnd in p.localBindStmts: + for n in bnd: + addSym(c.currentScope, n.sym) + p = p.next + proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, info: TLineInfo): PSym {.nosinks.} = ## Generates a new instance of a generic procedure. @@ -339,15 +346,19 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, c.matchedConcept = nil let oldScope = c.currentScope while not isTopLevel(c): c.currentScope = c.currentScope.parent - result = copySym(fn, nextId c.idgen) + result = copySym(fn, nextSymId c.idgen) incl(result.flags, sfFromGeneric) result.owner = fn result.ast = n pushOwner(c, result) + # mixin scope: + openScope(c) + fillMixinScope(c) + openScope(c) let gp = n[genericParamsPos] - internalAssert c.config, gp.kind != nkEmpty + internalAssert c.config, gp.kind == nkGenericParams n[namePos] = newSymNode(result) pushInfoContext(c.config, info, fn.detailedInfo) var entry = TInstantiation.new @@ -369,7 +380,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, if tfTriggersCompileTime in result.typ.flags: incl(result.flags, sfCompileTime) n[genericParamsPos] = c.graph.emptyNode - var oldPrc = genericCacheGet(fn, entry[], c.compilesContextId) + var oldPrc = genericCacheGet(c.graph, fn, entry[], c.compilesContextId) if oldPrc == nil: # we MUST not add potentially wrong instantiations to the caching mechanism. # This means recursive instantiations behave differently when in @@ -378,12 +389,12 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, #if c.compilesContextId == 0: rawHandleSelf(c, result) entry.compilesId = c.compilesContextId - fn.procInstCache.add(entry) + addToGenericProcCache(c, fn, entry) c.generics.add(makeInstPair(fn, entry)) if n[pragmasPos].kind != nkEmpty: pragma(c, result, n[pragmasPos], allRoutinePragmas) if isNil(n[bodyPos]): - n[bodyPos] = copyTree(fn.getBody) + n[bodyPos] = copyTree(getBody(c.graph, fn)) if c.inGenericContext == 0: instantiateBody(c, n, fn.typ.n, result, fn) sideEffectsCheck(c, result) @@ -395,9 +406,13 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, popProcCon(c) popInfoContext(c.config) closeScope(c) # close scope for parameters + closeScope(c) # close scope for 'mixin' declarations popOwner(c) c.currentScope = oldScope discard c.friendModules.pop() dec(c.instCounter) c.matchedConcept = oldMatchedConcept if result.kind == skMethod: finishMethod(c, result) + + # inform IC of the generic + #addGeneric(c.ic, result, entry.concreteTypes) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 3368bcfbf0..c80e689a52 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -71,7 +71,7 @@ proc semAsgnOpr(c: PContext; n: PNode): PNode = proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode = var r = isPartOf(n[1], n[2]) - result = newIntNodeT(toInt128(ord(r)), n, c.graph) + result = newIntNodeT(toInt128(ord(r)), n, c.idgen, c.graph) proc expectIntLit(c: PContext, n: PNode): int = let x = c.semConstExpr(c, n) @@ -119,7 +119,7 @@ proc uninstantiate(t: PType): PType = else: t proc getTypeDescNode(c: PContext; typ: PType, sym: PSym, info: TLineInfo): PNode = - var resType = newType(tyTypeDesc, nextId c.idgen, sym) + var resType = newType(tyTypeDesc, nextTypeId c.idgen, sym) rawAddSon(resType, typ) result = toNode(resType, info) @@ -160,7 +160,7 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym) result.info = traitCall.info of "arity": result = newIntNode(nkIntLit, operand.len - ord(operand.kind==tyProc)) - result.typ = newType(tyInt, nextId c.idgen, context) + result.typ = newType(tyInt, nextTypeId c.idgen, context) result.info = traitCall.info of "genericHead": var arg = operand @@ -172,33 +172,28 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym) # result = toNode(resType, traitCall.info) # doesn't work yet else: localError(c.config, traitCall.info, "expected generic type, got: type $2 of kind $1" % [arg.kind.toHumanStr, typeToString(operand)]) - result = newType(tyError, nextId c.idgen, context).toNode(traitCall.info) + result = newType(tyError, nextTypeId c.idgen, context).toNode(traitCall.info) of "stripGenericParams": result = uninstantiate(operand).toNode(traitCall.info) of "supportsCopyMem": let t = operand.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink, tyInferred}) let complexObj = containsGarbageCollectedRef(t) or hasDestructor(t) - result = newIntNodeT(toInt128(ord(not complexObj)), traitCall, c.graph) + result = newIntNodeT(toInt128(ord(not complexObj)), traitCall, c.idgen, c.graph) of "isNamedTuple": var operand = operand.skipTypes({tyGenericInst}) let cond = operand.kind == tyTuple and operand.n != nil - result = newIntNodeT(toInt128(ord(cond)), traitCall, c.graph) + result = newIntNodeT(toInt128(ord(cond)), traitCall, c.idgen, c.graph) of "tupleLen": var operand = operand.skipTypes({tyGenericInst}) assert operand.kind == tyTuple, $operand.kind - result = newIntNodeT(toInt128(operand.len), traitCall, c.graph) + result = newIntNodeT(toInt128(operand.len), traitCall, c.idgen, c.graph) of "distinctBase": var arg = operand.skipTypes({tyGenericInst}) - if arg.kind == tyDistinct: - while arg.kind == tyDistinct: - arg = arg.base - arg = arg.skipTypes(skippedTypes + {tyGenericInst}) - result = getTypeDescNode(c, arg, operand.owner, traitCall.info) - else: - localError(c.config, traitCall.info, - "distinctBase expects a distinct type as argument. The given type was " & typeToString(operand)) - result = newType(tyError, nextId c.idgen, context).toNode(traitCall.info) + while arg.kind == tyDistinct: + arg = arg.base + arg = arg.skipTypes(skippedTypes + {tyGenericInst}) + result = getTypeDescNode(c, arg, operand.owner, traitCall.info) else: localError(c.config, traitCall.info, "unknown trait: " & s) result = newNodeI(nkEmpty, traitCall.info) @@ -370,7 +365,7 @@ proc semUnown(c: PContext; n: PNode): PNode = elems[i] = unownedType(c, t[i]) if elems[i] != t[i]: someChange = true if someChange: - result = newType(tyTuple, nextId c.idgen, t.owner) + result = newType(tyTuple, nextTypeId c.idgen, t.owner) # we have to use 'rawAddSon' here so that type flags are # properly computed: for e in elems: result.rawAddSon(e) @@ -381,7 +376,9 @@ proc semUnown(c: PContext; n: PNode): PNode = tyGenericInst, tyAlias: let b = unownedType(c, t[^1]) if b != t[^1]: - result = copyType(t, nextId c.idgen, t.owner) + result = copyType(t, nextTypeId c.idgen, t.owner) + copyTypeProps(c.graph, c.idgen.module, result, t) + result[^1] = b result.flags.excl tfHasOwned else: @@ -407,26 +404,26 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym if n.sym == oldParam: result.sym = newParam elif n.sym.owner == orig: - result.sym = copySym(n.sym, nextId c.idgen) + result.sym = copySym(n.sym, nextSymId c.idgen) result.sym.owner = procSym for i in 0 ..< safeLen(n): result[i] = transform(c, procSym, n[i], old, fresh, oldParam, newParam) #if n.kind == nkDerefExpr and sameType(n[0].typ, old): # result = - result = copySym(orig, nextId c.idgen) + result = copySym(orig, nextSymId c.idgen) result.info = info result.flags.incl sfFromGeneric result.owner = orig let origParamType = orig.typ[1] let newParamType = makeVarType(result, origParamType.skipTypes(abstractPtrs), c.idgen) let oldParam = orig.typ.n[1].sym - let newParam = newSym(skParam, oldParam.name, nextId c.idgen, result, result.info) + let newParam = newSym(skParam, oldParam.name, nextSymId c.idgen, result, result.info) newParam.typ = newParamType # proc body: result.ast = transform(c, result, orig.ast, origParamType, newParamType, oldParam, newParam) # proc signature: - result.typ = newProcType(result.info, nextId c.idgen, result) + result.typ = newProcType(result.info, nextTypeId c.idgen, result) result.typ.addParam newParam proc semQuantifier(c: PContext; n: PNode): PNode = @@ -528,10 +525,10 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, localError(c.config, n.info, "finalizer must be a direct reference to a proc") elif optTinyRtti in c.config.globalOptions: let nfin = skipConvCastAndClosure(n[^1]) - let fin = case nfin.kind + let fin = case nfin.kind of nkSym: nfin.sym of nkLambda, nkDo: nfin[namePos].sym - else: + else: localError(c.config, n.info, "finalizer must be a direct reference to a proc") nil if fin != nil: @@ -541,7 +538,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, # check if we converted this finalizer into a destructor already: let t = whereToBindTypeHook(c, fin.typ[1].skipTypes(abstractInst+{tyRef})) - if t != nil and t.attachedOps[attachedDestructor] != nil and t.attachedOps[attachedDestructor].owner == fin: + if t != nil and getAttachedOp(c.graph, t, attachedDestructor) != nil and + getAttachedOp(c.graph, t, attachedDestructor).owner == fin: discard "already turned this one into a finalizer" else: bindTypeHook(c, turnFinalizerIntoDestructor(c, fin, n.info), n, attachedDestructor) @@ -549,8 +547,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, of mDestroy: result = n let t = n[1].typ.skipTypes(abstractVar) - if t.destructor != nil: - result[0] = newSymNode(t.destructor) + let op = getAttachedOp(c.graph, t, attachedDestructor) + if op != nil: + result[0] = newSymNode(op) of mUnown: result = semUnown(c, n) of mExists, mForall: diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 42529e1e50..792488c9f9 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -153,6 +153,7 @@ proc collectMissingFields(c: PContext, fieldsRecList: PNode, if assignment == nil: constrCtx.missingFields.add r.sym + proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, flags: TExprFlags): InitStatus = diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index 82fb069db9..b5b0be91b0 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -81,7 +81,7 @@ proc initAnalysisCtx(g: ModuleGraph): AnalysisCtx = result.slices = @[] result.args = @[] result.guards.s = @[] - result.guards.o = initOperators(g) + result.guards.g = g result.graph = g proc lookupSlot(c: AnalysisCtx; s: PSym): int = @@ -138,7 +138,7 @@ proc checkLe(c: AnalysisCtx; a, b: PNode) = proc checkBounds(c: AnalysisCtx; arr, idx: PNode) = checkLe(c, lowBound(c.graph.config, arr), idx) - checkLe(c, idx, highBound(c.graph.config, arr, c.guards.o)) + checkLe(c, idx, highBound(c.graph.config, arr, c.graph.operators)) proc addLowerBoundAsFacts(c: var AnalysisCtx) = for v in c.locals: @@ -147,8 +147,8 @@ proc addLowerBoundAsFacts(c: var AnalysisCtx) = proc addSlice(c: var AnalysisCtx; n: PNode; x, le, ri: PNode) = checkLocal(c, n) - let le = le.canon(c.guards.o) - let ri = ri.canon(c.guards.o) + let le = le.canon(c.graph.operators) + let ri = ri.canon(c.graph.operators) # perform static bounds checking here; and not later! let oldState = c.guards.s.len addLowerBoundAsFacts(c) @@ -192,7 +192,7 @@ proc subStride(c: AnalysisCtx; n: PNode): PNode = if isLocal(n): let s = c.lookupSlot(n.sym) if s >= 0 and c.locals[s].stride != nil: - result = buildAdd(n, c.locals[s].stride.intVal, c.guards.o) + result = buildAdd(n, c.locals[s].stride.intVal, c.graph.operators) else: result = n elif n.safeLen > 0: @@ -307,16 +307,16 @@ proc analyseCase(c: var AnalysisCtx; n: PNode) = proc analyseIf(c: var AnalysisCtx; n: PNode) = analyse(c, n[0][0]) let oldFacts = c.guards.s.len - addFact(c.guards, canon(n[0][0], c.guards.o)) + addFact(c.guards, canon(n[0][0], c.graph.operators)) analyse(c, n[0][1]) for i in 1.. 1: - addFact(c.guards, canon(branch[0], c.guards.o)) + addFact(c.guards, canon(branch[0], c.graph.operators)) for i in 0.. 0: result = shallowCopy(n) for i in 0.. 0: @@ -482,7 +483,7 @@ proc liftParallel*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n: PNode): P checkArgs(a, body) var varSection = newNodeI(nkVarSection, n.info) - var temp = newSym(skTemp, getIdent(g.cache, "barrier"), nextId idgen, owner, n.info) + var temp = newSym(skTemp, getIdent(g.cache, "barrier"), nextSymId idgen, owner, n.info) temp.typ = magicsys.getCompilerProc(g, "Barrier").typ incl(temp.flags, sfFromGeneric) let tempNode = newSymNode(temp) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 35b1473c56..f269afe4cd 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -10,7 +10,7 @@ import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, wordrecg, strutils, options, guards, lineinfos, semfold, semdata, - modulegraphs, varpartitions, typeallowed + modulegraphs, varpartitions, typeallowed, nilcheck when defined(useDfa): import dfa @@ -70,7 +70,7 @@ type guards: TModel # nested guards locked: seq[PNode] # locked locations gcUnsafe, isRecursive, isTopLevel, hasSideEffect, inEnforcedGcSafe: bool - hasDangerousAssign: bool + hasDangerousAssign, isInnerProc: bool inEnforcedNoSideEffects: bool maxLockLevel, currLockLevel: TLockLevel currOptions: TOptions @@ -219,7 +219,7 @@ proc markGcUnsafe(a: PEffects; reason: PNode) = if reason.kind == nkSym: a.owner.gcUnsafetyReason = reason.sym else: - a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name, nextId a.c.idgen, + a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name, nextSymId a.c.idgen, a.owner, reason.info, {}) when true: @@ -269,6 +269,9 @@ proc useVarNoInitCheck(a: PEffects; n: PNode; s: PSym) = markSideEffect(a, s) else: markSideEffect(a, s) + if s.owner != a.owner and s.kind in {skVar, skLet, skForVar, skResult, skParam} and + {sfGlobal, sfThread} * s.flags == {}: + a.isInnerProc = true proc useVar(a: PEffects, n: PNode) = let s = n.sym @@ -723,7 +726,7 @@ proc checkLe(c: PEffects; a, b: PNode) = proc checkBounds(c: PEffects; arr, idx: PNode) = checkLe(c, lowBound(c.config, arr), idx) - checkLe(c, idx, highBound(c.config, arr, c.guards.o)) + checkLe(c, idx, highBound(c.config, arr, c.guards.g.operators)) proc checkRange(c: PEffects; value: PNode; typ: PType) = let t = typ.skipTypes(abstractInst - {tyRange}) @@ -818,9 +821,9 @@ proc trackCall(tracked: PEffects; n: PNode) = if opKind != -1: # rebind type bounds operations after createTypeBoundOps call let t = n[1].typ.skipTypes({tyAlias, tyVar}) - if a.sym != t.attachedOps[TTypeAttachedOp(opKind)]: + if a.sym != getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind)): createTypeBoundOps(tracked, t, n.info) - let op = t.attachedOps[TTypeAttachedOp(opKind)] + let op = getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind)) if op != nil: n[0].sym = op @@ -1236,7 +1239,7 @@ proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects; c: PC t.ownerModule = s.getModule t.init = @[] t.guards.s = @[] - t.guards.o = initOperators(g) + t.guards.g = g when defined(drnim): t.currOptions = g.config.options + s.options - {optStaticBoundsCheck} else: @@ -1252,6 +1255,15 @@ proc hasRealBody(s: PSym): bool = ## which is not a real implementation, refs #14314 result = {sfForward, sfImportc} * s.flags == {} +proc maybeWrappedInClosure(tracked: PEffects; t: PType): bool {.inline.} = + ## The spec does say when to produce destructors. However, the spec + ## was written in mind with the idea that "lambda lifting" already + ## happened. Not true in our implementation, so we need to workaround + ## here: + result = tracked.isInnerProc and + sfSystemModule notin tracked.c.module.flags and + tfCheckedForDestructor notin t.flags and containsGarbageCollectedRef(t) + proc trackProc*(c: PContext; s: PSym, body: PNode) = let g = c.graph var effects = s.typ.n[0] @@ -1270,7 +1282,8 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = let param = params[i].sym let typ = param.typ if isSinkTypeForParam(typ) or - (t.config.selectedGC in {gcArc, gcOrc} and isClosure(typ.skipTypes(abstractInst))): + (t.config.selectedGC in {gcArc, gcOrc} and + (isClosure(typ.skipTypes(abstractInst)) or maybeWrappedInClosure(t, typ))): createTypeBoundOps(t, typ, param.info) when false: if typ.kind == tyOut and param.id notin t.init: @@ -1310,7 +1323,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = var goals: set[Goal] = {} if strictFuncs in c.features: goals.incl constParameters if views in c.features: goals.incl borrowChecking - var partitions = computeGraphPartitions(s, body, g.config, goals) + var partitions = computeGraphPartitions(s, body, g, goals) if not t.hasSideEffect and t.hasDangerousAssign: t.hasSideEffect = varpartitions.hasSideEffect(partitions, mutationInfo) if views in c.features: @@ -1344,7 +1357,10 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = when defined(useDfa): if s.name.s == "testp": dataflowAnalysis(s, body) + when false: trackWrites(s, body) + if strictNotNil in c.features and s.kind == skProc: + checkNil(s, body, g.config, c.idgen) proc trackStmt*(c: PContext; module: PSym; n: PNode, isTopLevel: bool) = if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef, diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index b4026f3d73..a981034786 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -66,7 +66,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = x.info = n.info incl(s.flags, sfUsed) n[0] = x - suggestSym(c.config, x.info, s, c.graph.usageSym) + suggestSym(c.graph, x.info, s, c.graph.usageSym) onUse(x.info, s) else: localError(c.config, n.info, errInvalidControlFlowX % s.name.s) @@ -332,7 +332,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = discard result = n.info let info = getLineInfo(n) - suggestSym(c.config, info, result, c.graph.usageSym) + suggestSym(c.graph, info, result, c.graph.usageSym) proc checkNilable(c: PContext; v: PSym) = if {sfGlobal, sfImportc} * v.flags == {sfGlobal} and v.typ.requiresInit: @@ -410,7 +410,7 @@ proc fillPartialObject(c: PContext; n: PNode; typ: PType) = let y = considerQuotedIdent(c, n[1]) let obj = x.typ.skipTypes(abstractPtrs) if obj.kind == tyObject and tfPartial in obj.flags: - let field = newSym(skField, getIdent(c.cache, y.s), nextId c.idgen, obj.sym, n[1].info) + let field = newSym(skField, getIdent(c.cache, y.s), nextSymId c.idgen, obj.sym, n[1].info) field.typ = skipIntLit(typ, c.idgen) field.position = obj.n.len obj.n.add newSymNode(field) @@ -537,8 +537,6 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = typFlags.incl taConcept typeAllowedCheck(c, a.info, typ, symkind, typFlags) - when false: liftTypeBoundOps(c, typ, a.info) - instAllTypeBoundOp(c, a.info) var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink}) if a.kind == nkVarTuple: if tup.kind != tyTuple: @@ -863,10 +861,10 @@ proc handleForLoopMacro(c: PContext; n: PNode; flags: TExprFlags): PNode = proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode = # n[0] has been sem'checked and has a type. We use this to resolve - # 'match(n[0])' but then we pass 'n' to the 'match' macro. This seems to + # '`case`(n[0])' but then we pass 'n' to the `case` macro. This seems to # be the best solution. var toResolve = newNodeI(nkCall, n.info) - toResolve.add newIdentNode(getIdent(c.cache, "match"), n.info) + toResolve.add newIdentNode(getIdent(c.cache, "case"), n.info) toResolve.add n[0] var errors: CandidateErrors @@ -877,7 +875,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode = markUsed(c, n[0].info, match) onUse(n[0].info, match) - # but pass 'n' to the 'match' macro, not 'n[0]': + # but pass 'n' to the `case` macro, not 'n[0]': r.call[1] = n let toExpand = semResolvedCall(c, r, r.call, {}) case match.kind @@ -1044,7 +1042,7 @@ proc typeSectionTypeName(c: PContext; n: PNode): PNode = if result.kind != nkSym: illFormedAst(n, c.config) proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = - let typeDef= typeSection[i] + let typeDef = typeSection[i] checkSonsLen(typeDef, 3, c.config) var name = typeDef[0] var s: PSym @@ -1055,14 +1053,14 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = if pkg.isNil or pkg.kind != skPackage: localError(c.config, name.info, "unknown package name: " & pkgName.s) else: - let typsym = pkg.tab.strTableGet(typName) + let typsym = c.graph.packageTypes.strTableGet(typName) if typsym.isNil: s = semIdentDef(c, name[1], skType) onDef(name[1].info, s) s.typ = newTypeS(tyObject, c) s.typ.sym = s s.flags.incl sfForward - pkg.tab.strTableAdd s + c.graph.packageTypes.strTableAdd s addInterfaceDecl(c, s) elif typsym.kind == skType and sfForward in typsym.flags: s = typsym @@ -1088,7 +1086,7 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = if not isTopLevel(c) or pkg.isNil: localError(c.config, name.info, "only top level types in a package can be 'package'") else: - let typsym = pkg.tab.strTableGet(s.name) + let typsym = c.graph.packageTypes.strTableGet(s.name) if typsym != nil: if sfForward notin typsym.flags or sfNoForward notin typsym.flags: typeCompleted(typsym) @@ -1239,10 +1237,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = var body = s.typ.lastSon if body.kind == tyObject: # erases all declared fields - when defined(nimNoNilSeqs): - body.n.sons = @[] - else: - body.n.sons = nil + body.n.sons = @[] popOwner(c) closeScope(c) @@ -1278,7 +1273,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = internalAssert c.config, st.lastSon.sym == nil incl st.flags, tfRefsAnonObj let obj = newSym(skType, getIdent(c.cache, s.name.s & ":ObjectType"), - nextId c.idgen, getCurrOwner(c), s.info) + nextSymId c.idgen, getCurrOwner(c), s.info) let symNode = newSymNode(obj) obj.ast = a.shallowCopy case a[0].kind @@ -1449,7 +1444,7 @@ proc addResult(c: PContext, n: PNode, t: PType, owner: TSymKind) = localError(c.config, n.info, "incorrect result proc symbol") c.p.resultSym = n[resultPos].sym else: - var s = newSym(skResult, getIdent(c.cache, "result"), nextId c.idgen, getCurrOwner(c), n.info) + var s = newSym(skResult, getIdent(c.cache, "result"), nextSymId c.idgen, getCurrOwner(c), n.info) s.typ = t incl(s.flags, sfUsed) c.p.resultSym = s @@ -1528,75 +1523,9 @@ proc semProcAnnotation(c: PContext, prc: PNode; return -proc setGenericParamsMisc(c: PContext; n: PNode): PNode = - let orig = n[genericParamsPos] - # we keep the original params around for better error messages, see - # issue https://github.com/nim-lang/Nim/issues/1713 - result = semGenericParamList(c, orig) - if n[miscPos].kind == nkEmpty: - n[miscPos] = newTree(nkBracket, c.graph.emptyNode, orig) - else: - n[miscPos][1] = orig - n[genericParamsPos] = result - -proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = - # XXX semProcAux should be good enough for this now, we will eventually - # remove semLambda - result = semProcAnnotation(c, n, lambdaPragmas) - if result != nil: return result - result = n - checkSonsLen(n, bodyPos + 1, c.config) - var s: PSym - if n[namePos].kind != nkSym: - s = newSym(skProc, c.cache.idAnon, nextId c.idgen, getCurrOwner(c), n.info) - s.ast = n - n[namePos] = newSymNode(s) - else: - s = n[namePos].sym - pushOwner(c, s) - openScope(c) - var gp: PNode - if n[genericParamsPos].kind != nkEmpty: - gp = setGenericParamsMisc(c, n) - else: - gp = newNodeI(nkGenericParams, n.info) - - if n[paramsPos].kind != nkEmpty: - semParamList(c, n[paramsPos], gp, s) - # paramsTypeCheck(c, s.typ) - if gp.len > 0 and n[genericParamsPos].kind == nkEmpty: - # we have a list of implicit type parameters: - n[genericParamsPos] = gp - else: - s.typ = newProcType(c, n.info) - if n[pragmasPos].kind != nkEmpty: - pragma(c, s, n[pragmasPos], lambdaPragmas) - s.options = c.config.options - if n[bodyPos].kind != nkEmpty: - if sfImportc in s.flags: - localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s) - #if efDetermineType notin flags: - # XXX not good enough; see tnamedparamanonproc.nim - if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags): - pushProcCon(c, s) - addResult(c, n, s.typ[0], skProc) - s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos])) - trackProc(c, s, s.ast[bodyPos]) - popProcCon(c) - elif efOperand notin flags: - localError(c.config, n.info, errGenericLambdaNotAllowed) - sideEffectsCheck(c, s) - else: - localError(c.config, n.info, errImplOfXexpected % s.name.s) - closeScope(c) # close scope for parameters - popOwner(c) - result.typ = s.typ - if optOwnedRefs in c.config.globalOptions: - result.typ = makeVarType(c, result.typ, tyOwned) - proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode {.nosinks.} = + ## used for resolving 'auto' in lambdas based on their callsite var n = n - let original = n[namePos].sym let s = original #copySym(original, false) #incl(s.flags, sfFromGeneric) @@ -1695,12 +1624,13 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) = else: break if obj.kind in {tyObject, tyDistinct, tySequence, tyString}: obj = canonType(c, obj) - if obj.attachedOps[op] == s: + let ao = getAttachedOp(c.graph, obj, op) + if ao == s: discard "forward declared destructor" - elif obj.attachedOps[op].isNil and tfCheckedForDestructor notin obj.flags: - obj.attachedOps[op] = s + elif ao.isNil and tfCheckedForDestructor notin obj.flags: + setAttachedOp(c.graph, c.module.position, obj, op, s) else: - prevDestructor(c, obj.attachedOps[op], obj, n.info) + prevDestructor(c, ao, obj, n.info) noError = true if obj.owner.getModule != s.getModule: localError(c.config, n.info, errGenerated, @@ -1728,7 +1658,8 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = elif t.kind == tyGenericInvocation: t = t[0] else: break if t.kind in {tyObject, tyDistinct, tyEnum, tySequence, tyString}: - if t.attachedOps[attachedDeepCopy].isNil: t.attachedOps[attachedDeepCopy] = s + if getAttachedOp(c.graph, t, attachedDeepCopy).isNil: + setAttachedOp(c.graph, c.module.position, t, attachedDeepCopy, s) else: localError(c.config, n.info, errGenerated, "cannot bind another 'deepCopy' to: " & typeToString(t)) @@ -1768,12 +1699,13 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = obj = canonType(c, obj) #echo "ATTACHING TO ", obj.id, " ", s.name.s, " ", cast[int](obj) let k = if name == "=" or name == "=copy": attachedAsgn else: attachedSink - if obj.attachedOps[k] == s: + let ao = getAttachedOp(c.graph, obj, k) + if ao == s: discard "forward declared op" - elif obj.attachedOps[k].isNil and tfCheckedForDestructor notin obj.flags: - obj.attachedOps[k] = s + elif ao.isNil and tfCheckedForDestructor notin obj.flags: + setAttachedOp(c.graph, c.module.position, obj, k, s) else: - prevDestructor(c, obj.attachedOps[k], obj, n.info) + prevDestructor(c, ao, obj, n.info) if obj.owner.getModule != s.getModule: localError(c.config, n.info, errGenerated, "type bound operation `" & name & "` can be defined only in the same module with its type (" & obj.typeToString() & ")") @@ -1800,11 +1732,6 @@ proc cursorInProc(conf: ConfigRef; n: PNode): bool = if n.info.fileIndex == conf.m.trackPos.fileIndex: result = cursorInProcAux(conf, n) -type - TProcCompilationSteps = enum - stepRegisterSymbol, - stepDetermineType, - proc hasObjParam(s: PSym): bool = var t = s.typ for col in 1.. 0: - if n[genericParamsPos].kind == nkEmpty: - # we have a list of implicit type parameters: - n[genericParamsPos] = gp - # check for semantics again: - # semParamList(c, n[ParamsPos], nil, s) + semParamList(c, n[paramsPos], n[genericParamsPos], s) + # we maybe have implicit type parameters: else: s.typ = newProcType(c, n.info) + + if n[genericParamsPos].safeLen == 0: + # if there exist no explicit or implicit generic parameters, then this is + # at most a nullary generic (generic with no type params). Regardless of + # whether it's a nullary generic or non-generic, we restore the original. + # In the case of `nkEmpty` it's non-generic and an empty `nkGeneircParams` + # is a nullary generic. + # + # Remarks about nullary generics vs non-generics: + # The difference between a non-generic and nullary generic is minor in + # most cases but there are subtle and significant differences as well. + # Due to instantiation that generic procs go through, a static echo in the + # body of a nullary generic will not be executed immediately, as it's + # instantiated and not immediately evaluated. + n[genericParamsPos] = n[miscPos][1] + n[miscPos] = c.graph.emptyNode + if tfTriggersCompileTime in s.typ.flags: incl(s.flags, sfCompileTime) if n[patternPos].kind != nkEmpty: n[patternPos] = semPattern(c, n[patternPos]) @@ -1910,56 +1867,75 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, elif s.kind == skFunc: incl(s.flags, sfNoSideEffect) incl(s.typ.flags, tfNoSideEffect) - var (proto, comesFromShadowScope) = if isAnon: (nil, false) - else: searchForProc(c, oldScope, s) + + var (proto, comesFromShadowScope) = + if isAnon: (nil, false) + else: searchForProc(c, delcarationScope, s) if proto == nil and sfForward in s.flags: - #This is a definition that shares its sym with its forward declaration (generated by a macro), - #if the symbol is also gensymmed we won't find it with searchForProc, so we check here + ## In cases such as a macro generating a proc with a gensymmed name we + ## know `searchForProc` will not find it and sfForward will be set. In + ## such scenarios the sym is shared between forward declaration and we + ## can treat the `s` as the proto. proto = s - if proto == nil: - if s.kind == skIterator: - if s.typ.callConv != ccClosure: - s.typ.callConv = if isAnon: ccClosure else: ccInline - else: - s.typ.callConv = lastOptionEntry(c).defaultCC - # add it here, so that recursive procs are possible: - if sfGenSym in s.flags: - if s.owner == nil: s.owner = getCurrOwner(c) - elif kind in OverloadableSyms: - if not typeIsDetermined: - addInterfaceOverloadableSymAt(c, oldScope, s) - else: - if not typeIsDetermined: - addInterfaceDeclAt(c, oldScope, s) - if n[pragmasPos].kind != nkEmpty: - pragma(c, s, n[pragmasPos], validPragmas) - else: - implicitPragmas(c, s, n, validPragmas) - styleCheckDef(c.config, s) - onDef(n[namePos].info, s) + let hasProto = proto != nil + + # set the default calling conventions + case s.kind + of skIterator: + if s.typ.callConv != ccClosure: + s.typ.callConv = if isAnon: ccClosure else: ccInline + of skMacro, skTemplate: + # we don't bother setting calling conventions for macros and templates + discard else: - if n[pragmasPos].kind != nkEmpty: - pragma(c, s, n[pragmasPos], validPragmas) - # To ease macro generation that produce forwarded .async procs we now - # allow a bit redundancy in the pragma declarations. The rule is - # a prototype's pragma list must be a superset of the current pragma - # list. - # XXX This needs more checks eventually, for example that external - # linking names do agree: - if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags: - localError(c.config, n[pragmasPos].info, errPragmaOnlyInHeaderOfProcX % - ("'" & proto.name.s & "' from " & c.config$proto.info)) - styleCheckDef(c.config, s) + # NB: procs with a forward decl have theirs determined by the forward decl + if not hasProto: + # in this case we're either a forward declaration or we're an impl without + # a forward decl. We set the calling convention or will be set during + # pragma analysis further down. + s.typ.callConv = lastOptionEntry(c).defaultCC + + if not hasProto and sfGenSym notin s.flags: #and not isAnon: + if s.kind in OverloadableSyms: + addInterfaceOverloadableSymAt(c, delcarationScope, s) + else: + addInterfaceDeclAt(c, delcarationScope, s) + + pragmaCallable(c, s, n, validPragmas) + if not hasProto: + implicitPragmas(c, s, n.info, validPragmas) + + # To ease macro generation that produce forwarded .async procs we now + # allow a bit redundancy in the pragma declarations. The rule is + # a prototype's pragma list must be a superset of the current pragma + # list. + # XXX This needs more checks eventually, for example that external + # linking names do agree: + if hasProto and ( + # calling convention mismatch + tfExplicitCallConv in s.typ.flags and proto.typ.callConv != s.typ.callConv or + # implementation has additional pragmas + proto.typ.flags < s.typ.flags): + localError(c.config, n[pragmasPos].info, errPragmaOnlyInHeaderOfProcX % + ("'" & proto.name.s & "' from " & c.config$proto.info & + " '" & s.name.s & "' from " & c.config$s.info)) + + styleCheckDef(c.config, s) + if hasProto: onDefResolveForward(n[namePos].info, proto) + else: + onDef(n[namePos].info, s) + + if hasProto: if sfForward notin proto.flags and proto.magic == mNone: wrongRedefinition(c, n.info, proto.name.s, proto.info) if not comesFromShadowScope: excl(proto.flags, sfForward) incl(proto.flags, sfWasForwarded) - suggestSym(c.config, s.info, proto, c.graph.usageSym) + suggestSym(c.graph, s.info, proto, c.graph.usageSym) closeScope(c) # close scope with wrong parameter symbols openScope(c) # open scope for old (correct) parameter symbols - if proto.ast[genericParamsPos].kind != nkEmpty: + if proto.ast[genericParamsPos].isGenericParams: addGenericParamListToScope(c, proto.ast[genericParamsPos]) addParams(c, proto.typ.n, proto.kind) proto.info = s.info # more accurate line information @@ -1976,31 +1952,42 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, popOwner(c) pushOwner(c, s) - if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n) - if s.name.s[0] in {'.', '('}: - if s.name.s in [".", ".()", ".="] and {Feature.destructor, dotOperators} * c.features == {}: - localError(c.config, n.info, "the overloaded " & s.name.s & - " operator has to be enabled with {.experimental: \"dotOperators\".}") - elif s.name.s == "()" and callOperator notin c.features: - localError(c.config, n.info, "the overloaded " & s.name.s & - " operator has to be enabled with {.experimental: \"callOperator\".}") + if not isAnon: + if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n) + elif s.name.s[0] in {'.', '('}: + if s.name.s in [".", ".()", ".="] and {Feature.destructor, dotOperators} * c.features == {}: + localError(c.config, n.info, "the overloaded " & s.name.s & + " operator has to be enabled with {.experimental: \"dotOperators\".}") + elif s.name.s == "()" and callOperator notin c.features: + localError(c.config, n.info, "the overloaded " & s.name.s & + " operator has to be enabled with {.experimental: \"callOperator\".}") if n[bodyPos].kind != nkEmpty and sfError notin s.flags: # for DLL generation we allow sfImportc to have a body, for use in VM if sfBorrow in s.flags: localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s) - let usePseudoGenerics = kind in {skMacro, skTemplate} - # Macros and Templates can have generic parameters, but they are - # only used for overload resolution (there is no instantiation of - # the symbol, so we must process the body now) - if not usePseudoGenerics and c.config.ideCmd in {ideSug, ideCon} and not + if c.config.ideCmd in {ideSug, ideCon} and s.kind notin {skMacro, skTemplate} and not cursorInProc(c.config, n[bodyPos]): - discard "speed up nimsuggest" + # speed up nimsuggest if s.kind == skMethod: semMethodPrototype(c, s, n) + elif isAnon: + let gp = n[genericParamsPos] + if gp.kind == nkEmpty or (gp.len == 1 and tfRetType in gp[0].typ.flags): + # absolutely no generics (empty) or a single generic return type are + # allowed, everything else, including a nullary generic is an error. + pushProcCon(c, s) + addResult(c, n, s.typ[0], skProc) + s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos])) + trackProc(c, s, s.ast[bodyPos]) + popProcCon(c) + elif efOperand notin flags: + localError(c.config, n.info, errGenericLambdaNotAllowed) else: pushProcCon(c, s) - if n[genericParamsPos].kind == nkEmpty or usePseudoGenerics: - if not usePseudoGenerics and s.magic == mNone: paramsTypeCheck(c, s.typ) + if n[genericParamsPos].kind == nkEmpty or s.kind in {skMacro, skTemplate}: + # Macros and Templates can have generic parameters, but they are only + # used for overload resolution (there is no instantiation of the symbol) + if s.kind notin {skMacro, skTemplate} and s.magic == mNone: paramsTypeCheck(c, s.typ) maybeAddResult(c, s, n) # semantic checking also needed with importc in case used in VM @@ -2008,30 +1995,26 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # unfortunately we cannot skip this step when in 'system.compiles' # context as it may even be evaluated in 'system.compiles': trackProc(c, s, s.ast[bodyPos]) - if s.kind == skMethod: semMethodPrototype(c, s, n) else: - if (s.typ[0] != nil and kind != skIterator) or kind == skMacro: - addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nextId c.idgen, nil, n.info)) + if (s.typ[0] != nil and s.kind != skIterator): + addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nextSymId c.idgen, nil, n.info)) openScope(c) n[bodyPos] = semGenericStmt(c, n[bodyPos]) closeScope(c) if s.magic == mNone: fixupInstantiatedSymbols(c, s) - if s.kind == skMethod: semMethodPrototype(c, s, n) - if sfImportc in s.flags: - # don't ignore the body in case used in VM - # n[bodyPos] = c.graph.emptyNode - discard + if s.kind == skMethod: semMethodPrototype(c, s, n) popProcCon(c) else: - if s.kind in {skProc, skFunc} and s.typ[0] != nil and s.typ[0].kind == tyUntyped: - # `auto` is represented as `tyUntyped` at this point in compilation. - localError(c.config, n[paramsPos][0].info, "return type 'auto' cannot be used in forward declarations") - if s.kind == skMethod: semMethodPrototype(c, s, n) - if proto != nil: localError(c.config, n.info, errImplOfXexpected % proto.name.s) + if hasProto: localError(c.config, n.info, errImplOfXexpected % proto.name.s) if {sfImportc, sfBorrow, sfError} * s.flags == {} and s.magic == mNone: + # this is a forward declaration and we're building the prototype + if s.kind in {skProc, skFunc} and s.typ[0] != nil and s.typ[0].kind == tyUntyped: + # `auto` is represented as `tyUntyped` at this point in compilation. + localError(c.config, n[paramsPos][0].info, "return type 'auto' cannot be used in forward declarations") + incl(s.flags, sfForward) incl(s.flags, sfWasForwarded) elif sfBorrow in s.flags: semBorrow(c, n, s) @@ -2046,15 +2029,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, result.typ = s.typ if optOwnedRefs in c.config.globalOptions: result.typ = makeVarType(c, result.typ, tyOwned) - if isTopLevel(c) and s.kind != skIterator and - s.typ.callConv == ccClosure: + elif isTopLevel(c) and s.kind != skIterator and s.typ.callConv == ccClosure: localError(c.config, s.info, "'.closure' calling convention for top level routines is invalid") proc determineType(c: PContext, s: PSym) = if s.typ != nil: return #if s.magic != mNone: return #if s.ast.isNil: return - discard semProcAux(c, s.ast, s.kind, {}, stepDetermineType) + discard semProcAux(c, s.ast, s.kind, {}) proc semIterator(c: PContext, n: PNode): PNode = # gensym'ed iterator? @@ -2078,7 +2060,7 @@ proc semIterator(c: PContext, n: PNode): PNode = incl(s.typ.flags, tfCapturesEnv) else: s.typ.callConv = ccInline - if n[bodyPos].kind == nkEmpty and s.magic == mNone: + if n[bodyPos].kind == nkEmpty and s.magic == mNone and c.inConceptDecl == 0: localError(c.config, n.info, errImplOfXexpected % s.name.s) if optOwnedRefs in c.config.globalOptions and result.typ != nil: result.typ = makeVarType(c, result.typ, tyOwned) @@ -2088,7 +2070,9 @@ proc semProc(c: PContext, n: PNode): PNode = result = semProcAux(c, n, skProc, procPragmas) proc semFunc(c: PContext, n: PNode): PNode = - result = semProcAux(c, n, skFunc, procPragmas) + let validPragmas = if n[namePos].kind != nkEmpty: procPragmas + else: lambdaPragmas + result = semProcAux(c, n, skFunc, validPragmas) proc semMethod(c: PContext, n: PNode): PNode = if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "method") @@ -2125,7 +2109,7 @@ proc semConverterDef(c: PContext, n: PNode): PNode = var t = s.typ if t[0] == nil: localError(c.config, n.info, errXNeedsReturnType % "converter") if t.len != 2: localError(c.config, n.info, "a converter takes exactly one argument") - addConverter(c, s) + addConverter(c, LazySym(sym: s)) proc semMacroDef(c: PContext, n: PNode): PNode = checkSonsLen(n, bodyPos + 1, c.config) @@ -2149,6 +2133,7 @@ proc semMacroDef(c: PContext, n: PNode): PNode = proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult: PNode) = var f = checkModuleName(c.config, it) if f != InvalidFileIdx: + addIncludeFileDep(c, f) if containsOrIncl(c.includedFiles, f.int): localError(c.config, n.info, errRecursiveDependencyX % toMsgFilename(c.config, f)) else: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 03bf1af924..4bb9f3e6be 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -86,6 +86,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule; a = nextOverloadIter(o, c, n) proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode = + result = copyNode(n) for i in 0.. 0: - if n[genericParamsPos].kind == nkEmpty: - # we have a list of implicit type parameters: - n[genericParamsPos] = gp + if gp.len > 0 and n[genericParamsPos].kind == nkEmpty: + # we have a list of implicit type parameters: + n[genericParamsPos] = gp else: s.typ = newTypeS(tyProc, c) # XXX why do we need tyTyped as a return type again? diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 827087c3df..dcab9a8842 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -140,7 +140,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = if result.sym != nil and sfExported in result.sym.flags: incl(e.flags, sfUsed) incl(e.flags, sfExported) - if not isPure: strTableAdd(c.module.tab, e) + if not isPure: exportSym(c, e) result.n.add symNode styleCheckDef(c.config, e) onDef(e.info, e) @@ -151,9 +151,10 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = wrongRedefinition(c, e.info, e.name.s, conflict.info) inc(counter) if isPure and sfExported in result.sym.flags: - addPureEnum(c, result.sym) + addPureEnum(c, LazySym(sym: result.sym)) if tfNotNil in e.typ.flags and not hasNull: result.flags.incl tfRequiresInit + setToStringProc(c.graph, result, genEnumToStrProc(result, n.info, c.graph, c.idgen)) proc semSet(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tySet, prev, c) @@ -199,7 +200,9 @@ proc semVarargs(c: PContext, n: PNode, prev: PType): PType = proc semVarOutType(c: PContext, n: PNode, prev: PType; kind: TTypeKind): PType = if n.len == 1: result = newOrPrevType(kind, prev, c) - var base = semTypeNode(c, n[0], nil).skipTypes({tyTypeDesc}) + var base = semTypeNode(c, n[0], nil) + if base.kind == tyTypeDesc and not isSelf(base): + base = base[0] if base.kind == tyVar: localError(c.config, n.info, "type 'var var' is not allowed") base = base[0] @@ -387,7 +390,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = if result.typ.sym == nil: localError(c.config, n.info, errTypeExpected) return errorSym(c, n) - result = result.typ.sym.copySym(nextId c.idgen) + result = result.typ.sym.copySym(nextSymId c.idgen) result.typ = exactReplica(result.typ) result.typ.flags.incl tfUnresolved @@ -779,7 +782,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, n[i][1].info else: n[i].info - suggestSym(c.config, info, f, c.graph.usageSym) + suggestSym(c.graph, info, f, c.graph.usageSym) f.typ = typ f.position = pos f.options = c.config.options @@ -917,6 +920,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = # check every except the last is an object: for i in isCall.. 0: + if genericParams.isGenericParams: def = semGenericStmt(c, def) if hasUnresolvedArgs(c, def): def.typ = makeTypeFromExpr(c, def.copyTree) @@ -1335,7 +1348,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, r = skipIntLit(r, c.idgen) if kind == skIterator: # see tchainediterators - # in cases like iterator foo(it: iterator): type(it) + # in cases like iterator foo(it: iterator): typeof(it) # we don't need to change the return type to iter[T] result.flags.incl tfIterator # XXX Would be nice if we could get rid of this @@ -1348,7 +1361,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, result.flags.excl tfHasMeta result.n.typ = r - if genericParams != nil and genericParams.len > 0: + if genericParams.isGenericParams: for n in genericParams: if {sfUsed, sfAnon} * n.sym.flags == {}: result.flags.incl tfUnresolved @@ -1521,7 +1534,8 @@ proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType = proc freshType(c: PContext; res, prev: PType): PType {.inline.} = if prev.isNil: - result = copyType(res, nextId c.idgen, res.owner) + result = copyType(res, nextTypeId c.idgen, res.owner) + copyTypeProps(c.graph, c.idgen.module, result, res) else: result = res @@ -1536,6 +1550,12 @@ template modifierTypeKindOfNode(n: PNode): TTypeKind = proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = # if n.len == 0: return newConstraint(c, tyTypeClass) + if isNewStyleConcept(n): + result = newOrPrevType(tyConcept, prev, c) + result.flags.incl tfCheckedForDestructor + result.n = semConceptDeclaration(c, n) + return result + let pragmas = n[1] inherited = n[2] @@ -1563,6 +1583,8 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = if modifier != tyNone: dummyName = param[0] dummyType = c.makeTypeWithModifier(modifier, candidateTypeSlot) + # if modifier == tyRef: + # dummyType.flags.incl tfNotNil if modifier == tyTypeDesc: dummyType.flags.incl tfConceptMatchedTypeSym dummyType.flags.incl tfCheckedForDestructor @@ -1576,7 +1598,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = internalAssert c.config, dummyName.kind == nkIdent var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar, - dummyName.ident, nextId c.idgen, owner, param.info) + dummyName.ident, nextSymId c.idgen, owner, param.info) dummyParam.typ = dummyType incl dummyParam.flags, sfUsed addDecl(c, dummyParam) @@ -1644,7 +1666,7 @@ proc semProcTypeWithScope(c: PContext, n: PNode, # we construct a fake 'nkProcDef' for the 'mergePragmas' inside 'implicitPragmas'... s.ast = newTree(nkProcDef, newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info)) - implicitPragmas(c, s, n, {wTags, wRaises}) + implicitPragmas(c, s, n.info, {wTags, wRaises}) when useEffectSystem: setEffectsForProcType(c.graph, result, s.ast[pragmasPos]) closeScope(c) @@ -1690,7 +1712,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = case n.kind of nkEmpty: result = n.typ of nkTypeOfExpr: - # for ``type(countup(1,3))``, see ``tests/ttoseq``. + # for ``typeof(countup(1,3))``, see ``tests/ttoseq``. checkSonsLen(n, 1, c.config) result = semTypeof(c, n[0], prev) if result.kind == tyTypeDesc: result.flags.incl tfExplicit @@ -1747,9 +1769,11 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = if n[2].kind != nkNilLit: localError(c.config, n.info, "Invalid syntax. When used with a type, 'not' can be followed only by 'nil'") - if notnil notin c.features: + if notnil notin c.features and strictNotNil notin c.features: localError(c.config, n.info, - "enable the 'not nil' annotation with {.experimental: \"notnil\".}") + "enable the 'not nil' annotation with {.experimental: \"notnil\".} or " & + " the `strict not nil` annotation with {.experimental: \"strictNotNil\".} " & + " the \"notnil\" one is going to be deprecated, so please use \"strictNotNil\"") let resolvedType = result.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}) case resolvedType.kind of tyGenericParam, tyTypeDesc, tyFromExpr: @@ -1831,7 +1855,9 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of mExpr: result = semTypeNode(c, n[0], nil) if result != nil: - result = copyType(result, nextId c.idgen, getCurrOwner(c)) + let old = result + result = copyType(result, nextTypeId c.idgen, getCurrOwner(c)) + copyTypeProps(c.graph, c.idgen.module, result, old) for i in 1.. 0: newSons(result, n.len) @@ -279,7 +278,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym = var g: G[string] ]# - result = copySym(s, nextId cl.c.idgen) + result = copySym(s, nextSymId cl.c.idgen) incl(result.flags, sfFromGeneric) #idTablePut(cl.symMap, s, result) result.owner = s.owner @@ -305,7 +304,8 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType = if cl.allowMetaTypes: result = t.exactReplica else: - result = copyType(t, nextId(cl.c.idgen), t.owner) + result = copyType(t, nextTypeId(cl.c.idgen), t.owner) + copyTypeProps(cl.c.graph, cl.c.idgen.module, result, t) #cl.typeMap.topLayer.idTablePut(result, t) if cl.allowMetaTypes: return @@ -327,12 +327,12 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = var body = t[0] if body.kind != tyGenericBody: internalError(cl.c.config, cl.info, "no generic body") - var header: PType = t + var header = t # search for some instantiation here: if cl.allowMetaTypes: result = PType(idTableGet(cl.localCache, t)) else: - result = searchInstTypes(t) + result = searchInstTypes(cl.c.graph, t) if result != nil and sameFlags(result, t): when defined(reportCacheHits): @@ -351,7 +351,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = if header != t: # search again after first pass: - result = searchInstTypes(header) + result = searchInstTypes(cl.c.graph, header) if result != nil and sameFlags(result, t): when defined(reportCacheHits): echo "Generic instantiation cached ", typeToString(result), " for ", @@ -360,7 +360,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = else: header = instCopyType(cl, t) - result = newType(tyGenericInst, nextId(cl.c.idgen), t[0].owner) + result = newType(tyGenericInst, nextTypeId(cl.c.idgen), t[0].owner) result.flags = header.flags # be careful not to propagate unnecessary flags here (don't use rawAddSon) result.sons = @[header[0]] @@ -368,7 +368,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # we need to add the candidate here, before it's fully instantiated for # recursive instantions: if not cl.allowMetaTypes: - cacheTypeInst(result) + cacheTypeInst(cl.c, result) else: idTablePut(cl.localCache, t, result) @@ -408,13 +408,13 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = if newbody.isGenericAlias: newbody = newbody.skipGenericAlias rawAddSon(result, newbody) checkPartialConstructedType(cl.c.config, cl.info, newbody) - let dc = newbody.attachedOps[attachedDeepCopy] if not cl.allowMetaTypes: - if dc != nil and sfFromGeneric notin newbody.attachedOps[attachedDeepCopy].flags: + let dc = cl.c.graph.getAttachedOp(newbody, attachedDeepCopy) + if dc != nil and sfFromGeneric notin dc.flags: # 'deepCopy' needs to be instantiated for # generics *when the type is constructed*: - newbody.attachedOps[attachedDeepCopy] = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info, - attachedDeepCopy, 1) + cl.c.graph.setAttachedOp(cl.c.module.position, newbody, attachedDeepCopy, + cl.c.instTypeBoundOp(cl.c, dc, result, cl.info, attachedDeepCopy, 1)) if newbody.typeInst == nil: # doAssert newbody.typeInst == nil newbody.typeInst = result @@ -432,13 +432,11 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # adding myseq for myseq[system.int] # sigmatch: Formal myseq[=destroy.T] real myseq[system.int] #echo "DESTROY: adding ", typeToString(newbody), " for ", typeToString(result, preferDesc) - #cl.c.typesWithOps.add((newbody, result)) let mm = skipTypes(bbody, abstractPtrs) if tfFromGeneric notin mm.flags: # bug #5479, prevent endless recursions here: incl mm.flags, tfFromGeneric - let methods = mm.methods - for col, meth in items(methods): + for col, meth in methodsForGeneric(cl.c.graph, mm): # we instantiate the known methods belonging to that type, this causes # them to be registered and that's enough, so we 'discard' the result. discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info, @@ -509,7 +507,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = result = t if t == nil: return - if t.kind in {tyStatic, tyGenericParam} + tyTypeClasses: + if t.kind in {tyStatic, tyGenericParam, tyConcept} + tyTypeClasses: let lookup = cl.typeMap.lookup(t) if lookup != nil: return lookup @@ -642,23 +640,6 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = result.size = -1 result.n = replaceObjBranches(cl, result.n) -template typeBound(c, newty, oldty, field, info) = - let opr = newty.attachedOps[field] - if opr != nil and sfFromGeneric notin opr.flags: - # '=' needs to be instantiated for generics when the type is constructed: - #echo "DESTROY: instantiating ", astToStr(field), " for ", typeToString(oldty) - newty.attachedOps[field] = c.instTypeBoundOp(c, opr, oldty, info, attachedAsgn, 1) - -proc instAllTypeBoundOp*(c: PContext, info: TLineInfo) = - var i = 0 - while i < c.typesWithOps.len: - let (newty, oldty) = c.typesWithOps[i] - typeBound(c, newty, oldty, attachedDestructor, info) - typeBound(c, newty, oldty, attachedSink, info) - typeBound(c, newty, oldty, attachedAsgn, info) - inc i - setLen(c.typesWithOps, 0) - proc initTypeVars*(p: PContext, typeMap: LayeredIdTable, info: TLineInfo; owner: PSym): TReplTypeVars = initIdTable(result.symMap) diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 9a16cc3e07..156bc66d79 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -371,7 +371,7 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash = if sym.ast != nil: md5Init(c) c.md5Update(cast[cstring](result.addr), sizeof(result)) - hashBodyTree(graph, c, sym.ast[bodyPos]) + hashBodyTree(graph, c, getBody(graph, sym)) c.md5Final(result.MD5Digest) graph.symBodyHashes[sym.id] = result diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 94f290b999..87f7c273b1 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -13,7 +13,7 @@ import intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, magicsys, idents, lexer, options, parampatterns, strutils, trees, - linter, lineinfos, lowerings, modulegraphs + linter, lineinfos, lowerings, modulegraphs, concepts type MismatchKind* = enum @@ -363,7 +363,7 @@ proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType = of tySequence, tySet: if t[0].kind == tyEmpty: result = nil else: result = t - of tyGenericParam, tyAnything: + of tyGenericParam, tyAnything, tyConcept: result = t while true: result = PType(idTableGet(c.bindings, t)) @@ -556,19 +556,13 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation = proc allowsNil(f: PType): TTypeRelation {.inline.} = result = if tfNotNil notin f.flags: isSubtype else: isNone -proc allowsNilDeprecated(c: TCandidate, f: PType): TTypeRelation = - if optNilSeqs in c.c.config.options: - result = allowsNil(f) - else: - result = isNone - proc inconsistentVarTypes(f, a: PType): bool {.inline.} = result = f.kind != a.kind and (f.kind in {tyVar, tyLent, tySink} or a.kind in {tyVar, tyLent, tySink}) proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = ## For example we have: - ## + ## ## .. code-block:: nim ## proc myMap[T,S](sIn: seq[T], f: proc(x: T): S): seq[S] = ... ## proc innerProc[Q,W](q: Q): W = ... @@ -728,7 +722,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = if alreadyBound != nil: typ = alreadyBound template paramSym(kind): untyped = - newSym(kind, typeParamName, nextId(c.idgen), typeClass.sym, typeClass.sym.info, {}) + newSym(kind, typeParamName, nextSymId(c.idgen), typeClass.sym, typeClass.sym.info, {}) block addTypeParam: for prev in typeParams: @@ -741,7 +735,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = of tyStatic: param = paramSym skConst param.typ = typ.exactReplica - #copyType(typ, nextId(c.idgen), typ.owner) + #copyType(typ, nextTypeId(c.idgen), typ.owner) if typ.n == nil: param.typ.flags.incl tfInferrableStatic else: @@ -749,7 +743,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = of tyUnknown: param = paramSym skVar param.typ = typ.exactReplica - #copyType(typ, nextId(c.idgen), typ.owner) + #copyType(typ, nextTypeId(c.idgen), typ.owner) else: param = paramSym skType param.typ = if typ.isMetaType: @@ -801,7 +795,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = result = generateTypeInstance(c, m.bindings, typeClass.sym.info, ff) else: result = ff.exactReplica - #copyType(ff, nextId(c.idgen), ff.owner) + #copyType(ff, nextTypeId(c.idgen), ff.owner) result.n = checkedBody @@ -1300,7 +1294,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = isNone elif tfNotNil in f.flags and tfNotNil notin a.flags: result = isNilConversion - of tyNil: result = allowsNilDeprecated(c, f) + of tyNil: result = isNone else: discard of tyOrdinal: if isOrdinalType(a, allowEnumWithHoles = optNimV1Emulation in c.c.config.globalOptions): @@ -1396,7 +1390,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = isNilConversion else: result = isEqual - of tyNil: result = allowsNilDeprecated(c, f) + of tyNil: result = isNone else: discard of tyCString: # conversion from string to cstring is automatic: @@ -1505,8 +1499,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyGenericInvocation: var x = a.skipGenericAlias - - var preventHack = false + let concpt = f[0].skipTypes({tyGenericBody}) + var preventHack = concpt.kind == tyConcept if x.kind == tyOwned and f[0].kind != tyOwned: preventHack = true x = x.lastSon @@ -1533,6 +1527,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # Workaround for regression #4589 if f[i].kind != tyTypeDesc: return result = isGeneric + elif x.kind == tyGenericInst and concpt.kind == tyConcept: + result = if concepts.conceptMatch(c.c, concpt, x, c.bindings, f): isGeneric + else: isNone else: let genericBody = f[0] var askip = skippedNone @@ -1654,6 +1651,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, else: result = isNone + of tyConcept: + result = if concepts.conceptMatch(c.c, f, a, c.bindings, nil): isGeneric + else: isNone + of tyCompositeTypeClass: considerPreviousT: let roota = a.skipGenericAlias @@ -2500,7 +2501,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int noMatch() checkConstraint(n[a]) - if m.state == csMatch and not(m.calleeSym != nil and m.calleeSym.kind in {skTemplate, skMacro}): + if m.state == csMatch and not (m.calleeSym != nil and m.calleeSym.kind in {skTemplate, skMacro}): c.mergeShadowScope else: c.closeShadowScope diff --git a/compiler/sinkparameter_inference.nim b/compiler/sinkparameter_inference.nim index 841f2de8eb..fa9f2b445e 100644 --- a/compiler/sinkparameter_inference.nim +++ b/compiler/sinkparameter_inference.nim @@ -32,7 +32,7 @@ proc checkForSink*(config: ConfigRef; idgen: IdGenerator; owner: PSym; arg: PNod if sfWasForwarded notin owner.flags: let argType = arg.sym.typ - let sinkType = newType(tySink, nextId(idgen), owner) + let sinkType = newType(tySink, nextTypeId(idgen), owner) sinkType.size = argType.size sinkType.align = argType.align sinkType.paddingAtEnd = argType.paddingAtEnd diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 65e19b8db7..54ed51dbc8 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -55,7 +55,7 @@ proc typeNeedsNoDeepCopy(t: PType): bool = proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; idgen: IdGenerator; owner: PSym; typ: PType; v: PNode; useShallowCopy=false): PSym = - result = newSym(skTemp, getIdent(g.cache, genPrefix), nextId idgen, owner, varSection.info, + result = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId idgen, owner, varSection.info, owner.options) result.typ = typ incl(result.flags, sfFromGeneric) @@ -169,7 +169,7 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym; params.add threadParam.newSymNode params.add argsParam.newSymNode - var t = newType(tyProc, nextId idgen, threadParam.owner) + var t = newType(tyProc, nextTypeId idgen, threadParam.owner) t.rawAddSon nil t.rawAddSon threadParam.typ t.rawAddSon argsParam.typ @@ -189,7 +189,7 @@ proc createCastExpr(argsParam: PSym; objType: PType; idgen: IdGenerator): PNode result = newNodeI(nkCast, argsParam.info) result.add newNodeI(nkEmpty, argsParam.info) result.add newSymNode(argsParam) - result.typ = newType(tyPtr, nextId idgen, objType.owner) + result.typ = newType(tyPtr, nextTypeId idgen, objType.owner) result.typ.rawAddSon(objType) proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; @@ -211,7 +211,7 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; # localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure") let fieldname = if i < formals.len: formals[i].sym.name else: tmpName - var field = newSym(skField, fieldname, nextId idgen, objType.owner, n.info, g.config.options) + var field = newSym(skField, fieldname, nextSymId idgen, objType.owner, n.info, g.config.options) field.typ = argType objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i]) @@ -239,15 +239,15 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; # localError(n.info, "'spawn'ed function cannot refer to 'ref'/closure") let fieldname = if i < formals.len: formals[i].sym.name else: tmpName - var field = newSym(skField, fieldname, nextId idgen, objType.owner, n.info, g.config.options) + var field = newSym(skField, fieldname, nextSymId idgen, objType.owner, n.info, g.config.options) if argType.kind in {tyVarargs, tyOpenArray}: # important special case: we always create a zero-copy slice: let slice = newNodeI(nkCall, n.info, 4) slice.typ = n.typ - slice[0] = newSymNode(createMagic(g, "slice", mSlice)) + slice[0] = newSymNode(createMagic(g, idgen, "slice", mSlice)) slice[0].typ = getSysType(g, n.info, tyInt) # fake type - var fieldB = newSym(skField, tmpName, nextId idgen, objType.owner, n.info, g.config.options) + var fieldB = newSym(skField, tmpName, nextSymId idgen, objType.owner, n.info, g.config.options) fieldB.typ = getSysType(g, n.info, tyInt) objType.addField(fieldB, g.cache, idgen) @@ -257,7 +257,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) - var fieldA = newSym(skField, tmpName, nextId idgen, objType.owner, n.info, g.config.options) + var fieldA = newSym(skField, tmpName, nextSymId idgen, objType.owner, n.info, g.config.options) fieldA.typ = getSysType(g, n.info, tyInt) objType.addField(fieldA, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2]) @@ -332,9 +332,9 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp var fn = n[0] let name = (if fn.kind == nkSym: fn.sym.name.s else: genPrefix) & "Wrapper" - wrapperProc = newSym(skProc, getIdent(g.cache, name), nextId idgen, owner, fn.info, g.config.options) - threadParam = newSym(skParam, getIdent(g.cache, "thread"), nextId idgen, wrapperProc, n.info, g.config.options) - argsParam = newSym(skParam, getIdent(g.cache, "args"), nextId idgen, wrapperProc, n.info, g.config.options) + wrapperProc = newSym(skProc, getIdent(g.cache, name), nextSymId idgen, owner, fn.info, g.config.options) + threadParam = newSym(skParam, getIdent(g.cache, "thread"), nextSymId idgen, wrapperProc, n.info, g.config.options) + argsParam = newSym(skParam, getIdent(g.cache, "args"), nextSymId idgen, wrapperProc, n.info, g.config.options) wrapperProc.flags.incl sfInjectDestructors block: @@ -347,7 +347,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp incl(objType.flags, tfFinal) let castExpr = createCastExpr(argsParam, objType, idgen) - var scratchObj = newSym(skVar, getIdent(g.cache, "scratch"), nextId idgen, owner, n.info, g.config.options) + var scratchObj = newSym(skVar, getIdent(g.cache, "scratch"), nextSymId idgen, owner, n.info, g.config.options) block: scratchObj.typ = objType incl(scratchObj.flags, sfFromGeneric) @@ -364,7 +364,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp skFunc, skMethod, skConverter}): # for indirect calls we pass the function pointer in the scratchObj var argType = n[0].typ.skipTypes(abstractInst) - var field = newSym(skField, getIdent(g.cache, "fn"), nextId idgen, owner, n.info, g.config.options) + var field = newSym(skField, getIdent(g.cache, "fn"), nextSymId idgen, owner, n.info, g.config.options) field.typ = argType objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0]) @@ -386,9 +386,9 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp var barrierAsExpr: PNode = nil if barrier != nil: - let typ = newType(tyPtr, nextId idgen, owner) + let typ = newType(tyPtr, nextTypeId idgen, owner) typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ) - var field = newSym(skField, getIdent(g.cache, "barrier"), nextId idgen, owner, n.info, g.config.options) + var field = newSym(skField, getIdent(g.cache, "barrier"), nextSymId idgen, owner, n.info, g.config.options) field.typ = typ objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier) @@ -396,7 +396,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp var fvField, fvAsExpr: PNode = nil if spawnKind == srFlowVar: - var field = newSym(skField, getIdent(g.cache, "fv"), nextId idgen, owner, n.info, g.config.options) + var field = newSym(skField, getIdent(g.cache, "fv"), nextSymId idgen, owner, n.info, g.config.options) field.typ = retType objType.addField(field, g.cache, idgen) fvField = newDotExpr(scratchObj, field) @@ -407,8 +407,8 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField.info, fvField) elif spawnKind == srByVar: - var field = newSym(skField, getIdent(g.cache, "fv"), nextId idgen, owner, n.info, g.config.options) - field.typ = newType(tyPtr, nextId idgen, objType.owner) + var field = newSym(skField, getIdent(g.cache, "fv"), nextSymId idgen, owner, n.info, g.config.options) + field.typ = newType(tyPtr, nextTypeId idgen, objType.owner) field.typ.rawAddSon(retType) objType.addField(field, g.cache, idgen) fvAsExpr = indirectAccess(castExpr, field, n.info) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 186b23cd95..cad776015e 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -56,10 +56,10 @@ proc findDocComment(n: PNode): PNode = elif n.kind in {nkAsgn, nkFastAsgn} and n.len == 2: result = findDocComment(n[1]) -proc extractDocComment(s: PSym): string = +proc extractDocComment(g: ModuleGraph; s: PSym): string = var n = findDocComment(s.ast) if n.isNil and s.kind in routineKinds and s.ast != nil: - n = findDocComment(s.ast[bodyPos]) + n = findDocComment(getBody(g, s)) if not n.isNil: result = n.comment.replace("\n##", "\n").strip else: @@ -70,11 +70,11 @@ proc cmpSuggestions(a, b: Suggest): int = result = b.field.int - a.field.int if result != 0: return result - cf scope cf prefix + cf contextFits + cf scope # when the first type matches, it's better when it's a generic match: cf quality - cf contextFits cf localUsages cf globalUsages # if all is equal, sort alphabetically for deterministic output, @@ -117,7 +117,7 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int elif sourceIdent != ident: result = 0 -proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo; +proc symToSuggest(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo; quality: range[0..100]; prefix: PrefixMatch; inTypeContext: bool; scope: int; useSuppliedInfo = false): Suggest = @@ -136,7 +136,7 @@ proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info if u.fileIndex == info.fileIndex: inc c result.localUsages = c result.symkind = byte s.kind - if optIdeTerse notin conf.globalOptions: + if optIdeTerse notin g.config.globalOptions: result.qualifiedPath = @[] if not isLocal and s.kind != skModule: let ow = s.owner @@ -156,20 +156,20 @@ proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info else: result.forth = "" when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler): - result.doc = s.extractDocComment + result.doc = extractDocComment(g, s) let infox = if useSuppliedInfo or section in {ideUse, ideHighlight, ideOutline}: info else: s.info - result.filePath = toFullPath(conf, infox) + result.filePath = toFullPath(g.config, infox) result.line = toLinenumber(infox) result.column = toColumn(infox) - result.version = conf.suggestVersion + result.version = g.config.suggestVersion result.tokenLen = if section != ideHighlight: s.name.s.len else: - getTokenLenFromSource(conf, s.name.s, infox) + getTokenLenFromSource(g.config, s.name.s, infox) proc `$`*(suggest: Suggest): string = result = $suggest.section @@ -258,24 +258,29 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = result = true break -proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var Suggestions) = - var pm: PrefixMatch - if filterSym(s, f, pm) and fieldVisible(c, s): - outputs.add(symToSuggest(c.config, s, isLocal=true, ideSug, info, 100, pm, c.inTypeContext > 0, 0)) - proc getQuality(s: PSym): range[0..100] = + result = 100 if s.typ != nil and s.typ.len > 1: var exp = s.typ[1].skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink}) if exp.kind == tyVarargs: exp = elemType(exp) - if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: return 50 - return 100 + if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: result = 50 + + # penalize deprecated symbols + if sfDeprecated in s.flags: + result = result - 5 + +proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var Suggestions) = + var pm: PrefixMatch + if filterSym(s, f, pm) and fieldVisible(c, s): + outputs.add(symToSuggest(c.graph, s, isLocal=true, ideSug, info, + s.getQuality, pm, c.inTypeContext > 0, 0)) template wholeSymTab(cond, section: untyped) {.dirty.} = for (item, scopeN, isLocal) in allSyms(c): let it = item var pm: PrefixMatch if cond: - outputs.add(symToSuggest(c.config, it, isLocal = isLocal, section, info, getQuality(it), + outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, section, info, getQuality(it), pm, c.inTypeContext > 0, scopeN)) proc suggestSymList(c: PContext, list, f: PNode; info: TLineInfo, outputs: var Suggestions) = @@ -298,6 +303,7 @@ proc suggestObject(c: PContext, n, f: PNode; info: TLineInfo, outputs: var Sugge proc nameFits(c: PContext, s: PSym, n: PNode): bool = var op = if n.kind in nkCallKinds: n[0] else: n if op.kind in {nkOpenSymChoice, nkClosedSymChoice}: op = op[0] + if op.kind == nkDotExpr: op = op[1] var opr: PIdent case op.kind of nkSym: opr = op.sym.name @@ -346,8 +352,8 @@ proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) = for (it, scopeN, isLocal) in allSyms(c): var pm: PrefixMatch if filterSym(it, f, pm): - outputs.add(symToSuggest(c.config, it, isLocal = isLocal, ideSug, n.info, 0, pm, - c.inTypeContext > 0, scopeN)) + outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, ideSug, n.info, + it.getQuality, pm, c.inTypeContext > 0, scopeN)) proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) = # special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but @@ -365,11 +371,14 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) let m = c.graph.importModuleCallback(c.graph, c.module, fileInfoIdx(c.config, fullPath)) if m == nil: typ = nil else: - for it in items(n.sym.tab): + for it in allSyms(c.graph, n.sym): if filterSym(it, field, pm): - outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -100)) - outputs.add(symToSuggest(c.config, m, isLocal=false, ideMod, n.info, 100, PrefixMatch.None, - c.inTypeContext > 0, -99)) + outputs.add(symToSuggest(c.graph, it, isLocal=false, ideSug, + n.info, it.getQuality, pm, + c.inTypeContext > 0, -100)) + outputs.add(symToSuggest(c.graph, m, isLocal=false, ideMod, n.info, + 100, PrefixMatch.None, c.inTypeContext > 0, + -99)) if typ == nil: # a module symbol has no type for example: @@ -378,25 +387,29 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) # all symbols accessible, because we are in the current module: for it in items(c.topLevelScope.symbols): if filterSym(it, field, pm): - outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) + outputs.add(symToSuggest(c.graph, it, isLocal=false, ideSug, + n.info, it.getQuality, pm, + c.inTypeContext > 0, -99)) else: - for it in items(n.sym.tab): + for it in allSyms(c.graph, n.sym): if filterSym(it, field, pm): - outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) + outputs.add(symToSuggest(c.graph, it, isLocal=false, ideSug, + n.info, it.getQuality, pm, + c.inTypeContext > 0, -99)) else: # fallback: suggestEverything(c, n, field, outputs) - elif typ.kind == tyEnum and n.kind == nkSym and n.sym.kind == skType: - # look up if the identifier belongs to the enum: - var t = typ - while t != nil: - suggestSymList(c, t.n, field, n.info, outputs) - t = t[0] - suggestOperations(c, n, field, typ, outputs) else: - let orig = typ # skipTypes(typ, {tyGenericInst, tyAlias, tySink}) - typ = skipTypes(typ, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink, tyOwned}) - if typ.kind == tyObject: + let orig = typ + typ = skipTypes(orig, {tyTypeDesc, tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink, tyOwned}) + + if typ.kind == tyEnum and n.kind == nkSym and n.sym.kind == skType: + # look up if the identifier belongs to the enum: + var t = typ + while t != nil: + suggestSymList(c, t.n, field, n.info, outputs) + t = t[0] + elif typ.kind == tyObject: var t = typ while true: suggestObject(c, t.n, field, n.info, outputs) @@ -404,6 +417,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) t = skipTypes(t[0], skipPtrs) elif typ.kind == tyTuple and typ.n != nil: suggestSymList(c, typ.n, field, n.info, outputs) + suggestOperations(c, n, field, orig, outputs) if typ != orig: suggestOperations(c, n, field, typ, outputs) @@ -440,27 +454,27 @@ when defined(nimsuggest): if infoB.infoToInt == infoAsInt: return s.allUsages.add(info) -proc findUsages(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) = - if conf.suggestVersion == 1: - if usageSym == nil and isTracked(info, conf.m.trackPos, s.name.s.len): +proc findUsages(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym) = + if g.config.suggestVersion == 1: + if usageSym == nil and isTracked(info, g.config.m.trackPos, s.name.s.len): usageSym = s - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) + suggestResult(g.config, symToSuggest(g, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) elif s == usageSym: - if conf.lastLineInfo != info: - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) - conf.lastLineInfo = info + if g.config.lastLineInfo != info: + suggestResult(g.config, symToSuggest(g, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) + g.config.lastLineInfo = info when defined(nimsuggest): - proc listUsages*(conf: ConfigRef; s: PSym) = + proc listUsages*(g: ModuleGraph; s: PSym) = #echo "usages ", s.allUsages.len for info in s.allUsages: let x = if info == s.info and info.col == s.info.col: ideDef else: ideUse - suggestResult(conf, symToSuggest(conf, s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0)) + suggestResult(g.config, symToSuggest(g, s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0)) -proc findDefinition(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) = +proc findDefinition(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym) = if s.isNil: return - if isTracked(info, conf.m.trackPos, s.name.s.len) or (s == usageSym and sfForward notin s.flags): - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0, useSuppliedInfo = s == usageSym)) + if isTracked(info, g.config.m.trackPos, s.name.s.len) or (s == usageSym and sfForward notin s.flags): + suggestResult(g.config, symToSuggest(g, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0, useSuppliedInfo = s == usageSym)) if sfForward notin s.flags: suggestQuit() else: @@ -472,8 +486,9 @@ proc ensureIdx[T](x: var T, y: int) = proc ensureSeq[T](x: var seq[T]) = if x == nil: newSeq(x, 0) -proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} = +proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} = ## misnamed: should be 'symDeclared' + let conf = g.config when defined(nimsuggest): if conf.suggestVersion == 0: if s.allUsages.len == 0: @@ -482,18 +497,28 @@ proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym; s.addNoDup(info) if conf.ideCmd == ideUse: - findUsages(conf, info, s, usageSym) + findUsages(g, info, s, usageSym) elif conf.ideCmd == ideDef: - findDefinition(conf, info, s, usageSym) + findDefinition(g, info, s, usageSym) elif conf.ideCmd == ideDus and s != nil: if isTracked(info, conf.m.trackPos, s.name.s.len): - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) - findUsages(conf, info, s, usageSym) + suggestResult(conf, symToSuggest(g, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) + findUsages(g, info, s, usageSym) elif conf.ideCmd == ideHighlight and info.fileIndex == conf.m.trackPos.fileIndex: - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0)) - elif conf.ideCmd == ideOutline and info.fileIndex == conf.m.trackPos.fileIndex and - isDecl: - suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0)) + suggestResult(conf, symToSuggest(g, s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0)) + elif conf.ideCmd == ideOutline and isDecl: + # if a module is included then the info we have is inside the include and + # we need to walk up the owners until we find the outer most module, + # which will be the last skModule prior to an skPackage. + var + parentFileIndex = info.fileIndex # assume we're in the correct module + parentModule = s.owner + while parentModule != nil and parentModule.kind == skModule: + parentFileIndex = parentModule.info.fileIndex + parentModule = parentModule.owner + + if parentFileIndex == conf.m.trackPos.fileIndex: + suggestResult(conf, symToSuggest(g, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0)) proc extractPragma(s: PSym): PNode = if s.kind in routineKinds: @@ -562,7 +587,7 @@ proc markUsed(c: PContext; info: TLineInfo; s: PSym) = if sfError in s.flags: userError(conf, info, s) when defined(nimsuggest): - suggestSym(conf, info, s, c.graph.usageSym, false) + suggestSym(c.graph, info, s, c.graph.usageSym, false) if {optStyleHint, optStyleError} * conf.globalOptions != {}: styleCheckUse(conf, info, s) markOwnerModuleAsUsed(c, s) @@ -587,6 +612,11 @@ proc sugExpr(c: PContext, n: PNode, outputs: var Suggestions) = #if optIdeDebug in gGlobalOptions: # echo "expression ", renderTree(obj), " has type ", typeToString(obj.typ) #writeStackTrace() + elif n.kind == nkIdent: + let + prefix = if c.config.m.trackPosAttached: nil else: n + info = n.info + wholeSymTab(filterSym(it, prefix, pm), ideSug) else: let prefix = if c.config.m.trackPosAttached: nil else: n suggestEverything(c, n, prefix, outputs) @@ -648,8 +678,8 @@ proc suggestSentinel*(c: PContext) = for (it, scopeN, isLocal) in allSyms(c): var pm: PrefixMatch if filterSymNoOpr(it, nil, pm): - outputs.add(symToSuggest(c.config, it, isLocal = isLocal, ideSug, - newLineInfo(c.config.m.trackPos.fileIndex, 0, -1), 0, + outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, ideSug, + newLineInfo(c.config.m.trackPos.fileIndex, 0, -1), it.getQuality, PrefixMatch.None, false, scopeN)) dec(c.compilesContextId) diff --git a/compiler/transf.nim b/compiler/transf.nim index ae233d3224..d2d9156aab 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -87,7 +87,7 @@ proc getCurrOwner(c: PTransf): PSym = else: result = c.module proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode = - let r = newSym(skTemp, getIdent(c.graph.cache, genPrefix), nextId(c.idgen), getCurrOwner(c), info) + let r = newSym(skTemp, getIdent(c.graph.cache, genPrefix), nextSymId(c.idgen), getCurrOwner(c), info) r.typ = typ #skipTypes(typ, {tyGenericInst, tyAlias, tySink}) incl(r.flags, sfFromGeneric) let owner = getCurrOwner(c) @@ -126,7 +126,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = var tc = c.transCon if sfBorrow in s.flags and s.kind in routineKinds: # simply exchange the symbol: - b = s.getBody + b = getBody(c.graph, s) if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol") b = newSymNode(b.sym, n.info) elif c.inlining > 0: @@ -163,7 +163,7 @@ proc freshVar(c: PTransf; v: PSym): PNode = if owner.isIterator and not c.tooEarly: result = freshVarForClosureIter(c.graph, v, c.idgen, owner) else: - var newVar = copySym(v, nextId(c.idgen)) + var newVar = copySym(v, nextSymId(c.idgen)) incl(newVar.flags, sfFromGeneric) newVar.owner = owner result = newSymNode(newVar) @@ -233,7 +233,7 @@ proc hasContinue(n: PNode): bool = if hasContinue(n[i]): return true proc newLabel(c: PTransf, n: PNode): PSym = - result = newSym(skLabel, nil, nextId(c.idgen), getCurrOwner(c), n.info) + result = newSym(skLabel, nil, nextSymId(c.idgen), getCurrOwner(c), n.info) result.name = getIdent(c.graph.cache, genPrefix) proc transformBlock(c: PTransf, n: PNode): PNode = @@ -496,7 +496,7 @@ proc transformConv(c: PTransf, n: PNode): PNode = of tyOpenArray, tyVarargs: result = transform(c, n[1]) #result = transformSons(c, n) - result.typ = takeType(n.typ, n[1].typ, c.idgen) + result.typ = takeType(n.typ, n[1].typ, c.graph, c.idgen) #echo n.info, " came here and produced ", typeToString(result.typ), # " from ", typeToString(n.typ), " and ", typeToString(n[1].typ) of tyCString: @@ -524,6 +524,7 @@ proc transformConv(c: PTransf, n: PNode): PNode = result[0] = transform(c, n[1]) else: result = transform(c, n[1]) + result.typ = n.typ else: result = transformSons(c, n) of tyObject: @@ -536,6 +537,7 @@ proc transformConv(c: PTransf, n: PNode): PNode = result[0] = transform(c, n[1]) else: result = transform(c, n[1]) + result.typ = n.typ of tyGenericParam, tyOrdinal: result = transform(c, n[1]) # happens sometimes for generated assignments, etc. @@ -594,7 +596,7 @@ proc findWrongOwners(c: PTransf, n: PNode) = else: for i in 0..= low(int)) and (n.intVal <= high(int)): result = result !& int(n.intVal) @@ -33,6 +34,9 @@ proc hashTree(n: PNode): Hash = else: for i in 0..typedesc: typedesc is declared as such, and is 10x more common. "GenericInvocation", "GenericBody", "GenericInst", "GenericParam", "distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple", "set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc", @@ -550,7 +551,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result.add(']') of tyTypeDesc: if t[0].kind == tyNone: result = "typedesc" - else: result = "type " & typeToString(t[0]) + else: result = "typedesc[" & typeToString(t[0]) & "]" of tyStatic: if prefer == preferGenericArg and t.n != nil: result = t.n.renderTree @@ -895,8 +896,6 @@ proc initSameTypeClosure: TSameTypeClosure = proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool = result = c.s.len > 0 and c.s.contains((a.id, b.id)) if not result: - when not defined(nimNoNilSeqs): - if isNil(c.s): c.s = @[] c.s.add((a.id, b.id)) proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool @@ -1196,7 +1195,8 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = cycleCheck() result = sameTypeAux(a.lastSon, b.lastSon, c) of tyNone: result = false - of tyOptDeprecated: doAssert false + of tyConcept: + result = exprStructuralEquivalent(a.n, b.n) proc sameBackendType*(x, y: PType): bool = var c = initSameTypeClosure() @@ -1272,6 +1272,7 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]], a = a[i] result = a.kind == last + include sizealignoffsetimpl proc computeSize*(conf: ConfigRef; typ: PType): BiggestInt = @@ -1307,11 +1308,12 @@ proc containsGenericTypeIter(t: PType, closure: RootRef): bool = proc containsGenericType*(t: PType): bool = result = iterOverType(t, containsGenericTypeIter, nil) -proc baseOfDistinct*(t: PType; idgen: IdGenerator): PType = +proc baseOfDistinct*(t: PType; g: ModuleGraph; idgen: IdGenerator): PType = if t.kind == tyDistinct: result = t[0] else: - result = copyType(t, nextId idgen, t.owner) + result = copyType(t, nextTypeId idgen, t.owner) + copyTypeProps(g, idgen.module, result, t) var parent: PType = nil var it = result while it.kind in {tyPtr, tyRef, tyOwned}: @@ -1449,7 +1451,7 @@ proc isEmptyContainer*(t: PType): bool = of tyGenericInst, tyAlias, tySink: result = isEmptyContainer(t.lastSon) else: result = false -proc takeType*(formal, arg: PType; idgen: IdGenerator): PType = +proc takeType*(formal, arg: PType; g: ModuleGraph; idgen: IdGenerator): PType = # param: openArray[string] = [] # [] is an array constructor of length 0 of type string! if arg.kind == tyNil: @@ -1457,7 +1459,8 @@ proc takeType*(formal, arg: PType; idgen: IdGenerator): PType = result = formal elif formal.kind in {tyOpenArray, tyVarargs, tySequence} and arg.isEmptyContainer: - let a = copyType(arg.skipTypes({tyGenericInst, tyAlias}), nextId(idgen), arg.owner) + let a = copyType(arg.skipTypes({tyGenericInst, tyAlias}), nextTypeId(idgen), arg.owner) + copyTypeProps(g, idgen.module, a, arg) a[ord(arg.kind == tyArray)] = formal[0] result = a elif formal.kind in {tyTuple, tySet} and arg.kind == formal.kind: @@ -1465,14 +1468,14 @@ proc takeType*(formal, arg: PType; idgen: IdGenerator): PType = else: result = arg -proc skipHiddenSubConv*(n: PNode; idgen: IdGenerator): PNode = +proc skipHiddenSubConv*(n: PNode; g: ModuleGraph; idgen: IdGenerator): PNode = if n.kind == nkHiddenSubConv: # param: openArray[string] = [] # [] is an array constructor of length 0 of type string! let formal = n.typ result = n[1] let arg = result.typ - let dest = takeType(formal, arg, idgen) + let dest = takeType(formal, arg, g, idgen) if dest == arg and formal.kind != tyUntyped: #echo n.info, " came here for ", formal.typeToString result = n diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 63c18d94af..7bb626c0a5 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -28,7 +28,7 @@ ## See https://nim-lang.github.io/Nim/manual_experimental.html#view-types-algorithm ## for a high-level description of how borrow checking works. -import ast, types, lineinfos, options, msgs, renderer, typeallowed +import ast, types, lineinfos, options, msgs, renderer, typeallowed, modulegraphs from trees import getMagic, isNoSideEffectPragma, stupidStmtListExpr from isolation_check import canAlias @@ -57,6 +57,7 @@ type ownsData, preventCursor, isReassigned, + isConditionallyReassigned, viewDoesMutate, viewBorrowsFromConst @@ -98,8 +99,9 @@ type goals: set[Goal] unanalysableMutation: bool inAsgnSource, inConstructor, inNoSideEffectSection: int + inConditional, inLoop: int owner: PSym - config: ConfigRef + g: ModuleGraph proc mutationAfterConnection(g: MutationInfo): bool {.inline.} = #echo g.maxMutation.int, " ", g.minConnection.int, " ", g.param @@ -509,11 +511,11 @@ proc borrowFrom(c: var Partitions; dest: PSym; src: PNode) = let s = pathExpr(src, c.owner) if s == nil: - localError(c.config, src.info, "cannot borrow from " & $src & ", it is not a path expression; " & url) + localError(c.g.config, src.info, "cannot borrow from " & $src & ", it is not a path expression; " & url) elif s.kind == nkSym: if dest.kind == skResult: if s.sym.kind != skParam or s.sym.position != 0: - localError(c.config, src.info, "'result' must borrow from the first parameter") + localError(c.g.config, src.info, "'result' must borrow from the first parameter") let vid = variableId(c, dest) if vid >= 0: @@ -539,13 +541,13 @@ proc borrowingCall(c: var Partitions; destType: PType; n: PNode; i: int) = when false: let isView = directViewType(destType) == immutableView if n[0].kind == nkSym and n[0].sym.name.s == "[]=": - localError(c.config, n[i].info, "attempt to mutate an immutable view") + localError(c.g.config, n[i].info, "attempt to mutate an immutable view") for j in i+1.. 0 and c.inLoop > 0: + # bug #17033: live ranges with loops and conditionals are too + # complex for our current analysis, so we prevent the cursorfication. + c.s[vid].flags.incl isConditionallyReassigned + proc computeLiveRanges(c: var Partitions; n: PNode) = # first pass: Compute live ranges for locals. # **Watch out!** We must traverse the tree like 'traverse' does @@ -777,7 +787,7 @@ proc computeLiveRanges(c: var Partitions; n: PNode) = if n[1].kind == nkSym and (c.s[vid].reassignedTo == 0 or c.s[vid].reassignedTo == n[1].sym.id): c.s[vid].reassignedTo = n[1].sym.id else: - c.s[vid].flags.incl isReassigned + markAsReassigned(c, vid) of nkSym: dec c.abstractTime @@ -804,7 +814,7 @@ proc computeLiveRanges(c: var Partitions; n: PNode) = if not paramType.isCompileTimeOnly and paramType.kind == tyVar: let vid = variableId(c, it.sym) if vid >= 0: - c.s[vid].flags.incl isReassigned + markAsReassigned(c, vid) of nkAddr, nkHiddenAddr: computeLiveRanges(c, n[0]) @@ -822,12 +832,18 @@ proc computeLiveRanges(c: var Partitions; n: PNode) = # while cond: # mutate(graph) # connect(graph, cursorVar) + inc c.inLoop for child in n: computeLiveRanges(c, child) + inc c.inLoop + of nkElifBranch, nkElifExpr, nkElse, nkOfBranch: + inc c.inConditional + for child in n: computeLiveRanges(c, child) + dec c.inConditional else: for child in n: computeLiveRanges(c, child) -proc computeGraphPartitions*(s: PSym; n: PNode; config: ConfigRef; goals: set[Goal]): Partitions = - result = Partitions(owner: s, config: config, goals: goals) +proc computeGraphPartitions*(s: PSym; n: PNode; g: ModuleGraph; goals: set[Goal]): Partitions = + result = Partitions(owner: s, g: g, goals: goals) if s.kind notin {skModule, skMacro}: let params = s.typ.n for i in 1.. ord(high(TSymKind)): internalError(c.config, c.debug[pc], "request to create symbol of invalid kind") - var sym = newSym(k.TSymKind, getIdent(c.cache, name), nextId c.idgen, c.module.owner, c.debug[pc]) + var sym = newSym(k.TSymKind, getIdent(c.cache, name), nextSymId c.idgen, c.module.owner, c.debug[pc]) incl(sym.flags, sfGenSym) regs[ra].node = newSymNode(sym) regs[ra].node.flags.incl nfIsRef @@ -2088,8 +2097,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = inc pc let typ = c.types[c.code[pc].regBx - wordExcess] createStrKeepNode(regs[ra]) - when not defined(nimNoNilSeqs): - if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000) storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode, c.config) c.profiler.leave(c) @@ -2184,7 +2191,7 @@ const evalPass* = makePass(myOpen, myProcess, myClose) proc evalConstExprAux(module: PSym; idgen: IdGenerator; g: ModuleGraph; prc: PSym, n: PNode, mode: TEvalMode): PNode = - if g.config.errorCounter > 0: return n + #if g.config.errorCounter > 0: return n let n = transformExpr(g, idgen, module, n) setupGlobalCtx(module, g, idgen) var c = PCtx g.vm @@ -2257,12 +2264,12 @@ const evalMacroLimit = 1000 proc errorNode(idgen: IdGenerator; owner: PSym, n: PNode): PNode = result = newNodeI(nkEmpty, n.info) - result.typ = newType(tyError, nextId idgen, owner) + result.typ = newType(tyError, nextTypeId idgen, owner) result.typ.flags.incl tfCheckedForDestructor proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstCounter: ref int; n, nOrig: PNode, sym: PSym): PNode = - if g.config.errorCounter > 0: return errorNode(idgen, module, n) + #if g.config.errorCounter > 0: return errorNode(idgen, module, n) # XXX globalError() is ugly here, but I don't know a better solution for now inc(g.config.evalMacroCounter) diff --git a/compiler/vmconv.nim b/compiler/vmconv.nim index 7db3906c20..b82fb2ff31 100644 --- a/compiler/vmconv.nim +++ b/compiler/vmconv.nim @@ -28,6 +28,10 @@ proc toLit*[T](a: T): PNode = elif T is tuple: result = newTree(nkTupleConstr) for ai in fields(a): result.add toLit(ai) + elif T is seq: + result = newNode(nkBracket) + for ai in a: + result.add toLit(ai) elif T is object: result = newTree(nkObjConstr) result.add(newNode(nkEmpty)) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 6d6c552508..e8b5cdda9a 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -86,6 +86,7 @@ type opcSubImmInt, opcLenSeq, opcLenStr, + opcLenCstring, opcIncl, opcInclRange, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt, opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, @@ -264,6 +265,7 @@ type oldErrorCount*: int profiler*: Profiler templInstCounter*: ref int # gives every template instantiation a unique ID, needed here for getAst + vmstateDiff*: seq[(PSym, PNode)] # we remember the "diff" to global state here (feature for IC) PStackFrame* = ref TStackFrame TStackFrame* = object diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 8083ae179a..a9157bc03b 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -26,7 +26,7 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): str proc atomicTypeX(cache: IdentCache; name: string; m: TMagic; t: PType; info: TLineInfo; idgen: IdGenerator): PNode = - let sym = newSym(skType, getIdent(cache, name), nextId(idgen), t.owner, info) + let sym = newSym(skType, getIdent(cache, name), nextSymId(idgen), t.owner, info) sym.magic = m sym.typ = t result = newSymNode(sym) @@ -47,7 +47,7 @@ proc mapTypeToBracketX(cache: IdentCache; name: string; m: TMagic; t: PType; inf for i in 0..= result.len: setLen(result.sons, pos + 1) let fieldNode = newNode(nkExprColonExpr) - fieldNode.add newSymNode(newSym(skField, ident, nextId(idgen), nil, unknownLineInfo)) + fieldNode.add newSymNode(newSym(skField, ident, nextSymId(idgen), nil, unknownLineInfo)) fieldNode.add loadAny(p, field.typ, tab, cache, conf, idgen) result[pos] = fieldNode if p.kind == jsonObjectEnd: next(p) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 47df3d24f6..5748b41b33 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -9,18 +9,28 @@ # Unfortunately this cannot be a module yet: #import vmdeps, vm -from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, +from std/math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc, - floor, ceil, `mod` + floor, ceil, `mod`, cbrt, arcsinh, arccosh, arctanh, erf, erfc, gamma, + lgamma + +when declared(math.copySign): + from std/math import copySign + +when declared(math.signbit): + from std/math import signbit + +from std/os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir, + getAppFilename, raiseOSError, osLastError + +from std/md5 import getMD5 +from std/times import cpuTime +from std/hashes import hash +from std/osproc import nil -from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir, getAppFilename -from md5 import getMD5 from sighashes import symBodyDigest -from times import cpuTime - -from hashes import hash -from osproc import nil +# There are some useful procs in vmconv. import vmconv template mathop(op) {.dirty.} = @@ -46,6 +56,7 @@ template md5op(op) {.dirty.} = template wrap1f_math(op) {.dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = + doAssert a.numArgs == 1 setResult(a, op(getFloat(a, 0))) mathop op @@ -124,6 +135,7 @@ when defined(nimHasInvariant): of compileOptions: result = conf.compileOptions of ccompilerPath: result = conf.cCompilerPath of backend: result = $conf.backend + of libPath: result = conf.libpath.string proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] = template copySeq(field: untyped): untyped = @@ -147,14 +159,17 @@ proc registerAdditionalOps*(c: PCtx) = setResult a, c.config.projectPath.string wrap1f_math(sqrt) + wrap1f_math(cbrt) wrap1f_math(ln) wrap1f_math(log10) wrap1f_math(log2) wrap1f_math(exp) - wrap1f_math(round) wrap1f_math(arccos) wrap1f_math(arcsin) wrap1f_math(arctan) + wrap1f_math(arcsinh) + wrap1f_math(arccosh) + wrap1f_math(arctanh) wrap2f_math(arctan2) wrap1f_math(cos) wrap1f_math(cosh) @@ -167,6 +182,23 @@ proc registerAdditionalOps*(c: PCtx) = wrap1f_math(trunc) wrap1f_math(floor) wrap1f_math(ceil) + wrap1f_math(erf) + wrap1f_math(erfc) + wrap1f_math(gamma) + wrap1f_math(lgamma) + + when declared(copySign): + wrap2f_math(copySign) + + when declared(signbit): + wrap1f_math(signbit) + + registerCallback c, "stdlib.math.round", proc (a: VmArgs) {.nimcall.} = + let n = a.numArgs + case n + of 1: setResult(a, round(getFloat(a, 0))) + of 2: setResult(a, round(getFloat(a, 0), getInt(a, 1).int)) + else: doAssert false, $n wrap1s(getMD5, md5op) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 170d04df1a..6a68e2c709 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -38,7 +38,8 @@ type wCursor = "cursor", wNoalias = "noalias", wImmediate = "immediate", wConstructor = "constructor", wDestructor = "destructor", - wDelegator = "delegator", wOverride = "override", wImportCpp = "importcpp", + wDelegator = "delegator", wOverride = "override", wImportCpp = "importcpp", + wCppNonPod = "cppNonPod", wImportObjC = "importobjc", wImportCompilerProc = "importcompilerproc", wImportc = "importc", wImportJs = "importjs", wExportc = "exportc", wExportCpp = "exportcpp", wExportNims = "exportnims", @@ -49,7 +50,10 @@ type wNosinks = "nosinks", wMerge = "merge", wLib = "lib", wDynlib = "dynlib", wCompilerProc = "compilerproc", wCore = "core", wProcVar = "procvar", wBase = "base", wUsed = "used", wFatal = "fatal", wError = "error", wWarning = "warning", - wHint = "hint", wWarningAsError = "warningAsError", wLine = "line", wPush = "push", + wHint = "hint", + wWarningAsError = "warningAsError", + wHintAsError = "hintAsError", + wLine = "line", wPush = "push", wPop = "pop", wDefine = "define", wUndef = "undef", wLineDir = "lineDir", wStackTrace = "stackTrace", wLineTrace = "lineTrace", wLink = "link", wCompile = "compile", wLinksys = "linksys", wDeprecated = "deprecated", wVarargs = "varargs", wCallconv = "callconv", diff --git a/config/config.nims b/config/config.nims index 24c7901681..2ae86012c6 100644 --- a/config/config.nims +++ b/config/config.nims @@ -1,5 +1,16 @@ # this config.nims also needs to exist to prevent future regressions, see #9990 -when defined(nimHasCppDefine): - cppDefine "errno" - cppDefine "unix" +cppDefine "errno" +cppDefine "unix" + +when defined(nimStrictMode): + # xxx add more flags here, and use `-d:nimStrictMode` in more contexts in CI. + + # pending bug #14246, enable this: + # when defined(nimHasWarningAsError): + # switch("warningAsError", "UnusedImport") + + when defined(nimHasHintAsError): + # switch("hint", "ConvFromXtoItselfNotNeeded") + switch("hintAsError", "ConvFromXtoItselfNotNeeded") + # future work: XDeclaredButNotUsed diff --git a/config/nim.cfg b/config/nim.cfg index a33a2f0a9f..39e6c002b2 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -43,14 +43,12 @@ path="$lib/arch" path="$lib/core" path="$lib/pure" -@if nimbabel: - @if not windows: - nimblepath="/opt/nimble/pkgs/" - @else: - # TODO: - @end - nimblepath="$home/.nimble/pkgs/" +@if not windows: + nimblepath="/opt/nimble/pkgs/" +@else: + # TODO: @end +nimblepath="$home/.nimble/pkgs/" @if danger or quick: obj_checks:off @@ -63,10 +61,6 @@ path="$lib/pure" linetrace:off debugger:off line_dir:off - dead_code_elim:on - @if nimHasNilChecks: - nilchecks:off - @end @end @if release or danger: @@ -111,7 +105,16 @@ path="$lib/pure" @end @if unix: - @if not bsd or haiku: + @if bsd: + # BSD got posix_spawn only recently, so we deactivate it for osproc: + define:useFork + @elif haiku: + gcc.options.linker = "-Wl,--as-needed -lnetwork" + gcc.cpp.options.linker = "-Wl,--as-needed -lnetwork" + clang.options.linker = "-Wl,--as-needed -lnetwork" + clang.cpp.options.linker = "-Wl,--as-needed -lnetwork" + tcc.options.linker = "-Wl,--as-needed -lnetwork" + @else: # -fopenmp gcc.options.linker = "-ldl" gcc.cpp.options.linker = "-ldl" @@ -119,19 +122,6 @@ path="$lib/pure" clang.cpp.options.linker = "-ldl" tcc.options.linker = "-ldl" @end - @if bsd: - # BSD got posix_spawn only recently, so we deactivate it for osproc: - define:useFork - # at least NetBSD has problems with thread local storage: - tlsEmulation:on - @end - @if haiku: - gcc.options.linker = "-Wl,--as-needed -lnetwork" - gcc.cpp.options.linker = "-Wl,--as-needed -lnetwork" - clang.options.linker = "-Wl,--as-needed -lnetwork" - clang.cpp.options.linker = "-Wl,--as-needed -lnetwork" - tcc.options.linker = "-Wl,--as-needed -lnetwork" - @end @end @if android: @@ -169,9 +159,13 @@ path="$lib/pure" gcc.maxerrorsimpl = "-fmax-errors=3" +@if bsd: + # at least NetBSD has problems with thread local storage: + tlsEmulation:on +@end + @if macosx or freebsd or openbsd: cc = clang - tlsEmulation:on gcc.options.always %= "-w ${gcc.maxerrorsimpl}" gcc.cpp.options.always %= "-w ${gcc.maxerrorsimpl} -fpermissive" @elif windows: diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 585b3cc49c..82bd9cc219 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -34,7 +34,8 @@ doc.section.toc2 = """ # Available variables are: # * $desc: the actual docstring of the item. # * $header: the full version of name, including types, pragmas, tags, etc. -# * $header_plain: like header but without HTML, for attribute embedding. +# * $header_plain: like header but without HTML (and without pragmas, tags, etc.), +# for attribute embedding. # * $itemID: numerical unique entry of the item in the HTML. # * $itemSym: short symbolic name of the item for easier hyperlinking. # * $itemSymEnc: quoted version for URLs or attributes. @@ -55,6 +56,9 @@ $seeSrc # Chunk of HTML emitted for each entry in the HTML table of contents. # See doc.item for available substitution variables. + +# This is used for TOC items which are not overloadable (e.g. types). +# `$header_plain` would be too verbose here, so we use $name. doc.item.toc = """
  • $name
  • @@ -63,7 +67,7 @@ doc.item.toc = """ # This is used for TOC items which are grouped by the same name (e.g. procs). doc.item.tocTable = """
  • $itemSymOrID
  • + title="$header_plain">$header_plain """ @@ -206,7 +210,8 @@ $moduledesc $content """ -doc.listing_start = "
    "
    +# $1 - number of listing in document, $2 - language (e.g. langNim), $3 - anchor
    +doc.listing_start = ""
     doc.listing_end = "
    " # * $analytics: Google analytics location, includes -Create a ``calculator.nim`` file with the following content (or reuse the one +Create a `calculator.nim` file with the following content (or reuse the one from the previous section): .. code-block:: nim @@ -209,9 +211,9 @@ from the previous section): when isMainModule: echo addTwoIntegers(3, 7) -Compile the Nim code to JavaScript with ``nim js -o:calculator.js -calculator.nim`` and open ``host.html`` in a browser. If the browser supports -javascript, you should see the value ``10`` in the browser's console. Use the +Compile the Nim code to JavaScript with `nim js -o:calculator.js +calculator.nim` and open `host.html` in a browser. If the browser supports +javascript, you should see the value `10` in the browser's console. Use the `dom module `_ for specific DOM querying and modification procs or take a look at `karax `_ for how to develop browser-based applications. @@ -222,29 +224,29 @@ Backend code calling Nim Backend code can interface with Nim code exposed through the `exportc pragma `_. The -``exportc`` pragma is the *generic* way of making Nim symbols available to +`exportc` pragma is the *generic* way of making Nim symbols available to the backends. By default, the Nim compiler will mangle all the Nim symbols to -avoid any name collision, so the most significant thing the ``exportc`` pragma +avoid any name collision, so the most significant thing the `exportc` pragma does is maintain the Nim symbol name, or if specified, use an alternative symbol for the backend in case the symbol rules don't match. The JavaScript target doesn't have any further interfacing considerations since it also has garbage collection, but the C targets require you to -initialize Nim's internals, which is done calling a ``NimMain`` function. +initialize Nim's internals, which is done calling a `NimMain` function. Also, C code requires you to specify a forward declaration for functions or the compiler will assume certain types for the return value and parameters which will likely make your program crash at runtime. -The Nim compiler can generate a C interface header through the ``--header`` +The Nim compiler can generate a C interface header through the `--header` command-line switch. The generated header will contain all the exported -symbols and the ``NimMain`` proc which you need to call before any other +symbols and the `NimMain` proc which you need to call before any other Nim code. Nim invocation example from C ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Create a ``fib.nim`` file with the following content: +Create a `fib.nim` file with the following content: .. code-block:: nim @@ -254,7 +256,7 @@ Create a ``fib.nim`` file with the following content: else: result = fib(a - 1) + fib(a - 2) -Create a ``maths.c`` file with the following content: +Create a `maths.c` file with the following content: .. code-block:: c @@ -277,30 +279,30 @@ program:: $ gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c The first command runs the Nim compiler with three special options to avoid -generating a ``main()`` function in the generated files, avoid linking the +generating a `main()` function in the generated files, avoid linking the object files into a final binary, and explicitly generate a header file for C -integration. All the generated files are placed into the ``nimcache`` -directory. That's why the next command compiles the ``maths.c`` source plus -all the ``.c`` files from ``nimcache``. In addition to this path, you also -have to tell the C compiler where to find Nim's ``nimbase.h`` header file. +integration. All the generated files are placed into the `nimcache` +directory. That's why the next command compiles the `maths.c` source plus +all the `.c` files from `nimcache`. In addition to this path, you also +have to tell the C compiler where to find Nim's `nimbase.h` header file. -Instead of depending on the generation of the individual ``.c`` files you can +Instead of depending on the generation of the individual `.c` files you can also ask the Nim compiler to generate a statically linked library:: $ nim c --app:staticLib --noMain --header fib.nim $ gcc -o m -Inimcache -Ipath/to/nim/lib libfib.nim.a maths.c The Nim compiler will handle linking the source files generated in the -``nimcache`` directory into the ``libfib.nim.a`` static library, which you can +`nimcache` directory into the `libfib.nim.a` static library, which you can then link into your C program. Note that these commands are generic and will vary for each system. For instance, on Linux systems you will likely need to -use ``-ldl`` too to link in required dlopen functionality. +use `-ldl` too to link in required dlopen functionality. Nim invocation example from JavaScript ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Create a ``mhost.html`` file with the following content: +Create a `mhost.html` file with the following content: .. code-block:: @@ -311,7 +313,7 @@ Create a ``mhost.html`` file with the following content: -Create a ``fib.nim`` file with the following content (or reuse the one +Create a `fib.nim` file with the following content (or reuse the one from the previous section): .. code-block:: nim @@ -322,10 +324,10 @@ from the previous section): else: result = fib(a - 1) + fib(a - 2) -Compile the Nim code to JavaScript with ``nim js -o:fib.js fib.nim`` and -open ``mhost.html`` in a browser. If the browser supports javascript, you -should see an alert box displaying the text ``Fib for 9 is 34``. As mentioned -earlier, JavaScript doesn't require an initialization call to ``NimMain`` or +Compile the Nim code to JavaScript with `nim js -o:fib.js fib.nim` and +open `mhost.html` in a browser. If the browser supports javascript, you +should see an alert box displaying the text `Fib for 9 is 34`. As mentioned +earlier, JavaScript doesn't require an initialization call to `NimMain` or a similar function and you can call the exported Nim proc directly. @@ -335,14 +337,14 @@ Nimcache naming logic The `nimcache`:idx: directory is generated during compilation and will hold either temporary or final files depending on your backend target. The default name for the directory depends on the used backend and on your OS but you can -use the ``--nimcache`` `compiler switch +use the `--nimcache` `compiler switch `_ to change it. Memory management ================= -In the previous sections, the ``NimMain()`` function reared its head. Since +In the previous sections, the `NimMain()` function reared its head. Since JavaScript already provides automatic memory management, you can freely pass objects between the two languages without problems. In C and derivate languages you need to be careful about what you do and how you share memory. The @@ -357,15 +359,15 @@ Strings and C strings The manual mentions that `Nim strings are implicitly convertible to cstrings `_ which makes interaction usually painless. Most C functions accepting a Nim string converted to a -``cstring`` will likely not need to keep this string around and by the time +`cstring` will likely not need to keep this string around and by the time they return the string won't be needed anymore. However, for the rare cases where a Nim string has to be preserved and made available to the C backend -as a ``cstring``, you will need to manually prevent the string data from being +as a `cstring`, you will need to manually prevent the string data from being freed with `GC_ref `_ and `GC_unref `_. A similar thing happens with C code invoking Nim code which returns a -``cstring``. Consider the following proc: +`cstring`. Consider the following proc: .. code-block:: nim @@ -373,8 +375,8 @@ A similar thing happens with C code invoking Nim code which returns a result = "Hey there C code! " & $rand(100) Since Nim's garbage collector is not aware of the C code, once the -``gimme`` proc has finished it can reclaim the memory of the ``cstring``. -However, from a practical standpoint, the C code invoking the ``gimme`` +`gimme` proc has finished it can reclaim the memory of the `cstring`. +However, from a practical standpoint, the C code invoking the `gimme` function directly will be able to use it since Nim's garbage collector has not had a chance to run *yet*. This gives you enough time to make a copy for the C side of the program, as calling any further Nim procs *might* trigger @@ -397,14 +399,14 @@ Again, if you are wrapping a library which *mallocs* and *frees* data structures, you need to expose the appropriate *free* function to Nim so you can clean it up. And of course, once cleaned you should avoid accessing it from Nim (or C for that matter). Typically C data structures have their own -``malloc_structure`` and ``free_structure`` specific functions, so wrapping +`malloc_structure` and `free_structure` specific functions, so wrapping these for the Nim side should be enough. Thread coordination ------------------- -When the ``NimMain()`` function is called Nim initializes the garbage +When the `NimMain()` function is called Nim initializes the garbage collector to the current thread, which is usually the main thread of your application. If your C code later spawns a different thread and calls Nim code, the garbage collector will fail to work properly and you will crash. diff --git a/doc/contributing.rst b/doc/contributing.rst index 90330e4f45..b7188a436a 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ============ Contributing ============ @@ -17,15 +19,15 @@ Writing tests There are 4 types of tests: -1. ``runnableExamples`` documentation comment tests, ran by ``nim doc mymod.nim`` +1. `runnableExamples` documentation comment tests, ran by `nim doc mymod.nim` These end up in documentation and ensure documentation stays in sync with code. -2. separate test files, e.g.: ``tests/stdlib/tos.nim``. +2. separate test files, e.g.: `tests/stdlib/tos.nim`. In nim repo, `testament` (see below) runs all `$nim/tests/*/t*.nim` test files; for nimble packages, see https://github.com/nim-lang/nimble#tests. -3. (deprecated) tests in ``when isMainModule:`` block, ran by ``nim r mymod.nim``. - ``nimble test`` can run those in nimble packages when specified in a +3. (deprecated) tests in `when isMainModule:` block, ran by `nim r mymod.nim`. + `nimble test` can run those in nimble packages when specified in a `task "test"`. 4. (not preferred) `.. code-block:: nim` RST snippets; these should only be used in rst sources, @@ -39,20 +41,23 @@ that don't. Always leave the code cleaner than you found it. Stdlib ------ -Each stdlib module (anything under ``lib/``, e.g. ``lib/pure/os.nim``) should +Each stdlib module (anything under `lib/`, e.g. `lib/pure/os.nim`) should preferably have a corresponding separate test file, e.g. `tests/stdlib/tos.nim`. -The old convention was to add a ``when isMainModule:`` block in the source file, +The old convention was to add a `when isMainModule:` block in the source file, which only gets executed when the tester is building the file. -Each test should be in a separate ``block:`` statement, such that -each has its own scope. Use boolean conditions and ``doAssert`` for the +Each test should be in a separate `block:` statement, such that +each has its own scope. Use boolean conditions and `doAssert` for the testing by itself, don't rely on echo statements or similar; in particular, avoid -things like `echo "done"`. +things like `echo "done"`. Don't use `unittest.suite` and `unittest.test`. Sample test: .. code-block:: nim + block: # foo + doAssert foo(1) == 10 + block: # bug #1234 static: doAssert 1+1 == 2 @@ -80,22 +85,22 @@ Rationale for using a separate test file instead of `when isMainModule:` block: Compiler -------- -The tests for the compiler use a testing tool called ``testament``. They are all -located in ``tests/`` (e.g.: ``tests/destructor/tdestructor3.nim``). -Each test has its own file. All test files are prefixed with ``t``. If you want -to create a file for import into another test only, use the prefix ``m``. +The tests for the compiler use a testing tool called `testament`. They are all +located in `tests/` (e.g.: `tests/destructor/tdestructor3.nim`). +Each test has its own file. All test files are prefixed with `t`. If you want +to create a file for import into another test only, use the prefix `m`. At the beginning of every test is the expected behavior of the test. Possible keys are: -- ``cmd``: A compilation command template e.g. ``nim $target --threads:on $options $file`` -- ``output``: The expected output (stdout + stderr), most likely via ``echo`` -- ``exitcode``: Exit code of the test (via ``exit(number)``) -- ``errormsg``: The expected compiler error message -- ``file``: The file the errormsg was produced at -- ``line``: The line the errormsg was produced at +- `cmd`: A compilation command template e.g. `nim $target --threads:on $options $file` +- `output`: The expected output (stdout + stderr), most likely via `echo` +- `exitcode`: Exit code of the test (via `exit(number)`) +- `errormsg`: The expected compiler error message +- `file`: The file the errormsg was produced at +- `line`: The line the errormsg was produced at -For a full spec, see here: ``testament/specs.nim`` +For a full spec, see here: `testament/specs.nim` An example of a test: @@ -131,8 +136,8 @@ only want to see the output of failing tests, go for ./koch tests --failing all You can also run only a single category of tests. A category is a subdirectory -in the ``tests`` directory. There are a couple of special categories; for a -list of these, see ``testament/categories.nim``, at the bottom. +in the `tests` directory. There are a couple of special categories; for a +list of these, see `testament/categories.nim`, at the bottom. :: @@ -148,16 +153,16 @@ To run a single test: For reproducible tests (to reproduce an environment more similar to the one run by Continuous Integration on travis/appveyor), you may want to disable your -local configuration (e.g. in ``~/.config/nim/nim.cfg``) which may affect some +local configuration (e.g. in `~/.config/nim/nim.cfg`) which may affect some tests; this can also be achieved by using -``export XDG_CONFIG_HOME=pathtoAlternateConfig`` before running ``./koch`` +`export XDG_CONFIG_HOME=pathtoAlternateConfig` before running `./koch` commands. Comparing tests =============== -Test failures can be grepped using ``Failure:``. +Test failures can be grepped using `Failure:`. The tester can compare two test runs. First, you need to create a reference test. You'll also need to the commit id, because that's what @@ -176,7 +181,7 @@ Then switch over to your changes and run the tester again. git checkout your-changes ./koch tests -Then you can ask the tester to create a ``testresults.html`` which will +Then you can ask the tester to create a `testresults.html` which will tell you if any new tests passed/failed. :: @@ -214,14 +219,14 @@ Documentation When contributing new procs, be sure to add documentation, especially if the proc is public. Even private procs benefit from documentation and can be -viewed using ``nim doc --docInternal foo.nim``. +viewed using `nim doc --docInternal foo.nim`. Documentation begins on the line -following the ``proc`` definition, and is prefixed by ``##`` on each line. +following the `proc` definition, and is prefixed by `##` on each line. Runnable code examples are also encouraged, to show typical behavior with a few -test cases (typically 1 to 3 ``assert`` statements, depending on complexity). -These ``runnableExamples`` are automatically run by ``nim doc mymodule.nim`` -as well as ``testament`` and guarantee they stay in sync. +test cases (typically 1 to 3 `assert` statements, depending on complexity). +These `runnableExamples` are automatically run by `nim doc mymodule.nim` +as well as `testament` and guarantee they stay in sync. .. code-block:: nim proc addBar*(a: string): string = @@ -233,21 +238,21 @@ as well as ``testament`` and guarantee they stay in sync. See `parentDir `_ example. The RestructuredText Nim uses has a special syntax for including code snippets -embedded in documentation; these are not run by ``nim doc`` and therefore are -not guaranteed to stay in sync, so ``runnableExamples`` is usually preferred: +embedded in documentation; these are not run by `nim doc` and therefore are +not guaranteed to stay in sync, so `runnableExamples` is almost always preferred: .. code-block:: nim - proc someproc*(): string = - ## Return "something" + proc someProc*(): string = + ## Returns "something" ## ## .. code-block:: - ## echo someproc() # "something" + ## echo someProc() # "something" result = "something" # single-hash comments do not produce documentation -The ``.. code-block:: nim`` followed by a newline and an indentation instructs the -``nim doc`` command to produce syntax-highlighted example code with the -documentation (``.. code-block::`` is sufficient from inside a nim module). +The `.. code-block:: nim` followed by a newline and an indentation instructs the +`nim doc` command to produce syntax-highlighted example code with the +documentation (`.. code-block::` is sufficient from inside a nim module). When forward declaration is used, the documentation should be included with the first appearance of the proc. @@ -262,12 +267,12 @@ first appearance of the proc. echo "hello" The preferred documentation style is to begin with a capital letter and use -the imperative (command) form. That is, between: +the third-person singular. That is, between: .. code-block:: nim proc hello*(): string = - ## Return "hello" + ## Returns "hello" result = "hello" or @@ -275,7 +280,7 @@ or .. code-block:: nim proc hello*(): string = - ## says hello + ## say hello result = "hello" the first is preferred. @@ -320,7 +325,7 @@ Design with method call syntax chaining in mind # can be called as: `getLines().foo(false)` .. _avoid_quit: -Use exceptions (including assert / doAssert) instead of ``quit`` +Use exceptions (including assert / doAssert) instead of `quit` rationale: https://forum.nim-lang.org/t/4089 .. code-block:: nim @@ -329,18 +334,33 @@ rationale: https://forum.nim-lang.org/t/4089 doAssert() # preferred .. _tests_use_doAssert: -Use ``doAssert`` (or ``require``, etc), not ``assert`` in all tests so they'll -be enabled even in release mode (except for tests in ``runnableExamples`` blocks -which for which ``nim doc`` ignores ``-d:release``). +Use `doAssert` (or `unittest.check`, `unittest.require`), not `assert` in all +tests so they'll be enabled even with `--assertions:off`. .. code-block:: nim - when isMainModule: + block: # foo assert foo() # bad doAssert foo() # preferred +.. _runnableExamples_use_assert: +An exception to the above rule is `runnableExamples` and `code-block` rst blocks +intended to be used as `runnableExamples`, which for brevity use `assert` +instead of `doAssert`. Note that `nim doc -d:danger main` won't pass `-d:danger` to the +`runnableExamples`, but `nim doc --doccmd:-d:danger main` would, and so would the +second example below: + +.. code-block:: nim + + runnableExamples: + doAssert foo() # bad + assert foo() # preferred + + runnableExamples("-d:danger"): + doAssert foo() # `assert` would be disabled here, so `doAssert` makes more sense + .. _delegate_printing: -Delegate printing to caller: return ``string`` instead of calling ``echo`` +Delegate printing to caller: return `string` instead of calling `echo` rationale: it's more flexible (e.g. allows the caller to call custom printing, including prepending location info, writing to log files, etc). @@ -359,7 +379,7 @@ unless stack allocation is needed (e.g. for efficiency). proc foo(): Option[Bar] .. _use_doAssert_not_echo: -Tests (including in testament) should always prefer assertions over ``echo``, +Tests (including in testament) should always prefer assertions over `echo`, except when that's not possible. It's more precise, easier for readers and maintainers to where expected values refer to. See for example https://github.com/nim-lang/Nim/pull/9335 and https://forum.nim-lang.org/t/4089 @@ -379,12 +399,12 @@ General commit rules 1. Important, critical bugfixes that have a tiny chance of breaking somebody's code should be backported to the latest stable release branch (currently 1.4.x) and maybe also all the way back to the 1.0.x branch. - The commit message should contain the tag ``[backport]`` for "backport to all - stable releases" and the tag ``[backport:$VERSION]`` for backporting to the + The commit message should contain the tag `[backport]` for "backport to all + stable releases" and the tag `[backport:$VERSION]` for backporting to the given $VERSION. 2. If you introduce changes which affect backward compatibility, - make breaking changes, or have PR which is tagged as ``[feature]``, + make breaking changes, or have PR which is tagged as `[feature]`, the changes should be mentioned in `the changelog `_. @@ -395,13 +415,13 @@ General commit rules your editor reformatted automatically the code or whatever different reason, this should be excluded from the commit. - *Tip:* Never commit everything as is using ``git commit -a``, but review - carefully your changes with ``git add -p``. + *Tip:* Never commit everything as is using `git commit -a`, but review + carefully your changes with `git add -p`. 4. Changes should not introduce any trailing whitespace. - Always check your changes for whitespace errors using ``git diff --check`` - or add the following ``pre-commit`` hook: + Always check your changes for whitespace errors using `git diff --check` + or add the following `pre-commit` hook: .. code-block:: sh @@ -410,10 +430,10 @@ General commit rules 5. Describe your commit and use your common sense. Example commit message: - ``Fixes #123; refs #124`` + `Fixes #123; refs #124` - indicates that issue ``#123`` is completely fixed (GitHub may automatically - close it when the PR is committed), wheres issue ``#124`` is referenced + indicates that issue `#123` is completely fixed (GitHub may automatically + close it when the PR is committed), wheres issue `#124` is referenced (e.g.: partially fixed) and won't close the issue when committed. 6. PR body (not just PR title) should contain references to fixed/referenced github @@ -425,7 +445,7 @@ General commit rules 7. Commits should be always be rebased against devel (so a fast forward merge can happen) - e.g.: use ``git pull --rebase origin devel``. This is to avoid messing up + e.g.: use `git pull --rebase origin devel`. This is to avoid messing up git history. Exceptions should be very rare: when rebase gives too many conflicts, simply squash all commits using the script shown in @@ -441,7 +461,7 @@ Continuous Integration (CI) 1. Continuous Integration is by default run on every push in a PR; this clogs the CI pipeline and affects other PR's; if you don't need it (e.g. for WIP or - documentation only changes), add ``[ci skip]`` to your commit message title. + documentation only changes), add `[ci skip]` to your commit message title. This convention is supported by `Appveyor `_ and `Travis `_. @@ -468,7 +488,11 @@ Debugging CI failures, flaky tests, etc If either on you own fork or in Nim repo, it's possible from inside GitHub UI under checks tab, see https://github.com/timotheecour/Nim/issues/211#issuecomment-629751569 * GitHub actions: under "Checks" tab, click "Re-run jobs" in the right. - * builds.sr.ht: create a sourcehut account so you can restart a PR job as illustrated + * builds.sr.ht: create a sourcehut account so you can restart a PR job as illustrated. + builds.sr.ht also allows you to ssh to a CI machine which can help a lot for debugging + issues, see docs in https://man.sr.ht/builds.sr.ht/build-ssh.md and + https://drewdevault.com/2019/08/19/Introducing-shell-access-for-builds.html; see + https://man.sr.ht/tutorials/set-up-account-and-git.md to generate and upload ssh keys. Code reviews @@ -522,11 +546,11 @@ Vocabulary types must be part of the stdlib ------------------------------------------- These are types most packages need to agree on for better interoperability, -for example ``Option[T]``. This rule also covers the existing collections like -``Table``, ``CountTable`` etc. "Sorted" containers based on a tree-like data +for example `Option[T]`. This rule also covers the existing collections like +`Table`, `CountTable` etc. "Sorted" containers based on a tree-like data structure are still missing and should be added. -Time handling, especially the ``Time`` type are also covered by this rule. +Time handling, especially the `Time` type are also covered by this rule. Existing, battle-tested modules stay @@ -537,8 +561,8 @@ fashion as in "Nim's core MUST BE SMALL". If you don't like an existing module, don't import it. If a compilation target (e.g. JS) cannot support a module, document this limitation. -This covers modules like ``os``, ``osproc``, ``strscans``, ``strutils``, -``strformat``, etc. +This covers modules like `os`, `osproc`, `strscans`, `strutils`, +`strformat`, etc. Syntactic helpers can start as experimental stdlib modules @@ -568,7 +592,7 @@ As long as they are documented and tested well, adding little helpers to existing modules is acceptable. For two reasons: 1. It makes Nim easier to learn and use in the long run. - ("Why does sequtils lack a ``countIt``? + ("Why does sequtils lack a `countIt`? Because version 1.0 happens to have lacked it? Silly...") 2. To encourage contributions. Contributors often start with PRs that add simple things and then they stay and also fix bugs. Nim is an @@ -579,14 +603,16 @@ to existing modules is acceptable. For two reasons: Conventions ----------- -1. New stdlib modules should go under `Nim/lib/std/`. The rationale is to require -users to import via `import std/foo` instead of `import foo`, which would cause -potential conflicts with nimble packages. Note that this still applies for new modules -in existing logical directories, e.g.: -use `lib/std/collections/foo.nim`, not `lib/pure/collections/foo.nim`. +1. New stdlib modules should go under `Nim/lib/std/`. The rationale is to + require users to import via `import std/foo` instead of `import foo`, + which would cause potential conflicts with nimble packages. + Note that this still applies for new modules in existing logical + directories, e.g.: use `lib/std/collections/foo.nim`, + not `lib/pure/collections/foo.nim`. 2. New module names should prefer plural form whenever possible, e.g.: -`std/sums.nim` instead of `std/sum.nim`. In particular, this reduces chances of conflicts -between module name and the symbols it defines. Furthermore, is should use `snake_case` -and not use capital letters, which cause issues when going from an OS without case -sensitivity to an OS without it. + `std/sums.nim` instead of `std/sum.nim`. In particular, this reduces + chances of conflicts between module name and the symbols it defines. + Furthermore, module names should use `snake_case` and not use capital + letters, which cause issues when going from an OS without case + sensitivity to an OS with it. diff --git a/doc/destructors.rst b/doc/destructors.rst index e48e360dd5..01e2d2ee9b 100644 --- a/doc/destructors.rst +++ b/doc/destructors.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ================================== Nim Destructors and Move Semantics ================================== @@ -16,7 +18,7 @@ not use classical GC algorithms anymore but is based on destructors and move semantics. The new runtime's advantages are that Nim programs become oblivious to the involved heap sizes and programs are easier to write to make effective use of multi-core machines. As a nice bonus, files and sockets and -the like will not require manual ``close`` calls anymore. +the like will not require manual `close` calls anymore. This document aims to be a precise specification about how move semantics and destructors work in Nim. @@ -37,7 +39,7 @@ written as: proc `=destroy`*[T](x: var myseq[T]) = if x.data != nil: - for i in 0..= x.cap: resize(x) + if x.len >= x.cap: + x.cap = max(x.len + 1, x.cap * 2) + x.data = cast[typeof(x.data)](realloc(x.data, x.cap * sizeof(T))) x.data[x.len] = y inc x.len @@ -87,11 +91,12 @@ written as: Lifetime-tracking hooks ======================= -The memory management for Nim's standard ``string`` and ``seq`` types as +The memory management for Nim's standard `string` and `seq` types as well as other standard collections is performed via so-called -"Lifetime-tracking hooks" or "type-bound operators". There are 3 different -hooks for each (generic or concrete) object type ``T`` (``T`` can also be a -``distinct`` type) that are called implicitly by the compiler. +"Lifetime-tracking hooks", which are particular `type bound operators `_. + +There are 3 different hooks for each (generic or concrete) object type `T` (`T` can also be a +`distinct` type) that are called implicitly by the compiler. (Note: The word "hook" here does not imply any kind of dynamic binding or runtime indirections, the implicit calls are statically bound and @@ -106,14 +111,14 @@ other associated resources. Variables are destroyed via this hook when they go out of scope or when the routine they were declared in is about to return. -The prototype of this hook for a type ``T`` needs to be: +The prototype of this hook for a type `T` needs to be: .. code-block:: nim proc `=destroy`(x: var T) -The general pattern in ``=destroy`` looks like: +The general pattern in `=destroy` looks like: .. code-block:: nim @@ -130,20 +135,20 @@ The general pattern in ``=destroy`` looks like: A `=sink` hook moves an object around, the resources are stolen from the source and passed to the destination. It is ensured that the source's destructor does not free the resources afterward by setting the object to its default value -(the value the object's state started in). Setting an object ``x`` back to its -default value is written as ``wasMoved(x)``. When not provided the compiler +(the value the object's state started in). Setting an object `x` back to its +default value is written as `wasMoved(x)`. When not provided the compiler is using a combination of `=destroy` and `copyMem` instead. This is efficient hence users rarely need to implement their own `=sink` operator, it is enough to provide `=destroy` and `=copy`, compiler will take care of the rest. -The prototype of this hook for a type ``T`` needs to be: +The prototype of this hook for a type `T` needs to be: .. code-block:: nim proc `=sink`(dest: var T; source: T) -The general pattern in ``=sink`` looks like: +The general pattern in `=sink` looks like: .. code-block:: nim @@ -153,25 +158,25 @@ The general pattern in ``=sink`` looks like: dest.field = source.field -**Note**: ``=sink`` does not need to check for self-assignments. +**Note**: `=sink` does not need to check for self-assignments. How self-assignments are handled is explained later in this document. `=copy` hook --------------- -The ordinary assignment in Nim conceptually copies the values. The ``=copy`` hook -is called for assignments that couldn't be transformed into ``=sink`` +The ordinary assignment in Nim conceptually copies the values. The `=copy` hook +is called for assignments that couldn't be transformed into `=sink` operations. -The prototype of this hook for a type ``T`` needs to be: +The prototype of this hook for a type `T` needs to be: .. code-block:: nim proc `=copy`(dest: var T; source: T) -The general pattern in ``=copy`` looks like: +The general pattern in `=copy` looks like: .. code-block:: nim @@ -183,48 +188,48 @@ The general pattern in ``=copy`` looks like: dest.field = duplicateResource(source.field) -The ``=copy`` proc can be marked with the ``{.error.}`` pragma. Then any assignment +The `=copy` proc can be marked with the `{.error.}` pragma. Then any assignment that otherwise would lead to a copy is prevented at compile-time. This looks like: .. code-block:: nim proc `=copy`(dest: var T; source: T) {.error.} -but a custom error message (e.g., ``{.error: "custom error".}``) will not be emitted -by the compiler. Notice that there is no ``=`` before the ``{.error.}`` pragma. +but a custom error message (e.g., `{.error: "custom error".}`) will not be emitted +by the compiler. Notice that there is no `=` before the `{.error.}` pragma. Move semantics ============== A "move" can be regarded as an optimized copy operation. If the source of the copy operation is not used afterward, the copy can be replaced by a move. This -document uses the notation ``lastReadOf(x)`` to describe that ``x`` is not +document uses the notation `lastReadOf(x)` to describe that `x` is not used afterwards. This property is computed by a static control flow analysis -but can also be enforced by using ``system.move`` explicitly. +but can also be enforced by using `system.move` explicitly. Swap ==== The need to check for self-assignments and also the need to destroy previous -objects inside ``=copy`` and ``=sink`` is a strong indicator to treat -``system.swap`` as a builtin primitive of its own that simply swaps every -field in the involved objects via ``copyMem`` or a comparable mechanism. -In other words, ``swap(a, b)`` is **not** implemented -as ``let tmp = move(b); b = move(a); a = move(tmp)``. +objects inside `=copy` and `=sink` is a strong indicator to treat +`system.swap` as a builtin primitive of its own that simply swaps every +field in the involved objects via `copyMem` or a comparable mechanism. +In other words, `swap(a, b)` is **not** implemented +as `let tmp = move(b); b = move(a); a = move(tmp)`. This has further consequences: * Objects that contain pointers that point to the same object are not supported by Nim's model. Otherwise swapped objects would end up in an inconsistent state. -* Seqs can use ``realloc`` in the implementation. +* Seqs can use `realloc` in the implementation. Sink parameters =============== -To move a variable into a collection usually ``sink`` parameters are involved. -A location that is passed to a ``sink`` parameter should not be used afterward. +To move a variable into a collection usually `sink` parameters are involved. +A location that is passed to a `sink` parameter should not be used afterward. This is ensured by a static analysis over a control flow graph. If it cannot be proven to be the last usage of the location, a copy is done instead and this copy is then passed to the sink parameter. @@ -232,9 +237,9 @@ copy is then passed to the sink parameter. A sink parameter *may* be consumed once in the proc's body but doesn't have to be consumed at all. The reason for this is that signatures -like ``proc put(t: var Table; k: sink Key, v: sink Value)`` should be possible -without any further overloads and ``put`` might not take ownership of ``k`` if -``k`` already exists in the table. Sink parameters enable an affine type system, +like `proc put(t: var Table; k: sink Key, v: sink Value)` should be possible +without any further overloads and `put` might not take ownership of `k` if +`k` already exists in the table. Sink parameters enable an affine type system, not a linear type system. The employed static analysis is limited and only concerned with local variables; @@ -251,7 +256,7 @@ however, object and tuple fields are treated as separate entities: echo tup[1] -Sometimes it is required to explicitly ``move`` a value into its final position: +Sometimes it is required to explicitly `move` a value into its final position: .. code-block:: nim @@ -291,9 +296,9 @@ Rewrite rules **Note**: There are two different allowed implementation strategies: -1. The produced ``finally`` section can be a single section that is wrapped +1. The produced `finally` section can be a single section that is wrapped around the complete routine body. -2. The produced ``finally`` section is wrapped around the enclosing scope. +2. The produced `finally` section is wrapped around the enclosing scope. The current implementation follows strategy (2). This means that resources are destroyed at the scope exit. @@ -356,13 +361,13 @@ Object and array construction ============================= Object and array construction is treated as a function call where the -function has ``sink`` parameters. +function has `sink` parameters. Destructor removal ================== -``wasMoved(x);`` followed by a `=destroy(x)` operation cancel each other +`wasMoved(x);` followed by a `=destroy(x)` operation cancel each other out. An implementation is encouraged to exploit this in order to improve efficiency and code sizes. The current implementation does perform this optimization. @@ -371,16 +376,22 @@ optimization. Self assignments ================ -``=sink`` in combination with ``wasMoved`` can handle self-assignments but +`=sink` in combination with `wasMoved` can handle self-assignments but it's subtle. -The simple case of ``x = x`` cannot be turned -into ``=sink(x, x); wasMoved(x)`` because that would lose ``x``'s value. -The solution is that simple self-assignments are simply transformed into -an empty statement that does nothing. +The simple case of `x = x` cannot be turned +into `=sink(x, x); wasMoved(x)` because that would lose `x`'s value. +The solution is that simple self-assignments that consist of -The complex case looks like a variant of ``x = f(x)``, we consider -``x = select(rand() < 0.5, x, y)`` here: +- Symbols: `x = x` +- Field access: `x.f = x.f` +- Array, sequence or string access with indices known at compile-time: `x[0] = x[0]` + +are transformed into an empty statement that does nothing. +The compiler is free to optimize further cases. + +The complex case looks like a variant of `x = f(x)`, we consider +`x = select(rand() < 0.5, x, y)` here: .. code-block:: nim @@ -441,17 +452,17 @@ self-assignments. Lent type ========= -``proc p(x: sink T)`` means that the proc ``p`` takes ownership of ``x``. +`proc p(x: sink T)` means that the proc `p` takes ownership of `x`. To eliminate even more creation/copy <-> destruction pairs, a proc's return -type can be annotated as ``lent T``. This is useful for "getter" accessors +type can be annotated as `lent T`. This is useful for "getter" accessors that seek to allow an immutable view into a container. -The ``sink`` and ``lent`` annotations allow us to remove most (if not all) +The `sink` and `lent` annotations allow us to remove most (if not all) superfluous copies and destructions. -``lent T`` is like ``var T`` a hidden pointer. It is proven by the compiler +`lent T` is like `var T` a hidden pointer. It is proven by the compiler that the pointer does not outlive its origin. No destructor call is injected -for expressions of type ``lent T`` or of type ``var T``. +for expressions of type `lent T` or of type `var T`. .. code-block:: nim @@ -485,9 +496,9 @@ for expressions of type ``lent T`` or of type ``var T``. The .cursor annotation ====================== -Under the ``--gc:arc|orc`` modes Nim's `ref` type is implemented via the same runtime +Under the `--gc:arc|orc` modes Nim's `ref` type is implemented via the same runtime "hooks" and thus via reference counting. This means that cyclic structures cannot be freed -immediately (``--gc:orc`` ships with a cycle collector). With the ``.cursor`` annotation +immediately (`--gc:orc` ships with a cycle collector). With the `.cursor` annotation one can break up cycles declaratively: .. code-block:: nim @@ -501,7 +512,7 @@ But please notice that this is not C++'s weak_ptr, it means the right field is n involved in the reference counting, it is a raw pointer without runtime checks. Automatic reference counting also has the disadvantage that it introduces overhead -when iterating over linked structures. The ``.cursor`` annotation can also be used +when iterating over linked structures. The `.cursor` annotation can also be used to avoid this overhead: .. code-block:: nim @@ -512,11 +523,11 @@ to avoid this overhead: it = it.next -In fact, ``.cursor`` more generally prevents object construction/destruction pairs +In fact, `.cursor` more generally prevents object construction/destruction pairs and so can also be useful in other contexts. The alternative solution would be to -use raw pointers (``ptr``) instead which is more cumbersome and also more dangerous -for Nim's evolution: Later on, the compiler can try to prove ``.cursor`` annotations -to be safe, but for ``ptr`` the compiler has to remain silent about possible +use raw pointers (`ptr`) instead which is more cumbersome and also more dangerous +for Nim's evolution: Later on, the compiler can try to prove `.cursor` annotations +to be safe, but for `ptr` the compiler has to remain silent about possible problems. @@ -547,13 +558,13 @@ indirections: Hook lifting ============ -The hooks of a tuple type ``(A, B, ...)`` are generated by lifting the -hooks of the involved types ``A``, ``B``, ... to the tuple type. In -other words, a copy ``x = y`` is implemented -as ``x[0] = y[0]; x[1] = y[1]; ...``, likewise for ``=sink`` and ``=destroy``. +The hooks of a tuple type `(A, B, ...)` are generated by lifting the +hooks of the involved types `A`, `B`, ... to the tuple type. In +other words, a copy `x = y` is implemented +as `x[0] = y[0]; x[1] = y[1]; ...`, likewise for `=sink` and `=destroy`. -Other value-based compound types like ``object`` and ``array`` are handled -correspondingly. For ``object`` however, the compiler-generated hooks +Other value-based compound types like `object` and `array` are handled +correspondingly. For `object` however, the compiler-generated hooks can be overridden. This can also be important to use an alternative traversal of the involved data structure that is more efficient or in order to avoid deep recursions. @@ -579,18 +590,18 @@ The ability to override a hook leads to a phase ordering problem: discard -The solution is to define ``proc `=destroy`[T](f: var Foo[T])`` before +The solution is to define `proc `=destroy`[T](f: var Foo[T])` before it is used. The compiler generates implicit hooks for all types in *strategic places* so that an explicitly provided hook that comes too "late" can be detected reliably. These *strategic places* have been derived from the rewrite rules and are as follows: -- In the construct ``let/var x = ...`` (var/let binding) - hooks are generated for ``typeof(x)``. -- In ``x = ...`` (assignment) hooks are generated for ``typeof(x)``. -- In ``f(...)`` (function call) hooks are generated for ``typeof(f(...))``. -- For every sink parameter ``x: sink T`` the hooks are generated - for ``typeof(x)``. +- In the construct `let/var x = ...` (var/let binding) + hooks are generated for `typeof(x)`. +- In `x = ...` (assignment) hooks are generated for `typeof(x)`. +- In `f(...)` (function call) hooks are generated for `typeof(f(...))`. +- For every sink parameter `x: sink T` the hooks are generated + for `typeof(x)`. nodestroy pragma @@ -625,3 +636,68 @@ used to specialize the object traversal in order to avoid deep recursions: As can be seen from the example, this solution is hardly sufficient and should eventually be replaced by a better solution. + + +Copy on write +============= + +String literals are implemented as [copy-on-write](https://en.wikipedia.org/wiki/Copy-on-write). +When assigning a string literal to a variable, a copy of the literal won't be created. +Instead the variable simply points to the literal. +The literal is shared between different variables which are pointing to it. +The copy operation is deferred until the first write. + +.. code-block:: nim + var x = "abc" # no copy + var y = x # no copy + +The string literal "abc" is stored in static memory and not allocated on the heap. +The variable `x` points to the literal and the variable `y` points to the literal too. +There is no copy during assigning operations. + +.. code-block:: nim + var x = "abc" # no copy + var y = x # no copy + y[0] = 'h' # copy + +The program above shows when the copy operations happen. +When mutating the variable `y`, the Nim compiler creates a fresh copy of `x`, +the variable `y` won't point to the string literal anymore. +Instead it points to the copy of `x` of which the memory can be mutated +and the variable `y` becomes a mutable string. + +.. Note:: The abstraction fails for `addr x` because whether the address is going to be used for mutations is unknown. + +Let's look at a silly example demonstrating this behaviour: + +.. code-block:: nim + var x = "abc" + var y = x + + moveMem(addr y[0], addr x[0], 3) + +The program fails because we need to prepare a fresh copy for the variable `y`. +`prepareMutation` should be called before the address operation. + +.. code-block:: nim + var x = "abc" + var y = x + + prepareMutation(y) + moveMem(addr y[0], addr x[0], 3) + assert y == "abc" + +Now `prepareMutation` solves the problem. +It manually creates a fresh copy and makes the variable `y` mutable. + +.. code-block:: nim + var x = "abc" + var y = x + + prepareMutation(y) + moveMem(addr y[0], addr x[0], 3) + moveMem(addr y[0], addr x[0], 3) + moveMem(addr y[0], addr x[0], 3) + assert y == "abc" + +No matter how many times `moveMem` is called, the program compiles and runs. diff --git a/doc/docgen.rst b/doc/docgen.rst index bbf0838bb5..c002ddb836 100644 --- a/doc/docgen.rst +++ b/doc/docgen.rst @@ -1,3 +1,5 @@ +.. default-role:: code + =================================== Nim DocGen Tools Guide =================================== @@ -15,7 +17,7 @@ This document describes the `documentation generation tools`:idx: built into the `Nim compiler `_, which can generate HTML and JSON output from input .nim files and projects, as well as HTML and LaTeX from input RST (reStructuredText) files. The output documentation will include the module -dependencies (``import``), any top-level documentation comments (##), and +dependencies (`import`), any top-level documentation comments (##), and exported symbols (*), including procedures, types, and variables. Quick start @@ -76,6 +78,24 @@ Note that without the `*` following the name of the type, the documentation for this type would not be generated. Documentation will only be generated for *exported* types/procedures/etc. +It's recommended to always add exactly **one** space after `##` for readability +of comments — this extra space will be cropped from the parsed comments and +won't influence RST formatting. + +.. note:: Generally, this baseline indentation level inside a documentation + comment may not be 1: it can be any since it is determined by the offset + of the first non-whitespace character in the comment. + After that indentation **must** be consistent on the following lines of + the same comment. + If you still need to add an additional indentation at the very beginning + (for RST block quote syntax) use backslash \\ before it: + + .. code-block:: nim + ## \ + ## + ## Block quote at the first line. + ## + ## Paragraph. Nim file input ----------------- @@ -88,7 +108,7 @@ sample.nim: .. code-block:: nim ## This module is a sample. - import strutils + import std/strutils proc helloWorld*(times: int) = ## Takes an integer and outputs @@ -107,12 +127,12 @@ Document Types HTML ---- -The generation of HTML documents is done via the ``doc`` command. This command +The generation of HTML documents is done via the `doc` command. This command takes either a single .nim file, outputting a single .html file with the same base filename, or multiple .nim files, outputting multiple .html files and, optionally, an index file. -The ``doc`` command:: +The `doc` command:: nim doc sample Partial Output:: @@ -128,12 +148,12 @@ compiler. JSON ---- -The generation of JSON documents is done via the ``jsondoc`` command. This command +The generation of JSON documents is done via the `jsondoc` command. This command takes in a .nim file and outputs a .json file with the same base filename. Note -that this tool is built off of the ``doc`` command (previously ``doc2``), and +that this tool is built off of the `doc` command (previously `doc2`), and contains the same information. -The ``jsondoc`` command:: +The `jsondoc` command:: nim jsondoc sample Output:: @@ -153,10 +173,10 @@ Output:: ] } -Similarly to the old ``doc`` command, the old ``jsondoc`` command has been -renamed to ``jsondoc0``. +Similarly to the old `doc` command, the old `jsondoc` command has been +renamed to `jsondoc0`. -The ``jsondoc0`` command:: +The `jsondoc0` command:: nim jsondoc0 sample Output:: @@ -172,8 +192,8 @@ Output:: } ] -Note that the ``jsondoc`` command outputs it's JSON without pretty-printing it, -while ``jsondoc0`` outputs pretty-printed JSON. +Note that the `jsondoc` command outputs it's JSON without pretty-printing it, +while `jsondoc0` outputs pretty-printed JSON. Related Options =============== @@ -185,7 +205,7 @@ Project switch nim doc --project filename.nim This will recursively generate documentation of all nim modules imported -into the input module that belong to the Nimble package that ``filename.nim`` +into the input module that belong to the Nimble package that `filename.nim` belongs to. @@ -196,13 +216,13 @@ Index switch nim doc --index:on filename.nim This will generate an index of all the exported symbols in the input Nim -module, and put it into a neighboring file with the extension of ``.idx``. The +module, and put it into a neighboring file with the extension of `.idx`. The index file is line-oriented (newlines have to be escaped). Each line represents a tab-separated record of several columns, the first two mandatory, the rest optional. See the `Index (idx) file format`_ section for details. Once index files have been generated for one or more modules, the Nim -compiler command ``buildIndex directory`` can be run to go over all the index +compiler command `buildIndex directory` can be run to go over all the index files in the specified directory to generate a `theindex.html `_ file. @@ -212,28 +232,28 @@ See source switch :: nim doc --git.url: filename.nim -With the ``git.url`` switch the *See source* hyperlink will appear below each +With the `git.url` switch the *See source* hyperlink will appear below each documented item in your source code pointing to the implementation of that item on a GitHub repository. You can click the link to see the implementation of the item. -The ``git.commit`` switch overrides the hardcoded `devel` branch in config/nimdoc.cfg. +The `git.commit` switch overrides the hardcoded `devel` branch in config/nimdoc.cfg. This is useful to link to a different branch e.g. `--git.commit:master`, or to a tag e.g. `--git.commit:1.2.3` or a commit. Source URLs are generated as `href="${url}/tree/${commit}/${path}#L${line}"` by default and this compatible with GitHub but not with GitLab. -Similarly, ``git.devel`` switch overrides the hardcoded `devel` branch for the `Edit` link which is also useful if you have a different working branch than `devel` e.g. `--git.devel:master`. +Similarly, `git.devel` switch overrides the hardcoded `devel` branch for the `Edit` link which is also useful if you have a different working branch than `devel` e.g. `--git.devel:master`. Edit URLs are generated as `href="${url}/tree/${devel}/${path}#L${line}"` by default. -You can edit ``config/nimdoc.cfg`` and modify the ``doc.item.seesrc`` value with a hyperlink to your own code repository. +You can edit `config/nimdoc.cfg` and modify the `doc.item.seesrc` value with a hyperlink to your own code repository. -In the case of Nim's own documentation, the ``commit`` value is just a commit +In the case of Nim's own documentation, the `commit` value is just a commit hash to append to a formatted URL to https://github.com/nim-lang/Nim. The -``tools/nimweb.nim`` helper queries the current git commit hash during the doc +`tools/nimweb.nim` helper queries the current git commit hash during the doc generation, but since you might be working on an unpublished repository, it -also allows specifying a ``githash`` value in ``web/website.ini`` to force a +also allows specifying a `githash` value in `web/website.ini` to force a specific commit in the output. @@ -241,9 +261,9 @@ Other Input Formats =================== The *Nim compiler* also has support for RST (reStructuredText) files with -the ``rst2html`` and ``rst2tex`` commands. Documents like this one are +the `rst2html` and `rst2tex` commands. Documents like this one are initially written in a dialect of RST which adds support for nim source code -highlighting with the ``.. code-block:: nim`` prefix. ``code-block`` also +highlighting with the `.. code-block:: nim` prefix. `code-block` also supports highlighting of C++ and some other c-like languages. Usage:: @@ -252,17 +272,17 @@ Usage:: Output:: You're reading it! -The ``rst2tex`` command is invoked identically to ``rst2html``, but outputs +The `rst2tex` command is invoked identically to `rst2html`, but outputs a .tex file instead of .html. HTML anchor generation ====================== -When you run the ``rst2html`` command, all sections in the RST document will +When you run the `rst2html` command, all sections in the RST document will get an anchor you can hyperlink to. Usually, you can guess the anchor lower casing the section title and replacing spaces with dashes, and in any case, you -can get it from the table of contents. But when you run the ``doc`` +can get it from the table of contents. But when you run the `doc` command to generate API documentation, some symbol get one or two anchors at the same time: a numerical identifier, or a plain name plus a complex name. @@ -294,31 +314,31 @@ suffix may be added depending on the type of the callable: Callable type Suffix ------------- -------------- proc *empty string* -macro ``.m`` -method ``.e`` -iterator ``.i`` -template ``.t`` -converter ``.c`` +macro `.m` +method `.e` +iterator `.i` +template `.t` +converter `.c` ------------- -------------- -The relationship of type to suffix is made by the proc ``complexName`` in the -``compiler/docgen.nim`` file. Here are some examples of complex names for +The relationship of type to suffix is made by the proc `complexName` in the +`compiler/docgen.nim` file. Here are some examples of complex names for symbols in the `system module `_. -* ``type SomeSignedInt = int | int8 | int16 | int32 | int64`` **=>** +* `type SomeSignedInt = int | int8 | int16 | int32 | int64` **=>** `#SomeSignedInt `_ -* ``var globalRaiseHook: proc (e: ref E_Base): bool {.nimcall.}`` **=>** +* `var globalRaiseHook: proc (e: ref E_Base): bool {.nimcall.}` **=>** `#globalRaiseHook `_ -* ``const NimVersion = "0.0.0"`` **=>** +* `const NimVersion = "0.0.0"` **=>** `#NimVersion `_ -* ``proc getTotalMem(): int {.rtl, raises: [], tags: [].}`` **=>** +* `proc getTotalMem(): int {.rtl, raises: [], tags: [].}` **=>** `#getTotalMem, `_ -* ``proc len[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}`` **=>** +* `proc len[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}` **=>** `#len,seq[T] `_ -* ``iterator pairs[T](a: seq[T]): tuple[key: int, val: T] {.inline.}`` **=>** +* `iterator pairs[T](a: seq[T]): tuple[key: int, val: T] {.inline.}` **=>** `#pairs.i,seq[T] `_ -* ``template newException[](exceptn: typedesc; message: string; - parentException: ref Exception = nil): untyped`` **=>** +* `template newException[](exceptn: typedesc; message: string; + parentException: ref Exception = nil): untyped` **=>** `#newException.t,typedesc,string,ref.Exception `_ @@ -326,13 +346,13 @@ symbols in the `system module `_. Index (idx) file format ======================= -Files with the ``.idx`` extension are generated when you use the `Index +Files with the `.idx` extension are generated when you use the `Index switch <#related-options-index-switch>`_ along with commands to generate documentation from source or text files. You can programmatically generate indices with the `setIndexTerm() `_ and `writeIndexFile() `_ procs. -The purpose of ``idx`` files is to hold the interesting symbols and their HTML +The purpose of `idx` files is to hold the interesting symbols and their HTML references so they can be later concatenated into a big index file with `mergeIndexes() `_. This section documents the file format in detail. @@ -344,7 +364,7 @@ columns is: 1. Mandatory term being indexed. Terms can include quoting according to Nim's rules (e.g. \`^\`). -2. Base filename plus anchor hyperlink (e.g. ``algorithm.html#*,int,SortOrder``). +2. Base filename plus anchor hyperlink (e.g. `algorithm.html#*,int,SortOrder`). 3. Optional human-readable string to display as a hyperlink. If the value is not present or is the empty string, the hyperlink will be rendered using the term. Prefix whitespace indicates that this entry is @@ -353,8 +373,8 @@ columns is: this as a tooltip after hovering a moment over the hyperlink. The index generation tools try to differentiate between documentation -generated from ``.nim`` files and documentation generated from ``.txt`` or -``.rst`` files. The former are always closely related to source code and +generated from `.nim` files and documentation generated from `.txt` or +`.rst` files. The former are always closely related to source code and consist mainly of API entries. The latter are generic documents meant for human reading. @@ -373,7 +393,7 @@ the index file with their third column having as much prefix spaces as their level is in the TOC (at least 1 character). The prefix whitespace helps to filter TOC entries from API or text symbols. This is important because the amount of spaces is used to replicate the hierarchy for document TOCs in the -final index, and TOC entries found in ``.nim`` files are discarded. +final index, and TOC entries found in `.nim` files are discarded. Additional resources @@ -384,8 +404,8 @@ Additional resources `RST Quick Reference `_ -The output for HTML and LaTeX comes from the ``config/nimdoc.cfg`` and -``config/nimdoc.tex.cfg`` configuration files. You can add and modify these +The output for HTML and LaTeX comes from the `config/nimdoc.cfg` and +`config/nimdoc.tex.cfg` configuration files. You can add and modify these files to your project to change the look of the docgen output. You can import the `packages/docutils/rstgen module `_ in your diff --git a/doc/docstyle.rst b/doc/docstyle.rst index 50ff81ac39..7f3fa8cf20 100644 --- a/doc/docstyle.rst +++ b/doc/docstyle.rst @@ -6,14 +6,16 @@ General Guidelines * See also `nep1`_ which should probably be merged here. * Authors should document anything that is exported; documentation for private - procs can be useful too (visible via ``nim doc --docInternal foo.nim``). + procs can be useful too (visible via `nim doc --docInternal foo.nim`). * Within documentation, a period (`.`) should follow each sentence (or sentence fragment) in a comment block. The documentation may be limited to one sentence fragment, but if multiple sentences are within the documentation, each sentence after the first should be complete and in present tense. * Documentation is parsed as a custom ReStructuredText (RST) with partial markdown support. * In nim sources, prefer single backticks to double backticks since it's simpler - and `nim doc` supports it (even in rst files with `nim rst2html`). -* In nim sources, for links, prefer `[link text](link.html)` to ``` `link text`_ ``` + and `nim doc` supports it. Likewise with rst files: `nim rst2html` will render those as monospace, and + adding `.. default-role:: code` to an rst file will also make those render as monospace when rendered directly + in tools such as github. +* In nim sources, for links, prefer `[link text](link.html)` to `` `link text`_ `` since the syntax is simpler and markdown is more common (likewise, `nim rst2html` also supports it in rst files). .. code-block:: nim @@ -26,8 +28,8 @@ General Guidelines Module-level documentation -------------------------- -Documentation of a module is placed at the top of the module itself. Each line of documentation begins with double hashes (``##``). -Sometimes ``##[ multiline docs containing code ]##`` is preferable, see ``lib/pure/times.nim``. +Documentation of a module is placed at the top of the module itself. Each line of documentation begins with double hashes (`##`). +Sometimes `##[ multiline docs containing code ]##` is preferable, see `lib/pure/times.nim`. Code samples are encouraged, and should follow the general RST syntax: .. code-block:: Nim @@ -78,7 +80,7 @@ Whenever an example of usage would be helpful to the user, you should include on doAssert addThree(3, 125, 6) == -122 result = x +% y +% z -The command ``nim doc`` will then correctly syntax highlight the Nim code within the documentation. +The command `nim doc` will then correctly syntax highlight the Nim code within the documentation. Types ----- @@ -114,8 +116,8 @@ Make sure to place the documentation beside or within the object. .. code-block:: Nim type - ## Bad: this documentation disappears because it annotates the ``type`` keyword - ## above, not ``NamedQueue``. + ## Bad: this documentation disappears because it annotates the `type` keyword + ## above, not `NamedQueue`. NamedQueue*[T] = object name*: string ## This becomes the main documentation for the object, which ## is not what we want. @@ -125,7 +127,7 @@ Make sure to place the documentation beside or within the object. Var, Let, and Const ------------------- -When declaring module-wide constants and values, documentation is encouraged. The placement of doc comments is similar to the ``type`` sections. +When declaring module-wide constants and values, documentation is encouraged. The placement of doc comments is similar to the `type` sections. .. code-block:: Nim @@ -135,9 +137,9 @@ When declaring module-wide constants and values, documentation is encouraged. Th [1,2,3], [2,3,1], [3,1,2], - ] ## Doc comment for ``SpreadArray``. + ] ## Doc comment for `SpreadArray`. -Placement of comments in other areas is usually allowed, but will not become part of the documentation output and should therefore be prefaced by a single hash (``#``). +Placement of comments in other areas is usually allowed, but will not become part of the documentation output and should therefore be prefaced by a single hash (`#`). .. code-block:: Nim diff --git a/doc/drnim.rst b/doc/drnim.rst index ee6e0ea172..d33a6066e0 100644 --- a/doc/drnim.rst +++ b/doc/drnim.rst @@ -1,3 +1,5 @@ +.. default-role:: code + =================================== DrNim User Guide =================================== @@ -18,7 +20,7 @@ DrNim's command-line options are the same as the Nim compiler's. DrNim currently only checks the sections of your code that are marked -via ``staticBoundChecks: on``: +via `staticBoundChecks: on`: .. code-block:: nim @@ -31,9 +33,9 @@ overflow errors are *not* prevented. Overflows will be checked for in the future. Later versions of the **Nim compiler** will **assume** that the checks inside -the ``staticBoundChecks: on`` environment have been proven correct and so +the `staticBoundChecks: on` environment have been proven correct and so it will **omit** the runtime checks. If you do not want this behavior, use -instead ``{.push staticBoundChecks: defined(nimDrNim).}``. This way the +instead `{.push staticBoundChecks: defined(nimDrNim).}`. This way the Nim compiler remains unaware of the performed proofs but DrNim will prove your code. @@ -41,7 +43,7 @@ your code. Installation ============ -Run ``koch drnim``, the executable will afterwards be in ``$nim/bin/drnim``. +Run `koch drnim`, the executable will afterwards be in `$nim/bin/drnim`. Motivating Example @@ -67,7 +69,7 @@ detects it and produces the following error message:: cannot prove: i <= len(a) + -1; counter example: i -> 0 a.len -> 0 [IndexCheck] -In other words for ``i == 0`` and ``a.len == 0`` (for example!) there would be +In other words for `i == 0` and `a.len == 0` (for example!) there would be an index out of bounds error. @@ -82,37 +84,37 @@ DrNim adds 4 additional annotations (pragmas) to Nim: - `assume`:idx: These pragmas are ignored by the Nim compiler so that they don't have to -be disabled via ``when defined(nimDrNim)``. +be disabled via `when defined(nimDrNim)`. Invariant --------- -An ``invariant`` is a proposition that must be true after every loop +An `invariant` is a proposition that must be true after every loop iteration, it's tied to the loop body it's part of. Requires -------- -A ``requires`` annotation describes what the function expects to be true -before it's called so that it can perform its operation. A ``requires`` +A `requires` annotation describes what the function expects to be true +before it's called so that it can perform its operation. A `requires` annotation is also called a `precondition`:idx:. Ensures ------- -An ``ensures`` annotation describes what will be true after the function -call. An ``ensures`` annotation is also called a `postcondition`:idx:. +An `ensures` annotation describes what will be true after the function +call. An `ensures` annotation is also called a `postcondition`:idx:. Assume ------ -An ``assume`` annotation describes what DrNim should **assume** to be true +An `assume` annotation describes what DrNim should **assume** to be true in this section of the program. It is an unsafe escape mechanism comparable -to Nim's ``cast`` statement. Use it only when you really know better +to Nim's `cast` statement. Use it only when you really know better than DrNim. You should add a comment to a paper that proves the proposition you assume. @@ -143,12 +145,12 @@ Example: insertionSort Unfortunately, the invariants required to prove that this code is correct take more code than the imperative instructions. However, this effort can be compensated by the fact that the result needs very little testing. Be aware though that -DrNim only proves that after ``insertionSort`` this condition holds:: +DrNim only proves that after `insertionSort` this condition holds:: forall(i in 1..``. -A ``prop`` is either a comparison or a compound:: +The basic syntax is `ensures|requires|invariant: `. +A `prop` is either a comparison or a compound:: prop = nim_bool_expression | prop 'and' prop @@ -186,17 +188,17 @@ A ``prop`` is either a comparison or a compound:: quantifier = 'in' nim_iteration_expression -``nim_iteration_expression`` here is an ordinary expression of Nim code -that describes an iteration space, for example ``1..4`` or ``1.. a.len``. +`nim_bool_expression` here is an ordinary expression of Nim code of +type `bool` like `a == 3` or `23 > a.len`. The supported subset of Nim code that can be used in these expressions -is currently underspecified but ``let`` variables, function parameters -and ``result`` (which represents the function's final result) are amenable +is currently underspecified but `let` variables, function parameters +and `result` (which represents the function's final result) are amenable for verification. The expressions must not have any side-effects and must terminate. -The operators ``forall``, ``exists``, ``->``, ``<->`` have to imported -from ``std / logic``. +The operators `forall`, `exists`, `->`, `<->` have to imported +from `std / logic`. diff --git a/doc/estp.rst b/doc/estp.rst index 805a84eb70..8146562b6a 100644 --- a/doc/estp.rst +++ b/doc/estp.rst @@ -1,3 +1,5 @@ +.. default-role:: code + =================================================== Embedded Stack Trace Profiler (ESTP) User Guide =================================================== @@ -10,21 +12,21 @@ Nim comes with a platform independent profiler - the Embedded Stack Trace Profiler (ESTP). The profiler is *embedded* into your executable. To activate the profiler you need to do: -* compile your program with the ``--profiler:on --stackTrace:on`` command +* compile your program with the `--profiler:on --stackTrace:on` command line options -* import the ``nimprof`` module +* import the `nimprof` module * run your program as usual. -You can in fact look at ``nimprof``'s source code to see how to implement +You can in fact look at `nimprof`'s source code to see how to implement your own profiler. -The setting ``--profiler:on`` defines the conditional symbol ``profiler``. +The setting `--profiler:on` defines the conditional symbol `profiler`. After your program has finished the profiler will create a -file ``profile_results.txt`` containing the profiling results. +file `profile_results.txt` containing the profiling results. Since the profiler works by examining stack traces, it's essential that -the option ``--stackTrace:on`` is active! Unfortunately this means that a +the option `--stackTrace:on` is active! Unfortunately this means that a profiling build is much slower than a release build. @@ -35,12 +37,12 @@ You can also use ESTP as a memory profiler to see which stack traces allocate the most memory and thus create the most GC pressure. It may also help to find memory leaks. To activate the memory profiler you need to do: -* compile your program with the ``--profiler:off --stackTrace:on -d:memProfiler`` - command line options. Yes it's ``--profiler:off``. -* import the ``nimprof`` module +* compile your program with the `--profiler:off --stackTrace:on -d:memProfiler` + command line options. Yes it's `--profiler:off`. +* import the `nimprof` module * run your program as usual. -Define the symbol ``ignoreAllocationSize`` so that only the number of +Define the symbol `ignoreAllocationSize` so that only the number of allocations is counted and the sizes of the memory allocations do not matter. @@ -51,7 +53,7 @@ The results file lists stack traces ordered by significance. The following example file has been generated by profiling the Nim compiler itself: It shows that in total 5.4% of the runtime has been spent -in ``crcFromRope`` or its children. +in `crcFromRope` or its children. In general the stack traces show you immediately where the problem is because the trace acts like an explanation; in traditional profilers you can only find diff --git a/doc/filters.rst b/doc/filters.rst index 40346ecafe..52704411fc 100644 --- a/doc/filters.rst +++ b/doc/filters.rst @@ -1,3 +1,5 @@ +.. default-role:: code + =================== Source Code Filters =================== @@ -8,7 +10,7 @@ A `Source Code Filter (SCF)` transforms the input character stream to an in-mem output stream before parsing. A filter can be used to provide templating systems or preprocessors. -To use a filter for a source file the ``#?`` notation is used:: +To use a filter for a source file the `#?` notation is used:: #? stdtmpl(subsChar = '$', metaChar = '#') #proc generateXML(name, age: string): string = @@ -21,9 +23,9 @@ To use a filter for a source file the ``#?`` notation is used:: As the example shows, passing arguments to a filter can be done just like an ordinary procedure call with named or positional arguments. The available parameters depend on the invoked filter. Before version 0.12.0 of -the language ``#!`` was used instead of ``#?``. +the language `#!` was used instead of `#?`. -**Hint:** With ``--hint[codeBegin]:on`` or ``--verbosity:2`` +**Hint:** With `--hint[codeBegin]:on` or `--verbosity:2` (or higher) while compiling or `nim check`, Nim lists the processed code after each filter application. @@ -32,8 +34,8 @@ Usage First, put your SCF code in a separate file with filters specified in the first line. **Note:** You can name your SCF file with any file extension you want, but the -conventional extension is ``.nimf`` -(it used to be ``.tmpl`` but that was too generic, for example preventing github to +conventional extension is `.nimf` +(it used to be `.tmpl` but that was too generic, for example preventing github to recognize it as Nim source file). If we use `generateXML` code shown above and call the SCF file `xmlGen.nimf` @@ -47,7 +49,7 @@ In your `main.nim`: Pipe operator ============= -Filters can be combined with the ``|`` pipe operator:: +Filters can be combined with the `|` pipe operator:: #? strip(startswith="<") | stdtmpl #proc generateXML(name, age: string): string = @@ -68,10 +70,10 @@ The replace filter replaces substrings in each line. Parameters and their defaults: - ``sub: string = ""`` + `sub: string = ""` the substring that is searched for - ``by: string = ""`` + `by: string = ""` the string the substring is replaced with @@ -83,14 +85,14 @@ each line. Parameters and their defaults: - ``startswith: string = ""`` + `startswith: string = ""` strip only the lines that start with *startswith* (ignoring leading whitespace). If empty every line is stripped. - ``leading: bool = true`` + `leading: bool = true` strip leading whitespace - ``trailing: bool = true`` + `trailing: bool = true` strip trailing whitespace @@ -99,25 +101,25 @@ StdTmpl filter The stdtmpl filter provides a simple templating engine for Nim. The filter uses a line based parser: Lines prefixed with a *meta character* -(default: ``#``) contain Nim code, other lines are verbatim. Because +(default: `#`) contain Nim code, other lines are verbatim. Because indentation-based parsing is not suited for a templating engine, control flow -statements need ``end X`` delimiters. +statements need `end X` delimiters. Parameters and their defaults: - ``metaChar: char = '#'`` + `metaChar: char = '#'` prefix for a line that contains Nim code - ``subsChar: char = '$'`` + `subsChar: char = '$'` prefix for a Nim expression within a template line - ``conc: string = " & "`` + `conc: string = " & "` the operation for concatenation - ``emit: string = "result.add"`` + `emit: string = "result.add"` the operation to emit a string literal - ``toString: string = "$"`` + `toString: string = "$"` the operation that is applied to each expression Example:: @@ -174,18 +176,18 @@ The filter transforms this into: Each line that does not start with the meta character (ignoring leading -whitespace) is converted to a string literal that is added to ``result``. +whitespace) is converted to a string literal that is added to `result`. The substitution character introduces a Nim expression *e* within the string literal. *e* is converted to a string with the *toString* operation -which defaults to ``$``. For strong type checking, set ``toString`` to the +which defaults to `$`. For strong type checking, set `toString` to the empty string. *e* must match this PEG pattern:: e <- [a-zA-Z\128-\255][a-zA-Z0-9\128-\255_.]* / '{' x '}' x <- '{' x+ '}' / [^}]* -To produce a single substitution character it has to be doubled: ``$$`` -produces ``$``. +To produce a single substitution character it has to be doubled: `$$` +produces `$`. The template engine is quite flexible. It is easy to produce a procedure that writes the template code directly to a file:: diff --git a/doc/gc.rst b/doc/gc.rst index 804481cd9f..4455afcbe7 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ======================= Nim's Memory Management ======================= @@ -14,45 +16,50 @@ Nim's Memory Management Introduction ============ -This document describes how the multi-paradigm memory management strategies work. -How to tune the garbage collectors for your needs, like (soft) `realtime systems`:idx:, -and how the memory management strategies that are not garbage collectors work. +A memory-management algorithm optimal for every use-case cannot exist. +Nim provides multiple paradigms for needs ranging from large multi-threaded +applications, to games, hard-realtime systems and small microcontrollers. +This document describes how the management strategies work; +How to tune the garbage collectors for your needs, like (soft) `realtime systems`:idx:, +and how the memory management strategies other than garbage collectors work. + +.. note:: the default GC is incremental, thread-local and not "stop-the-world" Multi-paradigm Memory Management Strategies =========================================== -To choose the memory management strategy use the ``--gc:`` switch. +To choose the memory management strategy use the `--gc:` switch. -- ``--gc:refc``. This is the default GC. It's a +- `--gc:refc`. This is the default GC. It's a deferred reference counting based garbage collector with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local. -- ``--gc:markAndSweep``. Simple Mark-And-Sweep based garbage collector. Heaps are thread-local. -- ``--gc:boehm``. Boehm based garbage collector, it offers a shared heap. -- ``--gc:go``. Go's garbage collector, useful for interoperability with Go. Offers a shared heap. -- ``--gc:arc``. Plain reference counting with +- `--gc:markAndSweep`. Simple Mark-And-Sweep based garbage collector. Heaps are thread-local. +- `--gc:boehm`. Boehm based garbage collector, it offers a shared heap. +- `--gc:go`. Go's garbage collector, useful for interoperability with Go. Offers a shared heap. +- `--gc:arc`. Plain reference counting with `move semantic optimizations `_, offers a shared heap. It offers deterministic performance for `hard realtime`:idx: systems. Reference cycles cause memory leaks, beware. -- ``--gc:orc``. Same as ``--gc:arc`` but adds a cycle collector based on "trial deletion". +- `--gc:orc`. Same as `--gc:arc` but adds a cycle collector based on "trial deletion". Unfortunately, that makes its performance profile hard to reason about so it is less useful for hard real-time systems. -- ``--gc:none``. No memory management strategy nor a garbage collector. Allocated memory is - simply never freed. You should use ``--gc:arc`` instead. +- `--gc:none`. No memory management strategy nor a garbage collector. Allocated memory is + simply never freed. You should use `--gc:arc` instead. ================== ======== ================= ============== =================== Memory Management Heap Reference Cycles Stop-The-World Command line switch ================== ======== ================= ============== =================== -RefC Local Cycle Collector No ``--gc:refc`` -Mark & Sweep Local Cycle Collector No ``--gc:markAndSweep`` -ARC Shared Leak No ``--gc:arc`` -ORC Shared Cycle Collector No ``--gc:orc`` -Boehm Shared Cycle Collector Yes ``--gc:boehm`` -Go Shared Cycle Collector Yes ``--gc:go`` -None Manual Manual Manual ``--gc:none`` +RefC Local Cycle Collector No `--gc:refc` +Mark & Sweep Local Cycle Collector No `--gc:markAndSweep` +ARC Shared Leak No `--gc:arc` +ORC Shared Cycle Collector No `--gc:orc` +Boehm Shared Cycle Collector Yes `--gc:boehm` +Go Shared Cycle Collector Yes `--gc:go` +None Manual Manual Manual `--gc:none` ================== ======== ================= ============== =================== JavaScript's garbage collector is used for the `JavaScript and NodeJS @@ -68,14 +75,14 @@ Cycle collector --------------- The cycle collector can be en-/disabled independently from the other parts of -the garbage collector with ``GC_enableMarkAndSweep`` and ``GC_disableMarkAndSweep``. +the garbage collector with `GC_enableMarkAndSweep` and `GC_disableMarkAndSweep`. Soft real-time support ---------------------- +---------------------- To enable real-time support, the symbol `useRealtimeGC`:idx: needs to be -defined via ``--define:useRealtimeGC`` (you can put this into your config +defined via `--define:useRealtimeGC` (you can put this into your config file as well). With this switch the garbage collector supports the following operations: @@ -83,29 +90,29 @@ With this switch the garbage collector supports the following operations: proc GC_setMaxPause*(maxPauseInUs: int) proc GC_step*(us: int, strongAdvice = false, stackSize = -1) -The unit of the parameters ``maxPauseInUs`` and ``us`` is microseconds. +The unit of the parameters `maxPauseInUs` and `us` is microseconds. 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 + 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`` + 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 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``, + 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. + 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. @@ -125,16 +132,16 @@ Time measurement with garbage collectors ---------------------------------------- The garbage collectors' way of measuring time uses -(see ``lib/system/timers.nim`` for the implementation): +(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. +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. -Define the symbol ``reportMissedDeadlines`` to make the +Define the symbol `reportMissedDeadlines` to make the garbage collector output whenever it missed a deadline. The reporting will be enhanced and supported by the API in later versions of the collector. @@ -143,9 +150,9 @@ Tweaking the garbage collector ------------------------------ The collector checks whether there is still time left for its work after -every ``workPackage``'th iteration. This is currently set to 100 which means +every `workPackage`'th iteration. This is currently set to 100 which means that up to 100 objects are traversed and freed before it checks again. Thus -``workPackage`` affects the timing granularity and may need to be tweaked in +`workPackage` affects the timing granularity and may need to be tweaked in highly specialized environments or for older hardware. @@ -153,22 +160,22 @@ Keeping track of memory ======================= If you need to pass around memory allocated by Nim to C, you can use the -procs ``GC_ref`` and ``GC_unref`` to mark objects as referenced to avoid them +procs `GC_ref` and `GC_unref` to mark objects as referenced to avoid them being freed by the garbage collector. Other useful procs from `system `_ you can use to keep track of memory are: -* ``getTotalMem()`` Returns the amount of total memory managed by the garbage collector. -* ``getOccupiedMem()`` Bytes reserved by the garbage collector and used by objects. -* ``getFreeMem()`` Bytes reserved by the garbage collector and not in use. -* ``GC_getStatistics()`` Garbage collector statistics as a human-readable string. +* `getTotalMem()` Returns the amount of total memory managed by the garbage collector. +* `getOccupiedMem()` Bytes reserved by the garbage collector and used by objects. +* `getFreeMem()` Bytes reserved by the garbage collector and not in use. +* `GC_getStatistics()` Garbage collector statistics as a human-readable string. These numbers are usually only for the running thread, not for the whole heap, -with the exception of ``--gc:boehm`` and ``--gc:go``. +with the exception of `--gc:boehm` and `--gc:go`. -In addition to ``GC_ref`` and ``GC_unref`` you can avoid the garbage collector by manually -allocating memory with procs like ``alloc``, ``alloc0``, ``allocShared``, ``allocShared0`` or ``allocCStringArray``. +In addition to `GC_ref` and `GC_unref` you can avoid the garbage collector by manually +allocating memory with procs like `alloc`, `alloc0`, `allocShared`, `allocShared0` or `allocCStringArray`. The garbage collector won't try to free them, you need to call their respective *dealloc* pairs -(``dealloc``, ``deallocShared``, ``deallocCStringArray``, etc) +(`dealloc`, `deallocShared`, `deallocCStringArray`, etc) when you are done with them or they will leak. @@ -177,12 +184,12 @@ Heap dump The heap dump feature is still in its infancy, but it already proved useful for us, so it might be useful for you. To get a heap dump, compile -with ``-d:nimTypeNames`` and call ``dumpNumberOfInstances`` at a strategic place in your program. +with `-d:nimTypeNames` and call `dumpNumberOfInstances` at a strategic place in your program. This produces a list of the used types in your program and for every type the total amount of object instances for this type as well as the total amount of bytes these instances take up. The numbers count the number of objects in all garbage collector heaps, they refer to all running threads, not only to the current thread. (The current thread -would be the thread that calls ``dumpNumberOfInstances``.) This might +would be the thread that calls `dumpNumberOfInstances`.) This might change in later versions. diff --git a/doc/grammar.txt b/doc/grammar.txt index f5e619ebcd..0d5eef179e 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -119,7 +119,7 @@ raiseStmt = 'raise' optInd expr? yieldStmt = 'yield' optInd expr? discardStmt = 'discard' optInd expr? breakStmt = 'break' optInd expr? -continueStmt = 'break' optInd expr? +continueStmt = 'continue' optInd expr? condStmt = expr colcom stmt COMMENT? (IND{=} 'elif' expr colcom stmt)* (IND{=} 'else' colcom stmt)? diff --git a/doc/hcr.rst b/doc/hcr.rst index d2e13e1c7d..7e9d71da39 100644 --- a/doc/hcr.rst +++ b/doc/hcr.rst @@ -1,3 +1,5 @@ +.. default-role:: code + =================================== Hot code reloading =================================== @@ -19,8 +21,8 @@ so we have to use a helper module where the major logic we want to change during development resides. In this example, we use SDL2 to create a window and we reload the logic -code when ``F9`` is pressed. The important lines are marked with ``#***``. -To install SDL2 you can use ``nimble install sdl2``. +code when `F9` is pressed. The important lines are marked with `#***`. +To install SDL2 you can use `nimble install sdl2`. .. code-block:: nim @@ -29,7 +31,7 @@ To install SDL2 you can use ``nimble install sdl2``. import sdl2 #*** import the hotcodereloading stdlib module *** - import hotcodereloading + import std/hotcodereloading var runGame*: bool = true var window: WindowPtr @@ -125,7 +127,7 @@ Then recompile the project, but do not restart or quit the mymain.exe program! nim c --hotcodereloading:on mymain.nim -Now give the ``mymain`` SDL window the focus, press F9, and watch the +Now give the `mymain` SDL window the focus, press F9, and watch the updated version of the program. @@ -133,8 +135,8 @@ updated version of the program. Reloading API ============= -One can use the special event handlers ``beforeCodeReload`` and -``afterCodeReload`` to reset the state of a particular variable or to force +One can use the special event handlers `beforeCodeReload` and +`afterCodeReload` to reset the state of a particular variable or to force the execution of certain statements: .. code-block:: Nim @@ -178,8 +180,8 @@ It's expected that most projects will implement the reloading with a suitable build-system triggered IPC notification mechanism, but a polling solution is also possible through the provided `hasAnyModuleChanged()`:idx: API. -In order to access ``beforeCodeReload``, ``afterCodeReload``, ``hasModuleChanged`` -or ``hasAnyModuleChanged`` one must import the `hotcodereloading`:idx: module. +In order to access `beforeCodeReload`, `afterCodeReload`, `hasModuleChanged` +or `hasAnyModuleChanged` one must import the `hotcodereloading`:idx: module. Native code targets @@ -187,11 +189,11 @@ Native code targets Native projects using the hot code reloading option will be implicitly compiled with the `-d:useNimRtl` option and they will depend on both -the ``nimrtl`` library and the ``nimhcr`` library which implements the -hot code reloading run-time. Both libraries can be found in the ``lib`` +the `nimrtl` library and the `nimhcr` library which implements the +hot code reloading run-time. Both libraries can be found in the `lib` folder of Nim and can be compiled into dynamic libraries to satisfy runtime demands of the example code above. An example of compiling -``nimhcr.nim`` and ``nimrtl.nim`` when the source dir of Nim is installed +`nimhcr.nim` and `nimrtl.nim` when the source dir of Nim is installed with choosenim follows. :: @@ -208,16 +210,16 @@ with choosenim follows. # source directory (.dll for Windows, .so for Unix, .dylib for MacOS) All modules of the project will be compiled to separate dynamic link -libraries placed in the ``nimcache`` directory. Please note that during +libraries placed in the `nimcache` directory. Please note that during the execution of the program, the hot code reloading run-time will load only copies of these libraries in order to not interfere with any newly issued build commands. The main module of the program is considered non-reloadable. Please note that procs from reloadable modules should not appear in the call stack of -program while ``performCodeReload`` is being called. Thus, the main module +program while `performCodeReload` is being called. Thus, the main module is a suitable place for implementing a program loop capable of calling -``performCodeReload``. +`performCodeReload`. Please note that reloading won't be possible when any of the type definitions in the program has been changed. When closure iterators are used (directly or diff --git a/doc/idetools.rst b/doc/idetools.rst index ac3b92947e..dcafaf45f4 100644 --- a/doc/idetools.rst +++ b/doc/idetools.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ================================ Nim IDE Integration Guide ================================ @@ -18,8 +20,8 @@ Note: this is mostly outdated, see instead `nimsuggest `_ Nim differs from many other compilers in that it is really fast, and being so fast makes it suited to provide external queries for text editors about the source code being written. Through the -``idetools`` command of `the compiler `_, any IDE -can query a ``.nim`` source file and obtain useful information like +`idetools` command of `the compiler `_, any IDE +can query a `.nim` source file and obtain useful information like definition of symbols or suggestions for completion. This document will guide you through the available options. If you @@ -36,7 +38,7 @@ Specifying the location of the query ------------------------------------ All of the available idetools commands require you to specify a -query location through the ``--track`` or ``--trackDirty`` switches. +query location through the `--track` or `--trackDirty` switches. The general idetools invocations are:: nim idetools --track:FILE,LINE,COL proj.nim @@ -45,35 +47,35 @@ Or:: nim idetools --trackDirty:DIRTY_FILE,FILE,LINE,COL proj.nim -``proj.nim`` +`proj.nim` This is the main *project* filename. Most of the time you will pass in the same as **FILE**, but for bigger projects this is the file which is used as main entry point for the program, the one which users compile to generate a final binary. -```` +`` This would be any of the other idetools available options, like - ``--def`` or ``--suggest`` explained in the following sections. + `--def` or `--suggest` explained in the following sections. -``COL`` +`COL` An integer with the column you are going to query. For the compiler columns start at zero, so the first column will be **0** and the last in an 80 column terminal will be **79**. -``LINE`` +`LINE` An integer with the line you are going to query. For the compiler lines start at **1**. -``FILE`` +`FILE` The file you want to perform the query on. Usually you will pass in the same value as **proj.nim**. -``DIRTY_FILE`` +`DIRTY_FILE` The **FILE** parameter is enough for static analysis, but IDEs tend to have *unsaved buffers* where the user may still be in the middle of typing a line. In such situations the IDE can save the current contents to a temporary file and then use the - ``--trackDirty`` switch. + `--trackDirty` switch. Dirty files are likely to contain errors and they are usually compiled partially only to the point needed to service the @@ -91,7 +93,7 @@ Or:: Definitions ----------- -The ``--def`` idetools switch performs a query about the definition +The `--def` idetools switch performs a query about the definition of a specific symbol. If available, idetools will answer with the type, source file, line/column information and other accessory data if available like a docstring. With this information an IDE can @@ -112,7 +114,7 @@ can't find any valid symbol matching the position of the query. Suggestions ----------- -The ``--suggest`` idetools switch performs a query about possible +The `--suggest` idetools switch performs a query about possible completion symbols at some point in the file. IDEs can easily provide an autocompletion feature where the IDE scans the current file (and related ones, if it knows about the language being edited and follows @@ -134,7 +136,7 @@ Idetools will try to return the suggestions sorted first by scope Invocation context ------------------ -The ``--context`` idetools switch is very similar to the suggestions +The `--context` idetools switch is very similar to the suggestions switch, but instead of being used after the user has typed a dot character, this one is meant to be used after the user has typed an opening brace to start typing parameters. @@ -143,7 +145,7 @@ an opening brace to start typing parameters. Symbol usages ------------- -The ``--usages`` idetools switch lists all usages of the symbol at +The `--usages` idetools switch lists all usages of the symbol at a position. IDEs can use this to find all the places in the file where the symbol is used and offer the user to rename it in all places at the same time. Again, a pure string based search and @@ -207,15 +209,15 @@ Idetools outputs is always returned on single lines separated by tab characters (``\t``). The values of each column are: 1. Three characters indicating the type of returned answer (e.g. - def for definition, ``sug`` for suggestion, etc). -2. Type of the symbol. This can be ``skProc``, ``skLet``, and just - about any of the enums defined in the module ``compiler/ast.nim``. + def for definition, `sug` for suggestion, etc). +2. Type of the symbol. This can be `skProc`, `skLet`, and just + about any of the enums defined in the module `compiler/ast.nim`. 3. Full qualified path of the symbol. If you are querying a symbol - defined in the ``proj.nim`` file, this would have the form - ``proj.symbolName``. + defined in the `proj.nim` file, this would have the form + `proj.symbolName`. 4. Type/signature. For variables and enums this will contain the type of the symbol, for procs, methods and templates this will - contain the full unique signature (e.g. ``proc (File)``). + contain the full unique signature (e.g. `proc (File)`). 5. Full path to the file containing the symbol. 6. Line where the symbol is located in the file. Lines start to count at **1**. @@ -329,7 +331,7 @@ skLet let text = "some text" --> col 2: $MODULE.text - col 3: TaintedString + col 3: string col 7: "" @@ -374,8 +376,8 @@ While at the language level a method is differentiated from others by the parameters and return value, the signature of the method returned by idetools returns also the pragmas for the method. -Note that at the moment the word ``proc`` is returned for the -signature of the found method instead of the expected ``method``. +Note that at the moment the word `proc` is returned for the +signature of the found method instead of the expected `method`. This may change in the future. | **Third column**: module + [n scope nesting] + method name. @@ -517,7 +519,7 @@ Test suite ========== To verify that idetools is working properly there are files in the -``tests/caas/`` directory which provide unit testing. If you find +`tests/caas/` directory which provide unit testing. If you find odd idetools behaviour and are able to reproduce it, you are welcome to report it as a bug and add a test to the suite to avoid future regressions. @@ -533,27 +535,27 @@ run it manually. First you have to compile the tester:: $ cd my/nim/checkout/tests $ nim c testament/caasdriver.nim -Running the ``caasdriver`` without parameters will attempt to process +Running the `caasdriver` without parameters will attempt to process all the test cases in all three operation modes. If a test succeeds nothing will be printed and the process will exit with zero. If any test fails, the specific line of the test preceding the failure and the failure itself will be dumped to stdout, along with a final indicator of the success state and operation mode. You can pass the -parameter ``verbose`` to force all output even on successful tests. +parameter `verbose` to force all output even on successful tests. -The normal operation mode is called ``ProcRun`` and it involves +The normal operation mode is called `ProcRun` and it involves starting a process for each command or query, similar to running -manually the Nim compiler from the commandline. The ``CaasRun`` -mode starts a server process to answer all queries. The ``SymbolProcRun`` +manually the Nim compiler from the commandline. The `CaasRun` +mode starts a server process to answer all queries. The `SymbolProcRun` mode is used by compiler developers. This means that running all -tests involves processing all ``*.txt`` files three times, which +tests involves processing all `*.txt` files three times, which can be quite time consuming. If you don't want to run all the test case files you can pass any -substring as a parameter to ``caasdriver``. Only files matching the +substring as a parameter to `caasdriver`. Only files matching the passed substring will be run. The filtering doesn't use any globbing metacharacters, it's a plain match. For example, to run only -``*-compile*.txt`` tests in verbose mode:: +`*-compile*.txt` tests in verbose mode:: ./caasdriver verbose -compile @@ -561,18 +563,18 @@ metacharacters, it's a plain match. For example, to run only Test case file format --------------------- -All the ``tests/caas/*.txt`` files encode a session with the compiler: +All the `tests/caas/*.txt` files encode a session with the compiler: * The first line indicates the main project file. -* Lines starting with ``>`` indicate a command to be sent to the +* Lines starting with `>` indicate a command to be sent to the compiler and the lines following a command include checks for - expected or forbidden output (``!`` for forbidden). + expected or forbidden output (`!` for forbidden). -* If a line starts with ``#`` it will be ignored completely, so you +* If a line starts with `#` it will be ignored completely, so you can use that for comments. -* Since some cases are specific to either ``ProcRun`` or ``CaasRun`` +* Since some cases are specific to either `ProcRun` or `CaasRun` modes, you can prefix a line with the mode and the line will be processed only in that mode. diff --git a/doc/intern.rst b/doc/intern.rst index 5de0c35d5c..2456b25fde 100644 --- a/doc/intern.rst +++ b/doc/intern.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ========================================= Internals of the Nim Compiler ========================================= @@ -19,19 +21,19 @@ The Nim project's directory structure is: ============ =================================================== Path Purpose ============ =================================================== -``bin`` generated binary files -``build`` generated C code for the installation -``compiler`` the Nim compiler itself; note that this +`bin` generated binary files +`build` generated C code for the installation +`compiler` the Nim compiler itself; note that this code has been translated from a bootstrapping version written in Pascal, so the code is **not** a poster child of good Nim code -``config`` configuration files for Nim -``dist`` additional packages for the distribution -``doc`` the documentation; it is a bunch of +`config` configuration files for Nim +`dist` additional packages for the distribution +`doc` the documentation; it is a bunch of reStructuredText files -``lib`` the Nim library -``web`` website of Nim; generated by ``nimweb`` - from the ``*.txt`` and ``*.nimf`` files +`lib` the Nim library +`web` website of Nim; generated by `nimweb` + from the `*.txt` and `*.nimf` files ============ =================================================== @@ -53,7 +55,7 @@ And for a debug version compatible with GDB:: nim c koch.nim ./koch boot --debuginfo --linedir:on -The ``koch`` program is Nim's maintenance script. It is a replacement for +The `koch` program is Nim's maintenance script. It is a replacement for make and shell scripting with the advantage that it is much more portable. More information about its options can be found in the `koch `_ documentation. @@ -67,8 +69,8 @@ Coding Guidelines * Max line length is 80 characters. * Provide spaces around binary operators if that enhances readability. * Use a space after a colon, but not before it. -* [deprecated] Start types with a capital ``T``, unless they are - pointers/references which start with ``P``. +* [deprecated] Start types with a capital `T`, unless they are + pointers/references which start with `P`. See also the `API naming design `_ document. @@ -81,12 +83,12 @@ portable programming language (within certain limits) and Nim generates C code, porting the code generator is not necessary. POSIX-compliant systems on conventional hardware are usually pretty easy to -port: Add the platform to ``platform`` (if it is not already listed there), +port: Add the platform to `platform` (if it is not already listed there), check that the OS, System modules work and recompile Nim. The only case where things aren't as easy is when the garbage collector needs some assembler tweaking to work. The standard -version of the GC uses C's ``setjmp`` function to store all registers +version of the GC uses C's `setjmp` function to store all registers on the hardware stack. It may be necessary that the new platform needs to replace this generic code by some assembler code. @@ -111,7 +113,7 @@ Complex assignments We already know the type information as a graph in the compiler. Thus we need to serialize this graph as RTTI for C code generation. -Look at the file ``lib/system/hti.nim`` for more information. +Look at the file `lib/system/hti.nim` for more information. Rebuilding the compiler ======================== @@ -139,7 +141,7 @@ Debugging the compiler ====================== You can of course use GDB or Visual Studio to debug the -compiler (via ``--debuginfo --lineDir:on``). However, there +compiler (via `--debuginfo --lineDir:on`). However, there are also lots of procs that aid in debugging: @@ -170,19 +172,19 @@ These procs may not be imported by a module. You can import them directly for de from renderer import renderTree from msgs import `??` -To create a new compiler for each run, use ``koch temp``:: +To create a new compiler for each run, use `koch temp`:: ./koch temp c /tmp/test.nim -``koch temp`` creates a debug build of the compiler, which is useful +`koch temp` creates a debug build of the compiler, which is useful to create stacktraces for compiler debugging. See also `Rebuilding the compiler`_ if you need more control. Bisecting for regressions ========================= -``koch temp`` returns 125 as the exit code in case the compiler -compilation fails. This exit code tells ``git bisect`` to skip the +`koch temp` returns 125 as the exit code in case the compiler +compilation fails. This exit code tells `git bisect` to skip the current commit.:: git bisect start bad-commit good-commit @@ -219,15 +221,15 @@ examples how the AST represents each syntactic structure. How the RTL is compiled ======================= -The ``system`` module contains the part of the RTL which needs support by +The `system` module contains the part of the RTL which needs support by compiler magic (and the stuff that needs to be in it because the spec says so). The C code generator generates the C code for it, just like any other -module. However, calls to some procedures like ``addInt`` are inserted by -the CCG. Therefore the module ``magicsys`` contains a table (``compilerprocs``) -with all symbols that are marked as ``compilerproc``. ``compilerprocs`` are -needed by the code generator. A ``magic`` proc is not the same as a -``compilerproc``: A ``magic`` is a proc that needs compiler magic for its -semantic checking, a ``compilerproc`` is a proc that is used by the code +module. However, calls to some procedures like `addInt` are inserted by +the CCG. Therefore the module `magicsys` contains a table (`compilerprocs`) +with all symbols that are marked as `compilerproc`. `compilerprocs` are +needed by the code generator. A `magic` proc is not the same as a +`compilerproc`: A `magic` is a proc that needs compiler magic for its +semantic checking, a `compilerproc` is a proc that is used by the code generator. @@ -254,11 +256,11 @@ This solves the problem without having to special case the logic that fills the internal seqs which are affected by the pragmas. In fact, this describes how the AST should be stored in the database, -as a "shallow" tree. Let's assume we compile module ``m`` with the +as a "shallow" tree. Let's assume we compile module `m` with the following contents: .. code-block:: nim - import strutils + import std/strutils var x*: int = 90 {.compile: "foo.c".} @@ -270,7 +272,7 @@ following contents: Conceptually this is the AST we store for the module: .. code-block:: nim - import strutils + import std/strutils var x* {.compile: "foo.c".} @@ -279,21 +281,21 @@ Conceptually this is the AST we store for the module: static: echo "static" -The symbol's ``ast`` field is loaded lazily, on demand. This is where most +The symbol's `ast` field is loaded lazily, on demand. This is where most savings come from, only the shallow outer AST is reconstructed immediately. -It is also important that the replay involves the ``import`` statement so +It is also important that the replay involves the `import` statement so that dependencies are resolved properly. Shared global compiletime state ------------------------------- -Nim allows ``.global, compiletime`` variables that can be filled by macro +Nim allows `.global, compiletime` variables that can be filled by macro invocations across different modules. This feature breaks modularity in a severe way. Plenty of different solutions have been proposed: -- Restrict the types of global compiletime variables to ``Set[T]`` or +- Restrict the types of global compiletime variables to `Set[T]` or similar unordered, only-growable collections so that we can track the module's write effects to these variables and reapply the changes in a different order. @@ -306,7 +308,7 @@ severe way. Plenty of different solutions have been proposed: Since we adopt the "replay the top level statements" idea, the natural solution to this problem is to emit pseudo top level statements that reflect the mutations done to the global variable. However, this is -MUCH harder than it sounds, for example ``squeaknim`` uses this +MUCH harder than it sounds, for example `squeaknim` uses this snippet: .. code-block:: nim @@ -314,12 +316,12 @@ snippet: "\t^self externalCallFailed\C!\C\C") stCode.add(st & "\C\t\"Generated by NimSqueak\"\C\t" & apicall) -We can "replay" ``stCode.add`` only if the values of ``st`` -and ``apicall`` are known. And even then a hash table's ``add`` with its +We can "replay" `stCode.add` only if the values of `st` +and `apicall` are known. And even then a hash table's `add` with its hashing mechanism is too hard to replay. -In practice, things are worse still, consider ``someGlobal[i][j].add arg``. -We only know the root is ``someGlobal`` but the concrete path to the data +In practice, things are worse still, consider `someGlobal[i][j].add arg`. +We only know the root is `someGlobal` but the concrete path to the data is unknown as is the value that is added. We could compute a "diff" between the global states and use that to compute a symbol patchset, but this is quite some work, expensive to do at runtime (it would need to run after @@ -342,7 +344,7 @@ an alien API and works with some existing Nimble packages, at least. On the other hand, in Nim's future I would like to replace the VM by native code. A diff algorithm wouldn't work for that. -Instead the native code would work with an API like ``put``, ``get``: +Instead the native code would work with an API like `put`, `get`: .. code-block:: nim @@ -350,7 +352,7 @@ Instead the native code would work with an API like ``put``, ``get``: proc cacheGet*(key: string): NimNode The API should embrace the AST diffing notion: See the -module ``macrocache`` for the final details. +module `macrocache` for the final details. @@ -382,9 +384,9 @@ too. Type converters fall into this category: if 1: echo "ugly, but should work" -If in the above example module ``B`` is re-compiled, but ``A`` is not then -``B`` needs to be aware of ``toBool`` even though ``toBool`` is not referenced -in ``B`` *explicitly*. +If in the above example module `B` is re-compiled, but `A` is not then +`B` needs to be aware of `toBool` even though `toBool` is not referenced +in `B` *explicitly*. Both the multi method and the type converter problems are solved by the AST replay implementation. @@ -395,7 +397,7 @@ Generics We cache generic instantiations and need to ensure this caching works well with the incremental compilation feature. Since the cache is -attached to the ``PSym`` datastructure, it should work without any +attached to the `PSym` datastructure, it should work without any special logic. @@ -405,22 +407,22 @@ Backend issues - Init procs must not be "forgotten" to be called. - Files must not be "forgotten" to be linked. - Method dispatchers are global. -- DLL loading via ``dlsym`` is global. +- DLL loading via `dlsym` is global. - Emulated thread vars are global. However the biggest problem is that dead code elimination breaks modularity! -To see why, consider this scenario: The module ``G`` (for example the huge +To see why, consider this scenario: The module `G` (for example the huge Gtk2 module...) is compiled with dead code elimination turned on. So none -of ``G``'s procs is generated at all. +of `G`'s procs is generated at all. -Then module ``B`` is compiled that requires ``G.P1``. Ok, no problem, -``G.P1`` is loaded from the symbol file and ``G.c`` now contains ``G.P1``. +Then module `B` is compiled that requires `G.P1`. Ok, no problem, +`G.P1` is loaded from the symbol file and `G.c` now contains `G.P1`. -Then module ``A`` (that depends on ``B`` and ``G``) is compiled and ``B`` -and ``G`` are left unchanged. ``A`` requires ``G.P2``. +Then module `A` (that depends on `B` and `G`) is compiled and `B` +and `G` are left unchanged. `A` requires `G.P2`. -So now ``G.c`` MUST contain both ``P1`` and ``P2``, but we haven't even -loaded ``P1`` from the symbol file, nor do we want to because we then quickly +So now `G.c` MUST contain both `P1` and `P2`, but we haven't even +loaded `P1` from the symbol file, nor do we want to because we then quickly would restore large parts of the whole program. @@ -428,7 +430,7 @@ Solution ~~~~~~~~ The backend must have some logic so that if the currently processed module -is from the compilation cache, the ``ast`` field is not accessed. Instead +is from the compilation cache, the `ast` field is not accessed. Instead the generated C(++) for the symbol's body needs to be cached too and inserted back into the produced C file. This approach seems to deal with all the outlined problems above. @@ -444,8 +446,8 @@ in mind: keeps allocating memory! Thus a stack overflow may happen, hiding the real issue. * What seem to be C code generation problems is often a bug resulting from - not producing prototypes, so that some types default to ``cint``. Testing - without the ``-w`` option helps! + not producing prototypes, so that some types default to `cint`. Testing + without the `-w` option helps! The Garbage Collector @@ -464,9 +466,9 @@ 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 +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`` +is extremely important that `pointer` is not confused with a `PCell` as this would lead to a memory corruption. @@ -474,9 +476,9 @@ The CellSet data structure -------------------------- The GC depends on an extremely efficient datastructure for storing a -set of pointers - this is called a ``TCellSet`` in the source code. +set of pointers - this is called a `TCellSet` in the source code. Inserting, deleting and searching are done in constant time. However, -modifying a ``TCellSet`` during traversal leads to undefined behaviour. +modifying a `TCellSet` during traversal leads to undefined behaviour. .. code-block:: Nim type @@ -559,11 +561,11 @@ Code generation for closures is implemented by `lambda lifting`:idx:. Design ------ -A ``closure`` proc var can call ordinary procs of the default Nim calling +A `closure` proc var can call ordinary procs of the default Nim calling convention. But not the other way round! A closure is implemented as a -``tuple[prc, env]``. ``env`` can be nil implying a call without a closure. -This means that a call through a closure generates an ``if`` but the -interoperability is worth the cost of the ``if``. Thunk generation would be +`tuple[prc, env]`. `env` can be nil implying a call without a closure. +This means that a call through a closure generates an `if` but the +interoperability is worth the cost of the `if`. Thunk generation would be possible too, but it's slightly more effort to implement. Tests with GCC on Amd64 showed that it's really beneficial if the @@ -579,7 +581,7 @@ A thunk would need to call 'returnsDefaultCC[i]' somehow and that would require an *additional* closure generation... Ok, not really, but it requires to pass the function to call. So we'd end up with 2 indirect calls instead of one. Another much more severe problem which this solution is that it's not GC-safe -to pass a proc pointer around via a generic ``ref`` type. +to pass a proc pointer around via a generic `ref` type. Example code: @@ -695,15 +697,15 @@ Accumulator Internals --------- -Lambda lifting is implemented as part of the ``transf`` pass. The ``transf`` +Lambda lifting is implemented as part of the `transf` pass. The `transf` pass generates code to setup the environment and to pass it around. However, this pass does not change the types! So we have some kind of mismatch here; on the one hand the proc expression becomes an explicit tuple, on the other hand the tyProc(ccClosure) type is not changed. For C code generation it's also -important the hidden formal param is ``void*`` and not something more +important the hidden formal param is `void*` and not something more specialized. However the more specialized env type needs to passed to the -backend somehow. We deal with this by modifying ``s.ast[paramPos]`` to contain -the formal hidden parameter, but not ``s.typ``! +backend somehow. We deal with this by modifying `s.ast[paramPos]` to contain +the formal hidden parameter, but not `s.typ`! Integer literals: diff --git a/doc/koch.rst b/doc/koch.rst index 01c6908164..1eb02d7852 100644 --- a/doc/koch.rst +++ b/doc/koch.rst @@ -1,3 +1,5 @@ +.. default-role:: code + =============================== Nim maintenance script =============================== @@ -17,7 +19,7 @@ Introduction The `koch`:idx: program is Nim's maintenance script. It is a replacement for make and shell scripting with the advantage that it is much more portable. -The word *koch* means *cook* in German. ``koch`` is used mainly to build the +The word *koch* means *cook* in German. `koch` is used mainly to build the Nim compiler, but it can also be used for other tasks. This document describes the supported commands and their options. @@ -39,8 +41,8 @@ options: Use the linenoise library for interactive mode (not needed on Windows). After compilation is finished you will hopefully end up with the nim -compiler in the ``bin`` directory. You can add Nim's ``bin`` directory to -your ``$PATH`` or use the install command to place it where it will be +compiler in the `bin` directory. You can add Nim's `bin` directory to +your `$PATH` or use the install command to place it where it will be found. csource command @@ -54,30 +56,37 @@ temp command ------------ The temp command builds the Nim compiler but with a different final name -(``nim_temp``), so it doesn't overwrite your normal compiler. You can use +(`nim_temp`), so it doesn't overwrite your normal compiler. You can use this command to test different options, the same you would issue for the `boot command <#commands-boot-command>`_. test command ------------ -The `test`:idx: command can also be invoked with the alias ``tests``. This -command will compile and run ``testament/tester.nim``, which is the main -driver of Nim's test suite. You can pass options to the ``test`` command, +The `test`:idx: command can also be invoked with the alias `tests`. This +command will compile and run `testament/tester.nim`, which is the main +driver of Nim's test suite. You can pass options to the `test` command, they will be forwarded to the tester. See its source code for available options. web command ----------- -The `web`:idx: command converts the documentation in the ``doc`` directory +The `web`:idx: command converts the documentation in the `doc` directory from rst to HTML. It also repeats the same operation but places the result in -the ``web/upload`` which can be used to update the website at +the `web/upload` which can be used to update the website at https://nim-lang.org. By default, the documentation will be built in parallel using the number of available CPU cores. If any documentation build sub-commands fail, they will be rerun in serial fashion so that meaningful error output can be gathered for -inspection. The ``--parallelBuild:n`` switch or configuration option can be +inspection. The `--parallelBuild:n` switch or configuration option can be used to force a specific number of parallel jobs or run everything serially -from the start (``n == 1``). +from the start (`n == 1`). + +pdf command +----------- + +The `pdf`:idx: command builds PDF versions of Nim documentation: Manual, +Tutorial and a few other documents. To run it one needs to +`install Latex/pdflatex `_ first. diff --git a/doc/lib.rst b/doc/lib.rst index 3c80fd343a..62e02815c6 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ==================== Nim Standard Library ==================== @@ -9,7 +11,7 @@ Nim Standard Library Nim's library is divided into *pure libraries*, *impure libraries*, and *wrappers*. -Pure libraries do not depend on any external ``*.dll`` or ``lib*.so`` binary +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. @@ -32,16 +34,16 @@ 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 + 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``. + Basic Nim thread support. **Note:** This is part of the system module. Do not + import it explicitly. Enabled with `--threads:on`. -* `channels `_ - Nim message passing support for threads. **Note**: This is part of the - system module. Do not import it explicitly. Enabled with ``--threads:on``. +* `channels `_ + Nim message passing support for threads. **Note:** This is part of the + system module. Do not import it explicitly. Enabled with `--threads:on`. Core @@ -62,6 +64,9 @@ Core * `locks `_ Locks and condition variables for Nim. +* `macrocache `_ + Provides an API for macros to collect compile-time information across modules. + * `macros `_ Contains the AST API and documentation of Nim for writing macros. @@ -85,10 +90,15 @@ Algorithms * `algorithm `_ This module implements some common generic algorithms like sort or binary search. +* `std/enumutils `_ + This module adds functionality for the built-in `enum` type. + * `sequtils `_ - This module implements operations for the built-in seq type + This module implements operations for the built-in `seq` type which were inspired by functional programming languages. +* `std/setutils `_ + This module adds functionality for the built-in `set` type. Collections @@ -100,7 +110,7 @@ Collections * `deques `_ Implementation of a double-ended queue. - The underlying implementation uses a ``seq``. + The underlying implementation uses a `seq`. * `heapqueue `_ Implementation of a heap data structure that can be used as a priority queue. @@ -115,6 +125,9 @@ Collections * `options `_ The option type encapsulates an optional value. +* `std/packedsets `_ + Efficient implementation of a set of ordinals as a sparse bit set. + * `sets `_ Nim hash and bit set support. @@ -128,12 +141,11 @@ Collections Nim hash table support. Contains tables, ordered tables, and count tables. - String handling --------------- * `cstrutils `_ - Utilities for ``cstring`` handling. + Utilities for `cstring` handling. * `std/editdistance `_ This module contains an algorithm to compute the edit distance between two @@ -141,7 +153,7 @@ String handling * `encodings `_ Converts between different character encodings. On UNIX, this uses - the ``iconv`` library, on Windows the Windows API. + the `iconv` library, on Windows the Windows API. * `parseutils `_ This module contains helpers for parsing tokens, numbers, identifiers, etc. @@ -154,22 +166,22 @@ String handling * `ropes `_ This module contains support for a *rope* data type. - Ropes can represent very long strings efficiently; + Ropes can represent very long strings efficiently; especially concatenation is done in O(1) instead of O(n). * `strformat `_ Macro based standard string interpolation/formatting. Inspired by - Python's ``f``-strings. + Python's `f`-strings. * `strmisc `_ This module contains uncommon string handling operations that do not fit with the commonly used operations in strutils. * `strscans `_ - This module contains a ``scanf`` macro for convenient parsing of mini languages. + This module contains a `scanf` macro for convenient parsing of mini languages. * `strtabs `_ - The ``strtabs`` module implements an efficient hash table that is a mapping + The `strtabs` module implements an efficient hash table that is a mapping from strings to strings. Supports a case-sensitive, case-insensitive and style-insensitive modes. @@ -196,7 +208,7 @@ Time handling The `monotimes` module implements monotonic timestamps. * `times `_ - The ``times`` module contains support for working with time. + The `times` module contains support for working with time. Generic Operating System Services @@ -218,7 +230,7 @@ Generic Operating System Services data structures. * `memfiles `_ - This module provides support for memory-mapped files (Posix's ``mmap``) + This module provides support for memory-mapped files (Posix's `mmap`) on the different operating systems. * `os `_ @@ -227,12 +239,12 @@ Generic Operating System Services commands, etc. * `osproc `_ - Module for process communication beyond ``os.execShellCmd``. + Module for process communication beyond `os.execShellCmd`. * `streams `_ This module provides a stream interface and two implementations thereof: - the `FileStream` and the `StringStream` which implement the stream - interface for Nim file objects (`File`) and strings. Other modules + the `FileStream` and the `StringStream` which implement the stream + interface for Nim file objects (`File`) and strings. Other modules may provide other implementations for this standard stream interface. * `terminal `_ @@ -260,6 +272,9 @@ Math libraries * `random `_ Fast and tiny random number generator. +* `std/sysrand `_ + Cryptographically secure pseudorandom number generator. + * `rationals `_ This module implements rational numbers and relevant mathematical operations. @@ -267,7 +282,7 @@ Math libraries Statistical analysis * `std/sums `_ - Fast summation functions. + Accurate summation functions. Internet Protocols and Support @@ -278,18 +293,18 @@ Internet Protocols and Support * `asyncfile `_ This module implements asynchronous file reading and writing using - ``asyncdispatch``. + `asyncdispatch`. * `asyncftpclient `_ - This module implements an asynchronous FTP client using the ``asyncnet`` + This module implements an asynchronous FTP client using the `asyncnet` module. * `asynchttpserver `_ - This module implements an asynchronous HTTP server using the ``asyncnet`` + This module implements an asynchronous HTTP server using the `asyncnet` module. * `asyncnet `_ - This module implements asynchronous sockets based on the ``asyncdispatch`` + This module implements asynchronous sockets based on the `asyncdispatch` module. * `asyncstreams `_ @@ -313,7 +328,7 @@ Internet Protocols and Support * `net `_ This module implements a high-level sockets API. It replaces the - ``sockets`` module. + `sockets` module. * `selectors `_ This module implements a selector API with backends specific to each OS. @@ -342,28 +357,34 @@ Parsers * `json `_ High-performance JSON parser. +* `std/jsonutils `_ + This module implements a hookable (de)serialization for arbitrary types. + * `lexbase `_ This is a low-level module that implements an extremely efficient buffering scheme for lexers and parsers. This is used by the diverse parsing modules. * `parsecfg `_ - 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 quote string literals are supported as in the Nim programming language. * `parsecsv `_ - The ``parsecsv`` module implements a simple high-performance CSV parser. + The `parsecsv` module implements a simple high-performance CSV parser. + +* `parsejson `_ + This module implements a JSON parser. It is used and exported by the `json `_ module, but can also be used in its own right. * `parseopt `_ - The ``parseopt`` module implements a command line option parser. + The `parseopt` module implements a command line option parser. * `parsesql `_ - The ``parsesql`` module implements a simple high-performance SQL parser. + The `parsesql` module implements a simple high-performance SQL parser. * `parsexml `_ - The ``parsexml`` module implements a simple high performance XML/HTML parser. + The `parsexml` module implements a simple high performance XML/HTML parser. The only encoding that is supported is UTF-8. The parser has been designed to be somewhat error-correcting, so that even some "wild HTML" found on the web can be parsed with it. @@ -373,12 +394,12 @@ Docutils -------- * `packages/docutils/highlite `_ - Source highlighter for programming or markup languages. Currently, + Source highlighter for programming or markup languages. Currently, only a few languages are supported, other languages may be added. The interface supports one language nested in another. * `packages/docutils/rst `_ - This module implements a reStructuredText parser. A large subset + This module implements a reStructuredText parser. A large subset is implemented. Some features of the markdown wiki syntax are also supported. * `packages/docutils/rstast `_ @@ -403,12 +424,11 @@ Generators ---------- * `htmlgen `_ - This module implements a simple XML and HTML code - generator. Each commonly used HTML tag has a corresponding macro + This module implements a simple XML and HTML code + generator. Each commonly used HTML tag has a corresponding macro that generates a string with its HTML representation. - Hashing ------- @@ -432,7 +452,6 @@ Hashing This module implements a sha1 encoder and decoder. - Miscellaneous ------------- @@ -446,11 +465,14 @@ Miscellaneous * `coro `_ This module implements experimental coroutines in Nim. +* `std/enumerate `_ + This module implements `enumerate` syntactic sugar based on Nim's macro system. + * `logging `_ This module implements a simple logger. * `segfaults `_ - Turns access violations or segfaults into a ``NilAccessDefect`` exception. + Turns access violations or segfaults into a `NilAccessDefect` exception. * `sugar `_ This module implements nice syntactic sugar based on Nim's macro system. @@ -461,6 +483,10 @@ Miscellaneous * `std/varints `_ Decode variable-length integers that are compatible with SQLite. +* `std/with `_ + This module implements the `with` macro for easy function chaining. + + Modules for JS backend ---------------------- @@ -472,11 +498,11 @@ Modules for JS backend Declaration of the Document Object Model for the JS backend. * `jsconsole `_ - Wrapper for the ``console`` object. + Wrapper for the `console` object. * `jscore `_ The wrapper of core JavaScript functions. For most purposes, you should be using - the ``math``, ``json``, and ``times`` stdlib modules instead of this module. + the `math`, `json`, and `times` stdlib modules instead of this module. * `jsffi `_ Types and macros for easier interaction with JavaScript. @@ -489,10 +515,11 @@ Regular expressions ------------------- * `re `_ - This module contains procedures and operators for handling regular + This module contains procedures and operators for handling regular expressions. The current implementation uses PCRE. + Database support ---------------- @@ -509,6 +536,13 @@ Database support for other databases too. +Generic Operating System Services +--------------------------------- + +* `rdstdin `_ + This module contains code for reading from stdin. + + Wrappers ======== @@ -533,6 +567,7 @@ UNIX specific * `posix_utils `_ Contains helpers for the POSIX standard or specialized for Linux and BSDs. + Regular expressions ------------------- @@ -558,3 +593,11 @@ Network Programming and Internet Protocols * `openssl `_ Wrapper for OpenSSL. + + + +Unstable +======== + +* `atomics `_ + Types and operations for atomic operations and lockless algorithms. diff --git a/doc/manual.rst b/doc/manual.rst index fd0ac05292..1bb47f28b7 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ========== Nim Manual ========== @@ -31,28 +33,28 @@ This document describes the lexis, the syntax, and the semantics of the Nim lang To learn how to compile Nim programs and generate documentation see `Compiler User Guide `_ and `DocGen Tools Guide `_. -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 +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 +`&` is the lookahead operator; `&a` means that an `a` is expected but not consumed. It will be consumed in the following rule. -The ``|``, ``/`` symbols are used to mark alternatives and have the lowest -precedence. ``/`` is the ordered choice that requires the parser to try the -alternatives in the given order. ``/`` is often used to ensure the grammar +The `|`, `/` symbols are used to mark alternatives and have the lowest +precedence. `/` is the ordered choice that requires the parser to try the +alternatives in the given order. `/` is often used to ensure the grammar is not ambiguous. Non-terminals start with a lowercase letter, abstract terminal symbols are in UPPERCASE. Verbatim terminal symbols (including keywords) are quoted -with ``'``. An example:: +with `'`. An example:: ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)? -The binary ``^*`` operator is used as a shorthand for 0 or more occurrences -separated by its second argument; likewise ``^+`` means 1 or more -occurrences: ``a ^+ b`` is short for ``a (b a)*`` -and ``a ^* b`` is short for ``(a (b a)*)?``. Example:: +The binary `^*` operator is used as a shorthand for 0 or more occurrences +separated by its second argument; likewise `^+` means 1 or more +occurrences: `a ^+ b` is short for `a (b a)*` +and `a ^* b` is short for `(a (b a)*)?`. Example:: arrayConstructor = '[' expr ^* ',' ']' @@ -125,9 +127,9 @@ compiler may instead choose to allow the program to die with a fatal error. echo "invalid index" The current implementation allows to switch between these different behaviors -via ``--panics:on|off``. When panics are turned on, the program dies with a +via `--panics:on|off`. When panics are turned on, the program dies with a panic, if they are turned off the runtime errors are turned into -exceptions. The benefit of ``--panics:on`` is that it produces smaller binary +exceptions. The benefit of `--panics:on` is that it produces smaller binary code and the compiler has more freedom to optimize the code. An `unchecked runtime error`:idx: is an error that is not guaranteed to be @@ -180,11 +182,11 @@ lookahead. The parser uses a stack of indentation levels: the stack consists of integers counting the spaces. The indentation information is queried at strategic -places in the parser but ignored otherwise: The pseudo-terminal ``IND{>}`` +places in the parser but ignored otherwise: The pseudo-terminal `IND{>}` denotes an indentation that consists of more spaces than the entry at the top -of the stack; ``IND{=}`` an indentation that has the same number of spaces. ``DED`` +of the stack; `IND{=}` an indentation that has the same number of spaces. `DED` is another pseudo terminal that describes the *action* of popping a value -from the stack, ``IND{>}`` then implies to push onto the stack. +from the stack, `IND{>}` then implies to push onto the stack. With this notation we can now easily define the core of the grammar: A block of statements (simplified example):: @@ -204,9 +206,9 @@ Comments -------- Comments start anywhere outside a string or character literal with the -hash character ``#``. +hash character `#`. Comments consist of a concatenation of `comment pieces`:idx:. A comment piece -starts with ``#`` and runs until the end of the line. The end of line characters +starts with `#` and runs until the end of the line. The end of line characters belong to the piece. If the next line only consists of a comment piece with no other tokens between it and the preceding one, it does not start a new comment: @@ -218,7 +220,7 @@ comment: # The comment continues here. -`Documentation comments`:idx: are comments that start with two ``##``. +`Documentation comments`:idx: are comments that start with two `##`. Documentation comments are tokens; they are only allowed at certain places in the input file as they belong to the syntax tree! @@ -247,7 +249,7 @@ Multiline documentation comments also exist and support nesting too: .. code-block:: nim proc foo = ##[Long documentation comment - here. + here. ]## @@ -258,15 +260,15 @@ Identifiers in Nim can be any string of letters, digits and underscores, with the following restrictions: * begins with a letter -* does not end with an underscore ``_`` -* two immediate following underscores ``__`` are not allowed:: +* does not end with an underscore `_` +* two immediate following underscores `__` are not allowed:: letter ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff' digit ::= '0'..'9' IDENTIFIER ::= letter ( ['_'] (letter | digit) )* Currently, any Unicode character with an ordinal value > 127 (non-ASCII) is -classified as a ``letter`` and may thus be part of an identifier but later +classified as a `letter` and may thus be part of an identifier but later versions of the language may assign some Unicode characters to belong to the operator characters instead. @@ -302,15 +304,15 @@ by different programmers cannot use incompatible conventions. A Nim-aware editor or IDE can show the identifiers as preferred. Another advantage is that it frees the programmer from remembering the exact spelling of an identifier. The exception with respect to the first -letter allows common code like ``var foo: Foo`` to be parsed unambiguously. +letter allows common code like `var foo: Foo` to be parsed unambiguously. -Note that this rule also applies to keywords, meaning that ``notin`` is -the same as ``notIn`` and ``not_in`` (all-lowercase version (``notin``, ``isnot``) +Note that this rule also applies to keywords, meaning that `notin` is +the same as `notIn` and `not_in` (all-lowercase version (`notin`, `isnot`) is the preferred way of writing keywords). Historically, Nim was a fully `style-insensitive`:idx: language. This meant that it was not case-sensitive and underscores were ignored and there was not even a -distinction between ``foo`` and ``Foo``. +distinction between `foo` and `Foo`. Stropping @@ -342,7 +344,7 @@ Examples String literals --------------- -Terminal symbol in the grammar: ``STR_LIT``. +Terminal symbol in the grammar: `STR_LIT`. String literals can be delimited by matching double quotes, and can contain the following `escape sequences`:idx:\ : @@ -360,7 +362,7 @@ contain the following `escape sequences`:idx:\ : ``\\`` `backslash`:idx: ``\"`` `quotation mark`:idx: ``\'`` `apostrophe`:idx: - ``\`` '0'..'9'+ `character with decimal value d`:idx:; + ``\\`` '0'..'9'+ `character with decimal value d`:idx:; all decimal digits directly following are used for the character ``\a`` `alert`:idx: @@ -371,7 +373,7 @@ contain the following `escape sequences`:idx:\ : ``\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 + all hex digits enclosed in `{}` are used for the codepoint ================== =================================================== @@ -383,16 +385,15 @@ some operations may interpret the first binary zero as a terminator. Triple quoted string literals ----------------------------- -Terminal symbol in the grammar: ``TRIPLESTR_LIT``. +Terminal symbol in the grammar: `TRIPLESTR_LIT`. -String literals can also be delimited by three double quotes -``"""`` ... ``"""``. -Literals in this form may run for several lines, may contain ``"`` and do not +String literals can also be delimited by three double quotes `"""` ... `"""`. +Literals in this form may run for several lines, may contain `"` and do not interpret any escape sequences. -For convenience, when the opening ``"""`` is followed by a newline (there may -be whitespace between the opening ``"""`` and the newline), +For convenience, when the opening `"""` is followed by a newline (there may +be whitespace between the opening `"""` and the newline), the newline (and the preceding whitespace) is not included in the string. The -ending of the string literal is defined by the pattern ``"""[^"]``, so this: +ending of the string literal is defined by the pattern `"""[^"]`, so this: .. code-block:: nim """"long string within quotes"""" @@ -405,10 +406,10 @@ Produces:: Raw string literals ------------------- -Terminal symbol in the grammar: ``RSTR_LIT``. +Terminal symbol in the grammar: `RSTR_LIT`. There are also raw string literals that are preceded with the -letter ``r`` (or ``R``) and are delimited by matching double quotes (just +letter `r` (or `R`) and are delimited by matching double quotes (just like ordinary string literals) and do not interpret the escape sequences. This is especially convenient for regular expressions or Windows paths: @@ -416,7 +417,7 @@ This is especially convenient for regular expressions or Windows paths: var f = openFile(r"C:\texts\text.txt") # a raw string, so ``\t`` is no tab -To produce a single ``"`` within a raw string literal, it has to be doubled: +To produce a single `"` within a raw string literal, it has to be doubled: .. code-block:: nim @@ -426,34 +427,34 @@ Produces:: a"b -``r""""`` is not possible with this notation, because the three leading -quotes introduce a triple quoted string literal. ``r"""`` is the same -as ``"""`` since triple quoted string literals do not interpret escape +`r""""` is not possible with this notation, because the three leading +quotes introduce a triple quoted string literal. `r"""` is the same +as `"""` since triple quoted string literals do not interpret escape sequences either. Generalized raw string literals ------------------------------- -Terminal symbols in the grammar: ``GENERALIZED_STR_LIT``, -``GENERALIZED_TRIPLESTR_LIT``. +Terminal symbols in the grammar: `GENERALIZED_STR_LIT`, +`GENERALIZED_TRIPLESTR_LIT`. -The construct ``identifier"string literal"`` (without whitespace between the +The construct `identifier"string literal"` (without whitespace between the identifier and the opening quotation mark) is a generalized raw string literal. It is a shortcut for the construct -``identifier(r"string literal")``, so it denotes a procedure call with a +`identifier(r"string literal")`, so it denotes a procedure call with a raw string literal as its only argument. Generalized raw string literals are especially convenient for embedding mini languages directly into Nim (for example regular expressions). -The construct ``identifier"""string literal"""`` exists too. It is a shortcut -for ``identifier("""string literal""")``. +The construct `identifier"""string literal"""` exists too. It is a shortcut +for `identifier("""string literal""")`. Character literals ------------------ -Character literals are enclosed in single quotes ``''`` and can contain the +Character literals are enclosed in single quotes `''` and can contain the same escape sequences as strings - with one exception: the platform dependent `newline`:idx: (``\p``) is not allowed as it may be wider than one character (often it is the pair @@ -471,7 +472,7 @@ literals: ``\\`` `backslash`:idx: ``\"`` `quotation mark`:idx: ``\'`` `apostrophe`:idx: - ``\`` '0'..'9'+ `character with decimal value d`:idx:; + ``\\`` '0'..'9'+ `character with decimal value d`:idx:; all decimal digits directly following are used for the character ``\a`` `alert`:idx: @@ -484,10 +485,10 @@ literals: A character is not a Unicode character but a single byte. The reason for this is efficiency: for the overwhelming majority of use-cases, the resulting programs will still handle UTF-8 properly as UTF-8 was specially designed for -this. Another reason is that Nim can thus support ``array[char, int]`` or -``set[char]`` efficiently as many algorithms rely on this feature. The `Rune` +this. Another reason is that Nim can thus support `array[char, int]` or +`set[char]` efficiently as many algorithms rely on this feature. The `Rune` type is used for Unicode characters, it can represent any Unicode character. -``Rune`` is declared in the `unicode module `_. +`Rune` is declared in the `unicode module `_. Numerical constants @@ -531,15 +532,15 @@ Numerical constants are of a single type and have the form:: As can be seen in the productions, numerical constants can contain underscores for readability. Integer and floating-point literals may be given in decimal (no -prefix), binary (prefix ``0b``), octal (prefix ``0o``), and hexadecimal -(prefix ``0x``) notation. +prefix), binary (prefix `0b`), octal (prefix `0o`), and hexadecimal +(prefix `0x`) notation. There exists a literal for each numerical type that is defined. The suffix starting with an apostrophe ('\'') is called a `type suffix`:idx:. Literals without a type suffix are of an integer type -unless the literal contains a dot or ``E|e`` in which case it is of -type ``float``. This integer type is ``int`` if the literal is in the range -``low(i32)..high(i32)``, otherwise it is ``int64``. +unless the literal contains a dot or `E|e` in which case it is of +type `float`. This integer type is `int` if the literal is in the range +`low(i32)..high(i32)`, otherwise it is `int64`. For notational convenience, the apostrophe of a type suffix is optional if it is not ambiguous (only hexadecimal floating-point literals with a type suffix can be ambiguous). @@ -550,24 +551,24 @@ The type suffixes are: ================= ========================= Type Suffix Resulting type of literal ================= ========================= - ``'i8`` int8 - ``'i16`` int16 - ``'i32`` int32 - ``'i64`` int64 - ``'u`` uint - ``'u8`` uint8 - ``'u16`` uint16 - ``'u32`` uint32 - ``'u64`` uint64 - ``'f`` float32 - ``'d`` float64 - ``'f32`` float32 - ``'f64`` float64 + `'i8` int8 + `'i16` int16 + `'i32` int32 + `'i64` int64 + `'u` uint + `'u8` uint8 + `'u16` uint16 + `'u32` uint32 + `'u64` uint64 + `'f` float32 + `'d` float64 + `'f32` float32 + `'f64` float64 ================= ========================= Floating-point literals may also be in binary, octal or hexadecimal notation: -``0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64`` +`0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64` is approximately 1.72826e35 according to the IEEE floating-point standard. Literals are bounds checked so that they fit the datatype. Non-base-10 @@ -591,16 +592,16 @@ following characters:: defined here.) These keywords are also operators: -``and or not xor shl shr div mod in notin is isnot of as from``. +`and or not xor shl shr div mod in notin is isnot of as from`. `.`:tok: `=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they are used for other notational purposes. -``*:`` is as a special case treated as the two tokens `*`:tok: and `:`:tok: -(to support ``var v*: T``). +`*:` is as a special case treated as the two tokens `*`:tok: and `:`:tok: +(to support `var v*: T`). -The ``not`` keyword is always a unary operator, ``a not b`` is parsed -as ``a(not b)``, not as ``(a) not (b)``. +The `not` keyword is always a unary operator, `a not b` is parsed +as `a(not b)`, not as `(a) not (b)`. Other tokens @@ -631,7 +632,7 @@ Binary operators have 11 different levels of precedence. Associativity ------------- -Binary operators whose first character is ``^`` are right-associative, all +Binary operators whose first character is `^` are right-associative, all other binary operators are left-associative. .. code-block:: nim @@ -645,21 +646,21 @@ Precedence ---------- Unary operators always bind stronger than any binary -operator: ``$a + b`` is ``($a) + b`` and not ``$(a + b)``. +operator: `$a + b` is `($a) + b` and not `$(a + b)`. -If an unary operator's first character is ``@`` it is a `sigil-like`:idx: -operator which binds stronger than a ``primarySuffix``: ``@x.abc`` is parsed -as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``. +If a unary operator's first character is `@` it is a `sigil-like`:idx: +operator which binds stronger than a `primarySuffix`: `@x.abc` is parsed +as `(@x).abc` whereas `$x.abc` is parsed as `$(x.abc)`. For binary operators that are not keywords, the precedence is determined by the following rules: -Operators ending in either ``->``, ``~>`` or ``=>`` are called +Operators ending in either `->`, `~>` or `=>` are called `arrow like`:idx:, and have the lowest precedence of all operators. -If the operator ends with ``=`` and its first character is none of -``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which +If the operator ends with `=` and its first character is none of +`<`, `>`, `!`, `=`, `~`, `?`, it is an *assignment operator* which has the second-lowest precedence. Otherwise, precedence is determined by the first character. @@ -667,17 +668,17 @@ 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 + 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 ================ ======================================================= ================== =============== @@ -690,7 +691,7 @@ whitespace (this parsing change was introduced with version 0.13.0): echo($foo) -Spacing also determines whether ``(a, b)`` is parsed as an argument list +Spacing also determines whether `(a, b)` is parsed as an argument list of a call or whether it is parsed as a tuple constructor: .. code-block:: nim @@ -703,7 +704,7 @@ of a call or whether it is parsed as a tuple constructor: Grammar ------- -The grammar's start symbol is ``module``. +The grammar's start symbol is `module`. .. include:: grammar.txt :literal: @@ -756,7 +757,7 @@ right-hand side: Rationale: Consistency with overloaded assignment or assignment-like operations, -``a = b`` can be read as ``performSomeCopy(a, b)``. +`a = b` can be read as `performSomeCopy(a, b)`. However, the concept of "order of evaluation" is only applicable after the code @@ -830,7 +831,7 @@ problem!) .. code-block:: nim :test: "nim c $1" - import strformat + import std/strformat var fib_n {.compileTime.}: int var fib_prev {.compileTime.}: int @@ -867,11 +868,11 @@ language features: * methods * closure iterators -* the ``cast`` operator +* the `cast` operator * reference (pointer) types * FFI -The use of wrappers that use FFI and/or ``cast`` is also disallowed. Note that +The use of wrappers that use FFI and/or `cast` is also disallowed. Note that these wrappers include the ones in the standard libraries. Some or all of these restrictions are likely to be lifted over time. @@ -900,8 +901,8 @@ Ordinal types ------------- Ordinal types have the following characteristics: -- Ordinal types are countable and ordered. This property allows - the operation of functions as ``inc``, ``ord``, ``dec`` on ordinal types to +- Ordinal types are countable and ordered. This property allows the operation + of functions such as `inc`, `ord`, and `dec` on ordinal types to be defined. - Ordinal values have the smallest possible value. Trying to count further down than the smallest value produces a panic or a static error. @@ -918,80 +919,80 @@ Pre-defined integer types ------------------------- These integer types are pre-defined: -``int`` +`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``. + `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``. + 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. +`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. uintXX additional unsigned integer types of XX bits use this naming scheme (example: uint16 is a 16-bit wide unsigned integer). - The current implementation supports ``uint8``, ``uint16``, ``uint32``, - ``uint64``. Literals of these types have the suffix 'uXX. + The current implementation supports `uint8`, `uint16`, `uint32`, + `uint64`. Literals of these types have the suffix 'uXX. Unsigned operations all wrap around; they cannot lead to over- or underflow errors. In addition to the usual arithmetic operators for signed and unsigned integers -(``+ - *`` etc.) there are also operators that formally work on *signed* +(`+ - *` etc.) there are also operators that formally work on *signed* integers but treat their arguments as *unsigned*: They are mostly provided for backwards compatibility with older versions of the language that lacked unsigned integer types. These unsigned operations for signed integers use -the ``%`` suffix as convention: +the `%` suffix as convention: ====================== ====================================================== operation meaning ====================== ====================================================== -``a +% b`` unsigned integer addition -``a -% b`` unsigned integer subtraction -``a *% b`` unsigned integer multiplication -``a /% b`` unsigned integer division -``a %% b`` unsigned integer modulo operation -``a <% b`` treat ``a`` and ``b`` as unsigned and compare -``a <=% b`` treat ``a`` and ``b`` as unsigned and compare -``ze(a)`` extends the bits of ``a`` with zeros until it has the - width of the ``int`` type -``toU8(a)`` treats ``a`` as unsigned and converts it to an +`a +% b` unsigned integer addition +`a -% b` unsigned integer subtraction +`a *% b` unsigned integer multiplication +`a /% b` unsigned integer division +`a %% b` unsigned integer modulo operation +`a <% b` treat `a` and `b` as unsigned and compare +`a <=% b` treat `a` and `b` as unsigned and compare +`ze(a)` extends the bits of `a` with zeros until it has the + width of the `int` type +`toU8(a)` treats `a` as unsigned and converts it to an unsigned integer of 8 bits (but still the - ``int8`` type) -``toU16(a)`` treats ``a`` as unsigned and converts it to an + `int8` type) +`toU16(a)` treats `a` as unsigned and converts it to an unsigned integer of 16 bits (but still the - ``int16`` type) -``toU32(a)`` treats ``a`` as unsigned and converts it to an + `int16` type) +`toU32(a)` treats `a` as unsigned and converts it to an unsigned integer of 32 bits (but still the - ``int32`` type) + `int32` type) ====================== ====================================================== `Automatic type conversion`:idx: is performed in expressions where different kinds of integer types are used: the smaller type is converted to the larger. A `narrowing type conversion`:idx: converts a larger to a smaller type (for -example ``int32 -> int16``. A `widening type conversion`:idx: converts a -smaller type to a larger type (for example ``int16 -> int32``). In Nim only +example `int32 -> int16`). A `widening type conversion`:idx: converts a +smaller type to a larger type (for example `int16 -> int32`). In Nim only widening type conversions are *implicit*: .. code-block:: nim var myInt16 = 5i16 var myInt: int - myInt16 + 34 # of type ``int16`` - myInt16 + myInt # of type ``int`` - myInt16 + 2i32 # of type ``int32`` + myInt16 + 34 # of type `int16` + myInt16 + myInt # of type `int` + myInt16 + 2i32 # of type `int32` -However, ``int`` literals are implicitly convertible to a smaller integer type +However, `int` literals are implicitly convertible to a smaller integer type if the literal's value fits this smaller type and such a conversion is less -expensive than other implicit conversions, so ``myInt16 + 34`` produces -an ``int16`` result. +expensive than other implicit conversions, so `myInt16 + 34` produces +an `int16` result. For further details, see `Convertible relation <#type-relations-convertible-relation>`_. @@ -1009,15 +1010,15 @@ lowest and highest value of the type. For example: PositiveFloat = range[0.0..Inf] -``Subrange`` is a subrange of an integer which can only hold the values 0 -to 5. ``PositiveFloat`` defines a subrange of all positive floating-point values. +`Subrange` is a subrange of an integer which can only hold the values 0 +to 5. `PositiveFloat` defines a subrange of all positive floating-point values. NaN does not belong to any subrange of floating-point types. -Assigning any other value to a variable of type ``Subrange`` is a +Assigning any other value to a variable of type `Subrange` is a panic (or a static error if it can be determined during semantic analysis). Assignments from the base type to one of its subrange types (and vice versa) are allowed. -A subrange type has the same size as its base type (``int`` in the +A subrange type has the same size as its base type (`int` in the Subrange example). @@ -1026,15 +1027,15 @@ Pre-defined floating-point types The following floating-point types are pre-defined: -``float`` +`float` the generic floating-point type; its size used to be platform-dependent, - but now it is always mapped to ``float64``. + but now it is always mapped to `float64`. This type should be used in general. floatXX an implementation may define additional floating-point types of XX bits using this naming scheme (example: float64 is a 64-bit wide float). The current - implementation supports ``float32`` and ``float64``. Literals of these types + implementation supports `float32` and `float64`. Literals of these types have the suffix 'fXX. @@ -1073,34 +1074,34 @@ whether the IEEE exceptions are ignored or trap a Nim exception: echo b / b # raises FloatInvalidOpDefect echo a / b # raises FloatOverflowDefect -In the current implementation ``FloatDivByZeroDefect`` and ``FloatInexactDefect`` -are never raised. ``FloatOverflowDefect`` is raised instead of -``FloatDivByZeroDefect``. +In the current implementation `FloatDivByZeroDefect` and `FloatInexactDefect` +are never raised. `FloatOverflowDefect` is raised instead of +`FloatDivByZeroDefect`. There is also a `floatChecks`:idx: pragma that is a short-cut for the -combination of ``nanChecks`` and ``infChecks`` pragmas. ``floatChecks`` are +combination of `nanChecks` and `infChecks` pragmas. `floatChecks` are turned off as default. -The only operations that are affected by the ``floatChecks`` pragma are -the ``+``, ``-``, ``*``, ``/`` operators for floating-point types. +The only operations that are affected by the `floatChecks` pragma are +the `+`, `-`, `*`, `/` operators for floating-point types. An implementation should always use the maximum precision available to evaluate floating pointer values during semantic analysis; this means expressions like -``0.09'f32 + 0.01'f32 == 0.09'f64 + 0.01'f64`` that are evaluating during +`0.09'f32 + 0.01'f32 == 0.09'f64 + 0.01'f64` that are evaluating during constant folding are true. Boolean type ------------ The boolean type is named `bool`:idx: in Nim and can be one of the two -pre-defined values ``true`` and ``false``. Conditions in ``while``, -``if``, ``elif``, ``when``-statements need to be of type ``bool``. +pre-defined values `true` and `false`. Conditions in `while`, +`if`, `elif`, `when`-statements need to be of type `bool`. This condition holds:: ord(false) == 0 and ord(true) == 1 -The operators ``not, and, or, xor, <, <=, >, >=, !=, ==`` are defined -for the bool type. The ``and`` and ``or`` operators perform short-cut +The operators `not, and, or, xor, <, <=, >, >=, !=, ==` are defined +for the bool type. The `and` and `or` operators perform short-cut evaluation. Example: .. code-block:: nim @@ -1115,15 +1116,15 @@ The size of the bool type is one byte. Character type -------------- -The character type is named ``char`` in Nim. Its size is one byte. +The character type is named `char` in Nim. Its size is one byte. Thus it cannot represent a UTF-8 character, but a part of it. The reason for this is efficiency: for the overwhelming majority of use-cases, the resulting programs will still handle UTF-8 properly as UTF-8 was especially designed for this. -Another reason is that Nim can support ``array[char, int]`` or -``set[char]`` efficiently as many algorithms rely on this feature. The +Another reason is that Nim can support `array[char, int]` or +`set[char]` efficiently as many algorithms rely on this feature. The `Rune` type is used for Unicode characters, it can represent any Unicode -character. ``Rune`` is declared in the `unicode module `_. +character. `Rune` is declared in the `unicode module `_. @@ -1151,8 +1152,8 @@ Now the following holds:: ord(Direction.west) == 3 Thus, north < east < south < west. The comparison operators can be used -with enumeration types. Instead of ``north`` etc, the enum value can also -be qualified with the enum type that it resides in, ``Direction.north``. +with enumeration types. Instead of `north` etc, the enum value can also +be qualified with the enum type that it resides in, `Direction.north`. For better interfacing to other programming languages, the fields of enum types can be assigned an explicit ordinal value. However, the ordinal values @@ -1167,11 +1168,11 @@ An explicit ordered enum can have *holes*: a = 2, b = 4, c = 89 # holes are valid However, it is then not ordinal anymore, so it is not possible to use these -enums as an index type for arrays. The procedures ``inc``, ``dec``, ``succ`` -and ``pred`` are not available for them either. +enums as an index type for arrays. The procedures `inc`, `dec`, `succ` +and `pred` are not available for them either. -The compiler supports the built-in stringify operator ``$`` for enumerations. +The compiler supports the built-in stringify operator `$` for enumerations. The stringify's result can be controlled by explicitly giving the string values to use: @@ -1188,11 +1189,11 @@ As can be seen from the example, it is possible to both specify a field's ordinal value and its string value by using a tuple. It is also possible to only specify one of them. -An enum can be marked with the ``pure`` pragma so that its fields are +An enum can be marked with the `pure` pragma so that its fields are added to a special module-specific hidden scope that is only queried as the last attempt. Only non-ambiguous symbols are added to this scope. But one can always access these via type qualification written -as ``MyEnum.value``: +as `MyEnum.value`: .. code-block:: nim @@ -1212,20 +1213,20 @@ To implement bit fields with enums see `Bit fields <#set-type-bit-fields>`_ String type ----------- -All string literals are of the type ``string``. A string in Nim is very +All string literals are of the type `string`. A string in Nim is very similar to a sequence of characters. However, strings in Nim are both zero-terminated and have a length field. One can retrieve the length with the -builtin ``len`` procedure; the length never counts the terminating zero. +builtin `len` procedure; the length never counts the terminating zero. The terminating zero cannot be accessed unless the string is converted -to the ``cstring`` type first. The terminating zero assures that this +to the `cstring` type first. The terminating zero assures that this conversion can be done in O(1) and without any allocations. The assignment operator for strings always copies the string. -The ``&`` operator concatenates strings. +The `&` operator concatenates strings. -Most native Nim types support conversion to strings with the special ``$`` proc. -When calling the ``echo`` proc, for example, the built-in stringify operation +Most native Nim types support conversion to strings with the special `$` proc. +When calling the `echo` proc, for example, the built-in stringify operation for the parameter is called: .. code-block:: nim @@ -1233,7 +1234,7 @@ for the parameter is called: echo 3 # calls `$` for `int` Whenever a user creates a specialized object, implementation of this procedure -provides for ``string`` representation. +provides for `string` representation. .. code-block:: nim type @@ -1248,9 +1249,9 @@ provides for ``string`` representation. # a string " years old." -While ``$p.name`` can also be used, the ``$`` operation on a string does -nothing. Note that we cannot rely on automatic conversion from an ``int`` to -a ``string`` like we can for the ``echo`` proc. +While `$p.name` can also be used, the `$` operation on a string does +nothing. Note that we cannot rely on automatic conversion from an `int` to +a `string` like we can for the `echo` proc. Strings are compared by their lexicographical order. All comparison operators are available. Strings can be indexed like arrays (lower bound is 0). Unlike @@ -1265,25 +1266,25 @@ arrays, they can be used in case statements: Per convention, all strings are UTF-8 strings, but this is not enforced. For example, when reading strings from binary files, they are merely a sequence of -bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the -i-th *unichar*. The iterator ``runes`` from the `unicode module +bytes. The index operation `s[i]` means the i-th *char* of `s`, not the +i-th *unichar*. The iterator `runes` from the `unicode module `_ can be used for iteration over all Unicode characters. cstring type ------------ -The ``cstring`` type meaning `compatible string` is the native representation -of a string for the compilation backend. For the C backend the ``cstring`` type +The `cstring` type meaning `compatible string` is the native representation +of a string for the compilation backend. For the C backend the `cstring` type represents a pointer to a zero-terminated char array -compatible with the type ``char*`` in Ansi C. Its primary purpose lies in easy -interfacing with C. The index operation ``s[i]`` means the i-th *char* of -``s``; however no bounds checking for ``cstring`` is performed making the +compatible with the type `char*` in Ansi C. Its primary purpose lies in easy +interfacing with C. The index operation `s[i]` means the i-th *char* of +`s`; however no bounds checking for `cstring` is performed making the index operation unsafe. -A Nim ``string`` is implicitly convertible -to ``cstring`` for convenience. If a Nim string is passed to a C-style -variadic proc, it is implicitly converted to ``cstring`` too: +A Nim `string` is implicitly convertible +to `cstring` for convenience. If a Nim string is passed to a C-style +variadic proc, it is implicitly converted to `cstring` too: .. code-block:: nim proc printf(formatstr: cstring) {.importc: "printf", varargs, @@ -1292,10 +1293,10 @@ variadic proc, it is implicitly converted to ``cstring`` too: printf("This works %s", "as expected") Even though the conversion is implicit, it is not *safe*: The garbage collector -does not consider a ``cstring`` to be a root and may collect the underlying +does not consider a `cstring` to be a root and may collect the underlying memory. However, in practice, this almost never happens as the GC considers -stack roots conservatively. One can use the builtin procs ``GC_ref`` and -``GC_unref`` to keep the string data alive for the rare cases where it does +stack roots conservatively. One can use the builtin procs `GC_ref` and +`GC_unref` to keep the string data alive for the rare cases where it does not work. A `$` proc is defined for cstrings that returns a string. Thus to get a nim @@ -1306,13 +1307,13 @@ string from a cstring: var cstr: cstring = str var newstr: string = $cstr -``cstring`` literals shouldn't be modified. +`cstring` literals shouldn't be modified. .. code-block:: nim var x = cstring"literals" x[1] = 'A' # This is wrong!!! -If the ``cstring`` originates from a regular memory (not read-only memory), +If the `cstring` originates from a regular memory (not read-only memory), it can be modified: .. code-block:: nim @@ -1331,9 +1332,9 @@ Array and sequence types Arrays are a homogeneous type, meaning that each element in the array has the same type. Arrays always have a fixed length specified as a constant expression (except for open arrays). They can be indexed by any ordinal type. -A parameter ``A`` may be an *open array*, in which case it is indexed by -integers from 0 to ``len(A)-1``. An array expression may be constructed by the -array constructor ``[]``. The element type of this array expression is +A parameter `A` may be an *open array*, in which case it is indexed by +integers from 0 to `len(A)-1`. An array expression may be constructed by the +array constructor `[]`. The element type of this array expression is inferred from the type of the first element. All other elements need to be implicitly convertible to this type. @@ -1342,11 +1343,11 @@ An array type can be defined using the `array[size, T]` syntax, or using Sequences are similar to arrays but of dynamic length which may change during runtime (like strings). Sequences are implemented as growable arrays, -allocating pieces of memory as items are added. A sequence ``S`` is always -indexed by integers from 0 to ``len(S)-1`` and its bounds are checked. -Sequences can be constructed by the array constructor ``[]`` in conjunction -with the array to sequence operator ``@``. Another way to allocate space for a -sequence is to call the built-in ``newSeq`` procedure. +allocating pieces of memory as items are added. A sequence `S` is always +indexed by integers from 0 to `len(S)-1` and its bounds are checked. +Sequences can be constructed by the array constructor `[]` in conjunction +with the array to sequence operator `@`. Another way to allocate space for a +sequence is to call the built-in `newSeq` procedure. A sequence may be passed to a parameter that is of type *open array*. @@ -1366,18 +1367,18 @@ Example: let z = [1.0, 2, 3, 4] # the type of z is array[0..3, float] The lower bound of an array or sequence may be received by the built-in proc -``low()``, the higher bound by ``high()``. The length may be -received by ``len()``. ``low()`` for a sequence or an open array always returns +`low()`, the higher bound by `high()`. The length may be +received by `len()`. `low()` for a sequence or an open array always returns 0, as this is the first valid index. -One can append elements to a sequence with the ``add()`` proc or the ``&`` +One can append elements to a sequence with the `add()` proc or the `&` operator, and remove (and get) the last element of a sequence with the -``pop()`` proc. +`pop()` proc. -The notation ``x[i]`` can be used to access the i-th element of ``x``. +The notation `x[i]` can be used to access the i-th element of `x`. Arrays are always bounds checked (statically or at runtime). These checks can be disabled via pragmas or invoking the compiler with the -``--boundChecks:off`` command-line switch. +`--boundChecks:off` command-line switch. An array constructor can have explicit indexes for readability: @@ -1394,7 +1395,7 @@ An array constructor can have explicit indexes for readability: valC: "C" ] -If an index is left out, ``succ(lastIndex)`` is used as the index +If an index is left out, `succ(lastIndex)` is used as the index value: .. code-block:: nim @@ -1419,10 +1420,10 @@ Open arrays Often fixed size arrays turn out to be too inflexible; procedures should be able to deal with arrays of different sizes. The `openarray`:idx: type allows this; it can only be used for parameters. Openarrays are always -indexed with an ``int`` starting at position 0. The ``len``, ``low`` -and ``high`` operations are available for open arrays too. Any array with +indexed with an `int` starting at position 0. The `len`, `low` +and `high` operations are available for open arrays too. Any array with a compatible base type can be passed to an openarray parameter, the index -type does not matter. In addition to arrays sequences can also be passed +type does not matter. In addition to arrays, sequences can also be passed to an open array parameter. The openarray type cannot be nested: multidimensional openarrays are not @@ -1437,7 +1438,7 @@ supported because this is seldom needed and cannot be done efficiently. Varargs ------- -A ``varargs`` parameter is an openarray parameter that additionally +A `varargs` parameter is an openarray parameter that additionally allows to pass a variable number of arguments to a procedure. The compiler converts the list of arguments to an array implicitly: @@ -1465,10 +1466,10 @@ type conversions in this context: # is transformed to: myWriteln(stdout, [$123, $"def", $4.0]) -In this example ``$`` is applied to any argument that is passed to the -parameter ``a``. (Note that ``$`` applied to strings is a nop.) +In this example `$` is applied to any argument that is passed to the +parameter `a`. (Note that `$` applied to strings is a nop.) -Note that an explicit array constructor passed to a ``varargs`` parameter is +Note that an explicit array constructor passed to a `varargs` parameter is not wrapped in another implicit array construction: .. code-block:: nim @@ -1477,9 +1478,9 @@ not wrapped in another implicit array construction: takeV([123, 2, 1]) # takeV's T is "int", not "array of int" -``varargs[typed]`` is treated specially: It matches a variable list of arguments +`varargs[typed]` is treated specially: It matches a variable list of arguments of arbitrary type but *always* constructs an implicit array. This is required -so that the builtin ``echo`` proc does what is expected: +so that the builtin `echo` proc does what is expected: .. code-block:: nim proc echo*(x: varargs[typed, `$`]) {...} @@ -1490,7 +1491,7 @@ so that the builtin ``echo`` proc does what is expected: Unchecked arrays ---------------- -The ``UncheckedArray[T]`` type is a special kind of ``array`` where its bounds +The `UncheckedArray[T]` type is a special kind of `array` where its bounds are not checked. This is often useful to implement customized flexibly sized arrays. Additionally, an unchecked array is translated into a C array of undetermined size: @@ -1525,7 +1526,7 @@ A variable of a tuple or object type is a heterogeneous storage container. A tuple or object defines various named *fields* of a type. A tuple also defines a lexicographic *order* of the fields. Tuples are meant to be -heterogeneous storage types with few abstractions. The ``()`` syntax +heterogeneous storage types with few abstractions. The `()` syntax can be used to construct tuples. The order of the fields in the constructor must match the order of the tuple's definition. Different tuple-types are *equivalent* if they specify the same fields of the same type in the same @@ -1565,8 +1566,8 @@ In fact, a trailing comma is allowed for every tuple construction. The implementation aligns the fields for the best access performance. The alignment is compatible with the way the C compiler does it. -For consistency with ``object`` declarations, tuples in a ``type`` section -can also be defined with indentation instead of ``[]``: +For consistency with `object` declarations, tuples in a `type` section +can also be defined with indentation instead of `[]`: .. code-block:: nim type @@ -1574,11 +1575,11 @@ can also be defined with indentation instead of ``[]``: name: string # a person consists of a name age: Natural # and an age -Objects provide many features that tuples do not. Object provide inheritance and -the ability to hide fields from other modules. Objects with inheritance enabled -have information about their type at runtime so that the ``of`` operator can be -used to determine the object's type. The ``of`` -operator is similar to the ``instanceof`` operator in Java. +Objects provide many features that tuples do not. Objects provide inheritance +and the ability to hide fields from other modules. Objects with inheritance +enabled have information about their type at runtime so that the `of` operator +can be used to determine the object's type. The `of` operator is similar to +the `instanceof` operator in Java. .. code-block:: nim type @@ -1595,12 +1596,12 @@ operator is similar to the ``instanceof`` operator in Java. assert(student of Student) # is true assert(student of Person) # also true -Object fields that should be visible from outside the defining module, have to -be marked by ``*``. In contrast to tuples, different object types are +Object fields that should be visible from outside the defining module have to +be marked by `*`. In contrast to tuples, different object types are never *equivalent*, they are nominal types whereas tuples are structural. -Objects that have no ancestor are implicitly ``final`` and thus have no hidden -type information. One can use the ``inheritable`` pragma to -introduce new object roots apart from ``system.RootObj``. +Objects that have no ancestor are implicitly `final` and thus have no hidden +type information. One can use the `inheritable` pragma to +introduce new object roots apart from `system.RootObj`. .. code-block:: nim type @@ -1616,14 +1617,14 @@ Object construction ------------------- Objects can also be created with an `object construction expression`:idx: that -has the syntax ``T(fieldA: valueA, fieldB: valueB, ...)`` where ``T`` is -an ``object`` type or a ``ref object`` type: +has the syntax `T(fieldA: valueA, fieldB: valueB, ...)` where `T` is +an `object` type or a `ref object` type: .. code-block:: nim var student = Student(name: "Anton", age: 5, id: 3) Note that, unlike tuples, objects require the field names along with their values. -For a ``ref object`` type ``system.new`` is invoked implicitly. +For a `ref object` type `system.new` is invoked implicitly. Object variants @@ -1637,7 +1638,7 @@ An example: .. code-block:: nim - # This is an example how an abstract syntax tree could be modelled in Nim + # This is an example of how an abstract syntax tree could be modelled in Nim type NodeKind = enum # the different node types nkInt, # a leaf with an integer value @@ -1648,7 +1649,7 @@ An example: nkIf # an if statement Node = ref NodeObj NodeObj = object - case kind: NodeKind # the ``kind`` field is the discriminator + case kind: NodeKind # the `kind` field is the discriminator of nkInt: intVal: int of nkFloat: floatVal: float of nkString: strVal: string @@ -1659,11 +1660,11 @@ An example: # create a new case object: var n = Node(kind: nkIf, condition: nil) - # accessing n.thenPart is valid because the ``nkIf`` branch is active: + # accessing n.thenPart is valid because the `nkIf` branch is active: n.thenPart = Node(kind: nkFloat, floatVal: 2.0) # the following statement raises an `FieldDefect` exception, because - # n.kind's value does not fit and the ``nkString`` branch is not active: + # n.kind's value does not fit and the `nkString` branch is not active: n.strVal = "" # invalid: would change the active object branch: @@ -1678,11 +1679,11 @@ As can be seen from the example, an advantage to an object hierarchy is that no casting between different object types is needed. Yet, access to invalid object fields raises an exception. -The syntax of ``case`` in an object declaration follows closely the syntax of -the ``case`` statement: The branches in a ``case`` section may be indented too. +The syntax of `case` in an object declaration follows closely the syntax of +the `case` statement: The branches in a `case` section may be indented too. -In the example, the ``kind`` field is called the `discriminator`:idx:\: For -safety its address cannot be taken and assignments to it are restricted: The +In the example, the `kind` field is called the `discriminator`:idx:\: For +safety, its address cannot be taken and assignments to it are restricted: The new value must not lead to a change of the active object branch. Also, when the fields of a particular branch are specified during object construction, the corresponding discriminator value must be specified as a constant expression. @@ -1698,15 +1699,15 @@ with a new one completely: x[] = NodeObj(kind: nkString, strVal: "abc") -Starting with version 0.20 ``system.reset`` cannot be used anymore to support +Starting with version 0.20 `system.reset` cannot be used anymore to support object branch changes as this never was completely memory safe. -As a special rule, the discriminator kind can also be bounded using a ``case`` +As a special rule, the discriminator kind can also be bounded using a `case` statement. If possible values of the discriminator variable in a -``case`` statement branch are a subset of discriminator values for the selected +`case` statement branch are a subset of discriminator values for the selected object branch, the initialization is considered valid. This analysis only works -for immutable discriminators of an ordinal type and disregards ``elif`` -branches. For discriminator values with a ``range`` type, the compiler +for immutable discriminators of an ordinal type and disregards `elif` +branches. For discriminator values with a `range` type, the compiler checks if the entire range of possible values for the discriminator value is valid for the chosen object branch. @@ -1753,13 +1754,13 @@ Traced references are declared with the **ref** keyword, untraced references are declared with the **ptr** keyword. In general, a `ptr T` is implicitly convertible to the `pointer` type. -An empty subscript ``[]`` notation can be used to de-refer a reference, -the ``addr`` procedure returns the address of an item. An address is always +An empty subscript `[]` notation can be used to de-refer a reference, +the `addr` procedure returns the address of an item. An address is always an untraced reference. -Thus the usage of ``addr`` is an *unsafe* feature. +Thus the usage of `addr` is an *unsafe* feature. -The ``.`` (access a tuple/object field operator) -and ``[]`` (array/string/sequence index operator) operators perform implicit +The `.` (access a tuple/object field operator) +and `[]` (array/string/sequence index operator) operators perform implicit dereferencing operations for reference types: .. code-block:: nim @@ -1786,10 +1787,10 @@ In order to simplify structural type checking, recursive tuples are not valid: # invalid recursion type MyTuple = tuple[a: ref MyTuple] -Likewise ``T = ref T`` is an invalid type. +Likewise `T = ref T` is an invalid type. -As a syntactical extension ``object`` types can be anonymous if -declared in a type section via the ``ref object`` or ``ptr object`` notations. +As a syntactical extension, `object` types can be anonymous if +declared in a type section via the `ref object` or `ptr object` notations. This feature is useful if an object should only gain reference semantics: .. code-block:: nim @@ -1800,31 +1801,31 @@ This feature is useful if an object should only gain reference semantics: data: int -To allocate a new traced object, the built-in procedure ``new`` has to be used. -To deal with untraced memory, the procedures ``alloc``, ``dealloc`` and -``realloc`` can be used. The documentation of the system module contains -further information. +To allocate a new traced object, the built-in procedure `new` has to be used. +To deal with untraced memory, the procedures `alloc`, `dealloc` and +`realloc` can be used. The documentation of the `system `_ module +contains further information. Nil --- -If a reference points to *nothing*, it has the value ``nil``. ``nil`` is the -default value for all ``ref`` and ``ptr`` types. The ``nil`` value can also be +If a reference points to *nothing*, it has the value `nil`. `nil` is the +default value for all `ref` and `ptr` types. The `nil` value can also be used like any other literal value. For example, it can be used in an assignment -like ``myRef = nil``. +like `myRef = nil`. -Dereferencing ``nil`` is an unrecoverable fatal runtime error (and not a panic). +Dereferencing `nil` is an unrecoverable fatal runtime error (and not a panic). -A successful dereferencing operation ``p[]`` implies that ``p`` is not nil. This +A successful dereferencing operation `p[]` implies that `p` is not nil. This can be exploited by the implementation to optimize code like: .. code-block:: nim p[].field = 3 if p != nil: - # if p were nil, ``p[]`` would have caused a crash already, - # so we know ``p`` is always not nil here. + # if p were nil, `p[]` would have caused a crash already, + # so we know `p` is always not nil here. action() Into: @@ -1839,12 +1840,12 @@ Into: dereferencing NULL pointers. -Mixing GC'ed memory with ``ptr`` +Mixing GC'ed memory with `ptr` -------------------------------- Special care has to be taken if an untraced object contains traced objects like traced references, strings, or sequences: in order to free everything properly, -the built-in procedure ``reset`` has to be called before freeing the untraced +the built-in procedure `reset` has to be called before freeing the untraced memory manually: .. code-block:: nim @@ -1863,16 +1864,16 @@ memory manually: # free the memory: dealloc(d) -Without the ``reset`` call the memory allocated for the ``d.s`` string would -never be freed. The example also demonstrates two important features for low-level programming: the ``sizeof`` proc returns the size of a type or value -in bytes. The ``cast`` operator can circumvent the type system: the compiler -is forced to treat the result of the ``alloc0`` call (which returns an untyped -pointer) as if it would have the type ``ptr Data``. Casting should only be +Without the `reset` call the memory allocated for the `d.s` string would +never be freed. The example also demonstrates two important features for low-level programming: the `sizeof` proc returns the size of a type or value +in bytes. The `cast` operator can circumvent the type system: the compiler +is forced to treat the result of the `alloc0` call (which returns an untyped +pointer) as if it would have the type `ptr Data`. Casting should only be done if it is unavoidable: it breaks type safety and bugs can lead to mysterious crashes. **Note**: The example only works because the memory is initialized to zero -(``alloc0`` instead of ``alloc`` does this): ``d.s`` is thus initialized to +(`alloc0` instead of `alloc` does this): `d.s` is thus initialized to binary zero which the string assignment can handle. One needs to know low-level details like this when mixing garbage-collected data with unmanaged memory. @@ -1881,7 +1882,7 @@ details like this when mixing garbage-collected data with unmanaged memory. Procedural type --------------- -A procedural type is internally a pointer to a procedure. ``nil`` is +A procedural type is internally a pointer to a procedure. `nil` is an allowed value for variables of a procedural type. Nim uses procedural types to achieve `functional`:idx: programming techniques. @@ -1916,78 +1917,78 @@ Examples: A subtle issue with procedural types is that the calling convention of the procedure influences the type compatibility: procedural types are only compatible if they have the same calling convention. As a special extension, -a procedure of the calling convention ``nimcall`` can be passed to a parameter -that expects a proc of the calling convention ``closure``. +a procedure of the calling convention `nimcall` can be passed to a parameter +that expects a proc of the calling convention `closure`. Nim supports these `calling conventions`:idx:\: `nimcall`:idx: is the default convention used for a Nim **proc**. It is the - same as ``fastcall``, but only for C compilers that support ``fastcall``. + same as `fastcall`, but only for C compilers that support `fastcall`. `closure`:idx: is the default calling convention for a **procedural type** that lacks any pragma annotations. It indicates that the procedure has a hidden implicit parameter (an *environment*). Proc vars that have the calling - convention ``closure`` take up two machine words: One for the proc pointer + convention `closure` take up two machine words: One for the proc pointer and another one for the pointer to implicitly passed environment. `stdcall`:idx: This is the stdcall convention as specified by Microsoft. The generated C - procedure is declared with the ``__stdcall`` keyword. + procedure is declared with the `__stdcall` keyword. `cdecl`:idx: The cdecl convention means that a procedure shall use the same convention as the C compiler. Under Windows the generated C procedure is declared with - the ``__cdecl`` keyword. + the `__cdecl` keyword. `safecall`:idx: This is the safecall convention as specified by Microsoft. The generated C - procedure is declared with the ``__safecall`` keyword. The word *safe* + procedure is declared with the `__safecall` keyword. The word *safe* refers to the fact that all hardware registers shall be pushed to the hardware stack. `inline`:idx: The inline convention means the caller should not call the procedure, but inline its code directly. Note that Nim does not inline, but leaves - this to the C compiler; it generates ``__inline`` procedures. This is + this to the C compiler; it generates `__inline` procedures. This is only a hint for the compiler: it may completely ignore it and - it may inline procedures that are not marked as ``inline``. + it may inline procedures that are not marked as `inline`. `fastcall`:idx: Fastcall means different things to different C compilers. One gets whatever - the C ``__fastcall`` means. + the C `__fastcall` means. `thiscall`:idx: - This is thiscall calling convention as specified by Microsoft, used on C++ - class member functions on the x86 architecture + This is the thiscall calling convention as specified by Microsoft, used on + C++ class member functions on the x86 architecture. `syscall`:idx: - The syscall convention is the same as ``__syscall`` in C. It is used for + The syscall convention is the same as `__syscall` in C. It is used for interrupts. `noconv`:idx: The generated C code will not have any explicit calling convention and thus use the C compiler's default calling convention. This is needed because - Nim's default calling convention for procedures is ``fastcall`` to + Nim's default calling convention for procedures is `fastcall` to improve speed. Most calling conventions exist only for the Windows 32-bit platform. -The default calling convention is ``nimcall``, unless it is an inner proc (a +The default calling convention is `nimcall`, unless it is an inner proc (a proc inside of a proc). For an inner proc an analysis is performed whether it accesses its environment. If it does so, it has the calling convention -``closure``, otherwise it has the calling convention ``nimcall``. +`closure`, otherwise it has the calling convention `nimcall`. Distinct type ------------- -A ``distinct`` type is a new type derived from a `base type`:idx: that is +A `distinct` type is a new type derived from a `base type`:idx: that is incompatible with its base type. In particular, it is an essential property of a distinct type that it **does not** imply a subtype relation between it and its base type. Explicit type conversions from a distinct type to its -base type and vice versa are allowed. See also ``distinctBase`` to get the +base type and vice versa are allowed. See also `distinctBase` to get the reverse operation. A distinct type is an ordinal type if its base type is an ordinal type. @@ -2012,11 +2013,11 @@ types are a perfect tool to model different currencies: e: Euro echo d + 12 - # Error: cannot add a number with no unit and a ``Dollar`` + # Error: cannot add a number with no unit and a `Dollar` -Unfortunately, ``d + 12.Dollar`` is not allowed either, -because ``+`` is defined for ``int`` (among others), not for ``Dollar``. So -a ``+`` for dollars needs to be defined: +Unfortunately, `d + 12.Dollar` is not allowed either, +because `+` is defined for `int` (among others), not for `Dollar`. So +a `+` for dollars needs to be defined: .. code-block:: proc `+` (x, y: Dollar): Dollar = @@ -2036,7 +2037,7 @@ number without unit; and the same holds for division: This quickly gets tedious. The implementations are trivial and the compiler should not generate all this code only to optimize it away later - after all -``+`` for dollars should produce the same binary code as ``+`` for ints. +`+` for dollars should produce the same binary code as `+` for ints. The pragma `borrow`:idx: has been designed to solve this problem; in principle, it generates the above trivial implementations: @@ -2045,11 +2046,11 @@ it generates the above trivial implementations: proc `*` (x: int, y: Dollar): Dollar {.borrow.} proc `div` (x: Dollar, y: int): Dollar {.borrow.} -The ``borrow`` pragma makes the compiler use the same implementation as +The `borrow` pragma makes the compiler use the same implementation as the proc that deals with the distinct type's base type, so no code is generated. -But it seems all this boilerplate code needs to be repeated for the ``Euro`` +But it seems all this boilerplate code needs to be repeated for the `Euro` currency. This can be solved with templates_. .. code-block:: nim @@ -2113,7 +2114,7 @@ modeled as a string. However, using string templates and filling in the values is vulnerable to the famous `SQL injection attack`:idx:\: .. code-block:: nim - import strutils + import std/strutils proc query(db: DbHandle, statement: string) = ... @@ -2125,7 +2126,7 @@ values is vulnerable to the famous `SQL injection attack`:idx:\: This can be avoided by distinguishing strings that contain SQL from strings that don't. Distinct types provide a means to introduce a new string type -``SQL`` that is incompatible with ``string``: +`SQL` that is incompatible with `string`: .. code-block:: nim type @@ -2142,10 +2143,10 @@ that don't. Distinct types provide a means to introduce a new string type It is an essential property of abstract types that they **do not** imply a subtype relation between the abstract type and its base type. Explicit type -conversions from ``string`` to ``SQL`` are allowed: +conversions from `string` to `SQL` are allowed: .. code-block:: nim - import strutils, sequtils + import std/[strutils, sequtils] proc properQuote(s: string): SQL = # quotes a string properly for an SQL statement @@ -2153,7 +2154,7 @@ conversions from ``string`` to ``SQL`` are allowed: proc `%` (frmt: SQL, values: openarray[string]): SQL = # quote each argument: - let v = values.mapIt(SQL, properQuote(it)) + let v = values.mapIt(properQuote(it)) # we need a temporary type for the type conversion :-( type StrSeq = seq[string] # call strutils.`%`: @@ -2162,8 +2163,8 @@ conversions from ``string`` to ``SQL`` are allowed: db.query("SELECT FROM users WHERE name = '$1'".SQL % [username]) Now we have compile-time checking against SQL injection attacks. Since -``"".SQL`` is transformed to ``SQL("")`` no new syntax is needed for nice -looking ``SQL`` string literals. The hypothetical ``SQL`` type actually +`"".SQL` is transformed to `SQL("")` no new syntax is needed for nice +looking `SQL` string literals. The hypothetical `SQL` type actually exists in the library as the `SqlQuery type `_ of modules like `db_sqlite `_. @@ -2171,7 +2172,7 @@ modules like `db_sqlite `_. Auto type --------- -The ``auto`` type can only be used for return types and parameters. For return +The `auto` type can only be used for return types and parameters. For return types it causes the compiler to infer the type from the routine body: .. code-block:: nim @@ -2188,8 +2189,8 @@ Is the same as: proc foo[T1, T2](a: T1, b: T2) = discard However, later versions of the language might change this to mean "infer the -parameters' types from the body". Then the above ``foo`` would be rejected as -the parameters' types can not be inferred from an empty ``discard`` statement. +parameters' types from the body". Then the above `foo` would be rejected as +the parameters' types can not be inferred from an empty `discard` statement. Type relations @@ -2241,15 +2242,15 @@ algorithm, *in pseudo-code*, determines type equality: result = typeEqualsAux(a, b, s) Since types are graphs which can have cycles, the above algorithm needs an -auxiliary set ``s`` to detect this case. +auxiliary set `s` to detect this case. Type equality modulo type distinction ------------------------------------- The following algorithm (in pseudo-code) determines whether two types -are equal with no respect to ``distinct`` types. For brevity the cycle check -with an auxiliary set ``s`` is omitted: +are equal with no respect to `distinct` types. For brevity the cycle check +with an auxiliary set `s` is omitted: .. code-block:: nim proc typeEqualsOrDistinct(a, b: PType): bool = @@ -2288,8 +2289,8 @@ with an auxiliary set ``s`` is omitted: Subtype relation ---------------- -If object ``a`` inherits from ``b``, ``a`` is a subtype of ``b``. This subtype -relation is extended to the types ``var``, ``ref``, ``ptr``: +If object `a` inherits from `b`, `a` is a subtype of `b`. This subtype +relation is extended to the types `var`, `ref`, `ptr`: .. code-block:: nim proc isSubtype(a, b: PType): bool = @@ -2309,7 +2310,7 @@ relation is extended to the types ``var``, ``ref``, ``ptr``: Convertible relation -------------------- -A type ``a`` is **implicitly** convertible to type ``b`` iff the following +A type `a` is **implicitly** convertible to type `b` iff the following algorithm returns true: .. code-block:: nim @@ -2343,18 +2344,18 @@ algorithm returns true: result = b == cstring -Implicit conversions are also performed for Nim's ``range`` type +Implicit conversions are also performed for Nim's `range` type constructor. -Let ``a0``, ``b0`` of type ``T``. +Let `a0`, `b0` of type `T`. -Let ``A = range[a0..b0]`` be the argument's type, ``F`` the formal -parameter's type. Then an implicit conversion from ``A`` to ``F`` -exists if ``a0 >= low(F) and b0 <= high(F)`` and both ``T`` and ``F`` +Let `A = range[a0..b0]` be the argument's type, `F` the formal +parameter's type. Then an implicit conversion from `A` to `F` +exists if `a0 >= low(F) and b0 <= high(F)` and both `T` and `F` are signed integers or if both are unsigned integers. -A type ``a`` is **explicitly** convertible to type ``b`` iff the following +A type `a` is **explicitly** convertible to type `b` iff the following algorithm returns true: .. code-block:: nim @@ -2385,50 +2386,50 @@ The convertible relation can be relaxed by a user-defined type x = chr.toInt echo x # => 97 -The type conversion ``T(a)`` is an L-value if ``a`` is an L-value and -``typeEqualsOrDistinct(T, typeof(a))`` holds. +The type conversion `T(a)` is an L-value if `a` is an L-value and +`typeEqualsOrDistinct(T, typeof(a))` holds. Assignment compatibility ------------------------ -An expression ``b`` can be assigned to an expression ``a`` iff ``a`` is an -`l-value` and ``isImplicitlyConvertible(b.typ, a.typ)`` holds. +An expression `b` can be assigned to an expression `a` iff `a` is an +`l-value` and `isImplicitlyConvertible(b.typ, a.typ)` holds. Overloading resolution ====================== -In a call ``p(args)`` the routine ``p`` that matches best is selected. If +In a call `p(args)` the routine `p` that matches best is selected. If multiple routines match equally well, the ambiguity is reported during semantic analysis. Every arg in args needs to match. There are multiple different categories how an -argument can match. Let ``f`` be the formal parameter's type and ``a`` the type +argument can match. Let `f` be the formal parameter's type and `a` the type of the argument. -1. Exact match: ``a`` and ``f`` are of the same type. -2. Literal match: ``a`` is an integer literal of value ``v`` - and ``f`` is a signed or unsigned integer type and ``v`` is in ``f``'s - range. Or: ``a`` is a floating-point literal of value ``v`` - and ``f`` is a floating-point type and ``v`` is in ``f``'s +1. Exact match: `a` and `f` are of the same type. +2. Literal match: `a` is an integer literal of value `v` + and `f` is a signed or unsigned integer type and `v` is in `f`'s + range. Or: `a` is a floating-point literal of value `v` + and `f` is a floating-point type and `v` is in `f`'s range. -3. Generic match: ``f`` is a generic type and ``a`` matches, for - instance ``a`` is ``int`` and ``f`` is a generic (constrained) parameter - type (like in ``[T]`` or ``[T: int|char]``. -4. Subrange or subtype match: ``a`` is a ``range[T]`` and ``T`` - matches ``f`` exactly. Or: ``a`` is a subtype of ``f``. -5. Integral conversion match: ``a`` is convertible to ``f`` and ``f`` and ``a`` +3. Generic match: `f` is a generic type and `a` matches, for + instance `a` is `int` and `f` is a generic (constrained) parameter + type (like in `[T]` or `[T: int|char]`. +4. Subrange or subtype match: `a` is a `range[T]` and `T` + matches `f` exactly. Or: `a` is a subtype of `f`. +5. Integral conversion match: `a` is convertible to `f` and `f` and `a` is some integer or floating-point type. -6. Conversion match: ``a`` is convertible to ``f``, possibly via a user - defined ``converter``. +6. Conversion match: `a` is convertible to `f`, possibly via a user + defined `converter`. These matching categories have a priority: An exact match is better than a -literal match and that is better than a generic match etc. In the following -``count(p, m)`` counts the number of matches of the matching category ``m`` -for the routine ``p``. +literal match and that is better than a generic match etc. In the following, +`count(p, m)` counts the number of matches of the matching category `m` +for the routine `p`. -A routine ``p`` matches better than a routine ``q`` if the following +A routine `p` matches better than a routine `q` if the following algorithm returns true:: for each matching category m in ["exact match", "literal match", @@ -2459,8 +2460,8 @@ Some examples: If this algorithm returns "ambiguous" further disambiguation is performed: -If the argument ``a`` matches both the parameter type ``f`` of ``p`` -and ``g`` of ``q`` via a subtyping relation, the inheritance depth is taken +If the argument `a` matches both the parameter type `f` of `p` +and `g` of `q` via a subtyping relation, the inheritance depth is taken into account: .. code-block:: nim @@ -2487,7 +2488,7 @@ into account: pp(c, c) -Likewise for generic matches the most specialized generic type (that still +Likewise, for generic matches, the most specialized generic type (that still matches) is preferred: .. code-block:: nim @@ -2502,10 +2503,10 @@ matches) is preferred: Overloading based on 'var T' -------------------------------------- -If the formal parameter ``f`` is of type ``var T`` +If the formal parameter `f` is of type `var T` in addition to the ordinary type checking, the argument is checked to be an `l-value`:idx:. -``var T`` matches better than just ``T`` then. +`var T` matches better than just `T` then. .. code-block:: nim proc sayHi(x: int): string = @@ -2530,9 +2531,9 @@ Lazy type resolution for untyped **Note**: An `unresolved`:idx: expression is an expression for which no symbol lookups and no type checking have been performed. -Since templates and macros that are not declared as ``immediate`` participate +Since templates and macros that are not declared as `immediate` participate in overloading resolution, it's essential to have a way to pass unresolved -expressions to a template or macro. This is what the meta-type ``untyped`` +expressions to a template or macro. This is what the meta-type `untyped` accomplishes: .. code-block:: nim @@ -2540,7 +2541,7 @@ accomplishes: rem unresolvedExpression(undeclaredIdentifier) -A parameter of type ``untyped`` always matches any argument (as long as there is +A parameter of type `untyped` always matches any argument (as long as there is any argument passed to it). But one has to watch out because other overloads might trigger the @@ -2553,8 +2554,8 @@ argument's resolution: # undeclared identifier: 'unresolvedExpression' rem unresolvedExpression(undeclaredIdentifier) -``untyped`` and ``varargs[untyped]`` are the only metatype that are lazy in this sense, the other -metatypes ``typed`` and ``typedesc`` are not lazy. +`untyped` and `varargs[untyped]` are the only metatype that are lazy in this sense, the other +metatypes `typed` and `typedesc` are not lazy. Varargs matching @@ -2573,7 +2574,7 @@ statements. Statements are separated into `simple statements`:idx: and `complex statements`:idx:. Simple statements are statements that cannot contain other statements like -assignments, calls, or the ``return`` statement; complex statements can +assignments, calls, or the `return` statement; complex statements can contain other statements. To avoid the `dangling else problem`:idx:, complex statements always have to be indented. The details can be found in the grammar. @@ -2582,11 +2583,11 @@ Statement list expression ------------------------- Statements can also occur in an expression context that looks -like ``(stmt1; stmt2; ...; ex)``. This is called -a statement list expression or ``(;)``. The type -of ``(stmt1; stmt2; ...; ex)`` is the type of ``ex``. All the other statements -must be of type ``void``. (One can use ``discard`` to produce a ``void`` type.) -``(;)`` does not introduce a new scope. +like `(stmt1; stmt2; ...; ex)`. This is called +a statement list expression or `(;)`. The type +of `(stmt1; stmt2; ...; ex)` is the type of `ex`. All the other statements +must be of type `void`. (One can use `discard` to produce a `void` type.) +`(;)` does not introduce a new scope. Discard statement @@ -2600,7 +2601,7 @@ Example: discard p(3, 4) # discard the return value of `p` -The ``discard`` statement evaluates its expression for side-effects and +The `discard` statement evaluates its expression for side-effects and throws the expression's resulting value away, and should only be used when ignoring this value is known not to cause problems. @@ -2627,7 +2628,7 @@ however the discardable pragma does not work on templates as templates substitut This template will resolve into "https://nim-lang.org" which is a string literal and since {.discardable.} doesn't apply to literals, the compiler will error. -An empty ``discard`` statement is often used as a null statement: +An empty `discard` statement is often used as a null statement: .. code-block:: nim proc classify(s: string) = @@ -2640,9 +2641,9 @@ An empty ``discard`` statement is often used as a null statement: Void context ------------ -In a list of statements every expression except the last one needs to have the -type ``void``. In addition to this rule an assignment to the builtin ``result`` -symbol also triggers a mandatory ``void`` context for the subsequent expressions: +In a list of statements, every expression except the last one needs to have the +type `void`. In addition to this rule an assignment to the builtin `result` +symbol also triggers a mandatory `void` context for the subsequent expressions: .. code-block:: nim proc invalid*(): string = @@ -2668,7 +2669,7 @@ variables of the same type: a: int = 0 x, y, z: int -If an initializer is given the type can be omitted: the variable is then of the +If an initializer is given, the type can be omitted: the variable is then of the same type as the initializing expression. Variables are always initialized with a default value if there is no initializing expression. The default value depends on the type and is always a zero in binary. @@ -2682,8 +2683,8 @@ char '\\0' bool false ref or pointer type nil procedural type nil -sequence ``@[]`` -string ``""`` +sequence `@[]` +string `""` tuple[x: A, y: B, ...] (default(A), default(B), ...) (analogous for objects) array[0..., T] [default(T), ...] @@ -2699,14 +2700,14 @@ The implicit initialization can be avoided for optimization reasons with the var a {.noInit.}: array[0..1023, char] -If a proc is annotated with the ``noinit`` pragma this refers to its implicit -``result`` variable: +If a proc is annotated with the `noinit` pragma, this refers to its implicit +`result` variable: .. code-block:: nim proc returnUndefinedValue: int {.noinit.} = discard -The implicit initialization can be also prevented by the `requiresInit`:idx: +The implicit initialization can also be prevented by the `requiresInit`:idx: type pragma. The compiler requires an explicit initialization for the object and all of its fields. However, it does a `control flow analysis`:idx: to prove the variable has been initialized and does not rely on syntactic properties: @@ -2758,25 +2759,25 @@ But these ones will compile successfully: Let statement ------------- -A ``let`` statement declares new local and global `single assignment`:idx: -variables and binds a value to them. The syntax is the same as that of the ``var`` -statement, except that the keyword ``var`` is replaced by the keyword ``let``. -Let variables are not l-values and can thus not be passed to ``var`` parameters +A `let` statement declares new local and global `single assignment`:idx: +variables and binds a value to them. The syntax is the same as that of the `var` +statement, except that the keyword `var` is replaced by the keyword `let`. +Let variables are not l-values and can thus not be passed to `var` parameters nor can their address be taken. They cannot be assigned new values. For let variables, the same pragmas are available as for ordinary variables. -As ``let`` statements are immutable after creation they need to define a value -when they are declared. The only exception to this is if the ``{.importc.}`` -pragma (or any of the other ``importX`` pragmas) is applied, in this case the -value is expected to come from native code, typically a C/C++ ``const``. +As `let` statements are immutable after creation they need to define a value +when they are declared. The only exception to this is if the `{.importc.}` +pragma (or any of the other `importX` pragmas) is applied, in this case the +value is expected to come from native code, typically a C/C++ `const`. Tuple unpacking --------------- -In a ``var`` or ``let`` statement tuple unpacking can be performed. The special -identifier ``_`` can be used to ignore some parts of the tuple: +In a `var` or `let` statement tuple unpacking can be performed. The special +identifier `_` can be used to ignore some parts of the tuple: .. code-block:: nim proc returnsTuple(): (int, int, int) = (4, 2, 3) @@ -2791,7 +2792,7 @@ Const section A const section declares constants whose values are constant expressions: .. code-block:: - import strutils + import std/[strutils] const roundPi = 3.1415 constEval = contains("abc", 'b') # computed at compile time! @@ -2835,20 +2836,20 @@ Example: else: echo "Boring name..." -The ``if`` statement is a simple way to make a branch in the control flow: -The expression after the keyword ``if`` is evaluated, if it is true -the corresponding statements after the ``:`` are executed. Otherwise -the expression after the ``elif`` is evaluated (if there is an -``elif`` branch), if it is true the corresponding statements after -the ``:`` are executed. This goes on until the last ``elif``. If all -conditions fail, the ``else`` part is executed. If there is no ``else`` +The `if` statement is a simple way to make a branch in the control flow: +The expression after the keyword `if` is evaluated, if it is true +the corresponding statements after the `:` are executed. Otherwise +the expression after the `elif` is evaluated (if there is an +`elif` branch), if it is true the corresponding statements after +the `:` are executed. This goes on until the last `elif`. If all +conditions fail, the `else` part is executed. If there is no `else` part, execution continues with the next statement. -In ``if`` statements new scopes begin immediately after -the ``if``/``elif``/``else`` keywords and ends after the +In `if` statements, new scopes begin immediately after +the `if`/`elif`/`else` keywords and ends after the corresponding *then* block. For visualization purposes the scopes have been enclosed -in ``{| |}`` in the following example: +in `{| |}` in the following example: .. code-block:: nim if {| (let m = input =~ re"(\w+)=\w+"; m.isMatch): @@ -2880,25 +2881,25 @@ Example: else: echo "unknown command" -The ``case`` statement is similar to the if statement, but it represents -a multi-branch selection. The expression after the keyword ``case`` is +The `case` statement is similar to the if statement, but it represents +a multi-branch selection. The expression after the keyword `case` is evaluated and if its value is in a *slicelist* the corresponding statements -(after the ``of`` keyword) are executed. If the value is not in any -given *slicelist* the ``else`` part is executed. If there is no ``else`` -part and not all possible values that ``expr`` can hold occur in a -``slicelist``, a static error occurs. This holds only for expressions of -ordinal types. "All possible values" of ``expr`` are determined by ``expr``'s -type. To suppress the static error an ``else`` part with an -empty ``discard`` statement should be used. +(after the `of` keyword) are executed. If the value is not in any +given *slicelist* the `else` part is executed. If there is no `else` +part and not all possible values that `expr` can hold occur in a +*slicelist*, a static error occurs. This holds only for expressions of +ordinal types. "All possible values" of `expr` are determined by `expr`'s +type. To suppress the static error an `else` part with an +empty `discard` statement should be used. For non-ordinal types, it is not possible to list every possible value and so -these always require an ``else`` part. +these always require an `else` part. Because case statements are checked for exhaustiveness during semantic analysis, -the value in every ``of`` branch must be a constant expression. +the value in every `of` branch must be a constant expression. This restriction also allows the compiler to generate more performant code. -As a special semantic extension, an expression in an ``of`` branch of a case +As a special semantic extension, an expression in an `of` branch of a case statement may evaluate to a set or array constructor; the set or array is then expanded into a list of its elements: @@ -2919,7 +2920,7 @@ expanded into a list of its elements: of '0'..'9': echo "a number" else: echo "other" -The ``case`` statement doesn't produce an l-value, so the following example +The `case` statement doesn't produce an l-value, so the following example won't work: .. code-block:: nim @@ -2938,7 +2939,7 @@ won't work: var foo = Foo(x: @[]) foo.get_x().add("asd") -This can be fixed by explicitly using ``return``: +This can be fixed by explicitly using `return`: .. code-block:: nim proc get_x(x: Foo): var seq[string] = @@ -2965,26 +2966,26 @@ Example: else: echo "cannot happen!" -The ``when`` statement is almost identical to the ``if`` statement with some +The `when` statement is almost identical to the `if` statement with some exceptions: -* Each condition (``expr``) has to be a constant expression (of type ``bool``). +* Each condition (`expr`) has to be a constant expression (of type `bool`). * The statements do not open a new scope. * The statements that belong to the expression that evaluated to true are translated by the compiler, the other statements are not checked for semantics! However, each condition is checked for semantics. -The ``when`` statement enables conditional compilation techniques. As -a special syntactic extension, the ``when`` construct is also available -within ``object`` definitions. +The `when` statement enables conditional compilation techniques. As +a special syntactic extension, the `when` construct is also available +within `object` definitions. When nimvm statement -------------------- -``nimvm`` is a special symbol, that may be used as an expression of ``when nimvm`` -statement to differentiate execution path between compile-time and the -executable. +`nimvm` is a special symbol that may be used as the expression of a +`when nimvm` statement to differentiate the execution path between +compile-time and the executable. Example: @@ -3001,14 +3002,14 @@ Example: assert(ctValue == true) assert(rtValue == false) -``when nimvm`` statement must meet the following requirements: +A `when nimvm` statement must meet the following requirements: -* Its expression must always be ``nimvm``. More complex expressions are not +* Its expression must always be `nimvm`. More complex expressions are not allowed. -* It must not contain ``elif`` branches. -* It must contain ``else`` branch. +* It must not contain `elif` branches. +* It must contain an `else` branch. * Code in branches must not affect semantics of the code that follows the - ``when nimvm`` statement. E.g. it must not define symbols that are used in + `when nimvm` statement. E.g. it must not define symbols that are used in the following code. Return statement @@ -3019,8 +3020,8 @@ Example: .. code-block:: nim return 40+2 -The ``return`` statement ends the execution of the current procedure. -It is only allowed in procedures. If there is an ``expr``, this is syntactic +The `return` statement ends the execution of the current procedure. +It is only allowed in procedures. If there is an `expr`, this is syntactic sugar for: .. code-block:: nim @@ -3028,10 +3029,10 @@ sugar for: return result -``return`` without an expression is a short notation for ``return result`` if +`return` without an expression is a short notation for `return result` if the proc has a return type. The `result`:idx: variable is always the return value of the procedure. It is automatically declared by the compiler. As all -variables, ``result`` is initialized to (binary) zero: +variables, `result` is initialized to (binary) zero: .. code-block:: nim proc returnZero(): int = @@ -3046,7 +3047,7 @@ Example: .. code-block:: nim yield (1, 2, 3) -The ``yield`` statement is used instead of the ``return`` statement in +The `yield` statement is used instead of the `return` statement in iterators. It is only valid in iterators. Execution is returned to the body of the for loop that called the iterator. Yield does not end the iteration process, but the execution is passed back to the iterator if the next iteration @@ -3069,10 +3070,10 @@ Example: break myblock # leave the block, in this case both for-loops echo found -The block statement is a means to group statements to a (named) ``block``. -Inside the block, the ``break`` statement is allowed to leave the block -immediately. A ``break`` statement can contain a name of a surrounding -block to specify which block is to leave. +The block statement is a means to group statements to a (named) `block`. +Inside the block, the `break` statement is allowed to leave the block +immediately. A `break` statement can contain a name of a surrounding +block to specify which block is to be left. Break statement @@ -3083,8 +3084,8 @@ Example: .. code-block:: nim break -The ``break`` statement is used to leave a block immediately. If ``symbol`` -is given, it is the name of the enclosing block that is to leave. If it is +The `break` statement is used to leave a block immediately. If `symbol` +is given, it is the name of the enclosing block that is to be left. If it is absent, the innermost block is left. @@ -3101,15 +3102,15 @@ Example: pw = readLine(stdin) -The ``while`` statement is executed until the ``expr`` evaluates to false. -Endless loops are no error. ``while`` statements open an `implicit block`, -so that they can be left with a ``break`` statement. +The `while` statement is executed until the `expr` evaluates to false. +Endless loops are no error. `while` statements open an `implicit block` +so that they can be left with a `break` statement. Continue statement ------------------ -A ``continue`` statement leads to the immediate next iteration of the +A `continue` statement leads to the immediate next iteration of the surrounding loop construct. It is only allowed within a loop. A continue statement is syntactic sugar for a nested block: @@ -3133,7 +3134,7 @@ Assembler statement ------------------- The direct embedding of assembler code into Nim code is supported -by the unsafe ``asm`` statement. Identifiers in the assembler code that refer to +by the unsafe `asm` statement. Identifiers in the assembler code that refer to Nim identifiers shall be enclosed in a special character which can be specified in the statement's pragmas. The default special character is ``'`'``: @@ -3188,8 +3189,8 @@ the same parameter names and types are used over and over. Instead of: proc baz(c: Context; n: Node) = ... One can tell the compiler about the convention that a parameter of -name ``c`` should default to type ``Context``, ``n`` should default to -``Node`` etc.: +name `c` should default to type `Context`, `n` should default to +`Node` etc.: .. code-block:: nim using @@ -3206,13 +3207,13 @@ name ``c`` should default to type ``Context``, ``n`` should default to # 'n' is inferred to be of the type 'Node' # But 'x' and 'y' are of type 'int'. -The ``using`` section uses the same indentation based grouping syntax as -a ``var`` or ``let`` section. +The `using` section uses the same indentation based grouping syntax as +a `var` or `let` section. -Note that ``using`` is not applied for ``template`` since the untyped template -parameters default to the type ``system.untyped``. +Note that `using` is not applied for `template` since the untyped template +parameters default to the type `system.untyped`. -Mixing parameters that should use the ``using`` declaration with parameters +Mixing parameters that should use the `using` declaration with parameters that are explicitly typed is possible and requires a semicolon between them. @@ -3226,8 +3227,8 @@ Example: .. code-block:: nim var y = if x > 8: 9 else: 10 -An if expression always results in a value, so the ``else`` part is -required. ``Elif`` parts are also allowed. +An if expression always results in a value, so the `else` part is +required. `Elif` parts are also allowed. When expression --------------- @@ -3279,19 +3280,19 @@ A table constructor is syntactic sugar for an array constructor: [("key1", "value1"), ("key2", "value2"), ("key3", "value2")] -The empty table can be written ``{:}`` (in contrast to the empty set -which is ``{}``) which is thus another way to write as the empty array -constructor ``[]``. This slightly unusual way of supporting tables +The empty table can be written `{:}` (in contrast to the empty set +which is `{}`) which is thus another way to write the empty array +constructor `[]`. This slightly unusual way of supporting tables has lots of advantages: * The order of the (key,value)-pairs is preserved, thus it is easy to - support ordered dicts with for example ``{key: val}.newOrderedTable``. -* A table literal can be put into a ``const`` section and the compiler + support ordered dicts with for example `{key: val}.newOrderedTable`. +* A table literal can be put into a `const` section and the compiler can easily put it into the executable's data section just like it can for arrays and the generated data section requires a minimal amount of memory. * Every table implementation is treated equally syntactically. -* Apart from the minimal syntactic sugar the language core does not need to +* Apart from the minimal syntactic sugar, the language core does not need to know about tables. @@ -3304,7 +3305,7 @@ safe in the sense that a failure to convert a type to another results in an exception (if it cannot be determined statically). Ordinary procs are often preferred over type conversions in Nim: For instance, -``$`` is the ``toString`` operator by convention and ``toFloat`` and ``toInt`` +`$` is the `toString` operator by convention and `toFloat` and `toInt` can be used to convert from floating-point to integer or vice versa. Type conversion can also be used to disambiguate overloaded routines: @@ -3318,12 +3319,12 @@ Type conversion can also be used to disambiguate overloaded routines: procVar("a") Since operations on unsigned numbers wrap around and are unchecked so are -type conversion to unsigned integers and between unsigned integers. The +type conversions to unsigned integers and between unsigned integers. The rationale for this is mostly better interoperability with the C Programming language when algorithms are ported from C to Nim. Exception: Values that are converted to an unsigned type at compile time -are checked so that code like ``byte(-1)`` does not compile. +are checked so that code like `byte(-1)` does not compile. **Note**: Historically the operations were unchecked and the conversions were sometimes checked but starting with @@ -3352,17 +3353,17 @@ Type casts should not be confused with *type conversions,* as mentioned in the prior section. Unlike type conversions, a type cast cannot change the underlying bit pattern of the data being casted (aside from that the size of the target type may differ from the source type). Casting resembles *type punning* in other -languages or C++'s ``reinterpret_cast`` and ``bit_cast`` features. +languages or C++'s `reinterpret_cast` and `bit_cast` features. The addr operator ----------------- -The ``addr`` operator returns the address of an l-value. If the type of the -location is ``T``, the `addr` operator result is of the type ``ptr T``. An +The `addr` operator returns the address of an l-value. If the type of the +location is `T`, the `addr` operator result is of the type `ptr T`. An address is always an untraced reference. Taking the address of an object that resides on the stack is **unsafe**, as the pointer may live longer than the object on the stack and can thus reference a non-existing object. One can get the address of variables, but one can't use it on variables declared through -``let`` statements: +`let` statements: .. code-block:: nim @@ -3383,8 +3384,8 @@ The unsafeAddr operator ----------------------- For easier interoperability with other compiled languages such as C, retrieving -the address of a ``let`` variable, a parameter or a ``for`` loop variable, the -``unsafeAddr`` operation can be used: +the address of a `let` variable, a parameter, or a `for` loop variable can +be accomplished by using the `unsafeAddr` operation: .. code-block:: nim @@ -3400,7 +3401,7 @@ called `procedures`:idx: in Nim. A procedure declaration consists of an identifier, zero or more formal parameters, a return value type and a block of code. Formal parameters are declared as a list of identifiers separated by either comma or semicolon. A parameter is given a type -by ``: typename``. The type applies to all parameters immediately before it, +by `: typename`. The type applies to all parameters immediately before it, until either the beginning of the parameter list, a semicolon separator, or an already typed parameter, is reached. The semicolon can be used to make separation of types and subsequent identifiers more distinct. @@ -3514,9 +3515,9 @@ current module: Method call syntax ------------------ -For object-oriented programming, the syntax ``obj.method(args)`` can be used -instead of ``method(obj, args)``. The parentheses can be omitted if there are no -remaining arguments: ``obj.len`` (instead of ``len(obj)``). +For object-oriented programming, the syntax `obj.method(args)` can be used +instead of `method(obj, args)`. The parentheses can be omitted if there are no +remaining arguments: `obj.len` (instead of `len(obj)`). This method call syntax is not restricted to objects, it can be used to supply any type of first argument for procedures: @@ -3532,15 +3533,15 @@ Another way to look at the method call syntax is that it provides the missing postfix notation. The method call syntax conflicts with explicit generic instantiations: -``p[T](x)`` cannot be written as ``x.p[T]`` because ``x.p[T]`` is always -parsed as ``(x.p)[T]``. +`p[T](x)` cannot be written as `x.p[T]` because `x.p[T]` is always +parsed as `(x.p)[T]`. See also: `Limitations of the method call syntax <#templates-limitations-of-the-method-call-syntax>`_. -The ``[: ]`` notation has been designed to mitigate this issue: ``x.p[:T]`` -is rewritten by the parser to ``p[T](x)``, ``x.p[:T](y)`` is rewritten to -``p[T](x, y)``. Note that ``[: ]`` has no AST representation, the rewrite +The `[: ]` notation has been designed to mitigate this issue: `x.p[:T]` +is rewritten by the parser to `p[T](x)`, `x.p[:T](y)` is rewritten to +`p[T](x, y)`. Note that `[: ]` has no AST representation, the rewrite is performed directly in the parsing step. @@ -3559,14 +3560,14 @@ different; for this, a special setter syntax is needed: proc `host=`*(s: var Socket, value: int) {.inline.} = ## setter of hostAddr. ## This accesses the 'host' field and is not a recursive call to - ## ``host=`` because the builtin dot access is preferred if it is + ## `host=` because the builtin dot access is preferred if it is ## available: s.host = value proc host*(s: Socket): int {.inline.} = ## getter of hostAddr ## This accesses the 'host' field and is not a recursive call to - ## ``host`` because the builtin dot access is preferred if it is + ## `host` because the builtin dot access is preferred if it is ## available: s.host @@ -3577,7 +3578,7 @@ different; for this, a special setter syntax is needed: new s s.host = 34 # same as `host=`(s, 34) -A proc defined as ``f=`` (with the trailing ``=``) is called +A proc defined as `f=` (with the trailing `=`) is called a `setter`:idx:. A setter can be called explicitly via the common backticks notation: @@ -3589,22 +3590,22 @@ backticks notation: `f=`(myObject, "value") -``f=`` can be called implicitly in the pattern -``x.f = value`` if and only if the type of ``x`` does not have a field -named ``f`` or if ``f`` is not visible in the current module. These rules +`f=` can be called implicitly in the pattern +`x.f = value` if and only if the type of `x` does not have a field +named `f` or if `f` is not visible in the current module. These rules ensure that object fields and accessors can have the same name. Within the -module ``x.f`` is then always interpreted as field access and outside the +module `x.f` is then always interpreted as field access and outside the module it is interpreted as an accessor proc call. Command invocation syntax ------------------------- -Routines can be invoked without the ``()`` if the call is syntactically +Routines can be invoked without the `()` if the call is syntactically a statement. This command invocation syntax also works for expressions, but then only a single argument may follow. This restriction -means ``echo f 1, f 2`` is parsed as ``echo(f(1), f(2))`` and not as -``echo(f(1, f(2)))``. The method call syntax may be used to provide one +means `echo f 1, f 2` is parsed as `echo(f(1), f(2))` and not as +`echo(f(1, f(2)))`. The method call syntax may be used to provide one more argument in this case: .. code-block:: nim @@ -3619,8 +3620,8 @@ more argument in this case: assert x == y The command invocation syntax also can't have complex expressions as arguments. -For example: (`anonymous procs <#procedures-anonymous-procs>`_), ``if``, -``case`` or ``try``. Function calls with no arguments still need () to +For example: (`anonymous procs <#procedures-anonymous-procs>`_), `if`, +`case` or `try`. Function calls with no arguments still need () to distinguish between a call and the function itself as a first-class value. @@ -3666,7 +3667,7 @@ lambdas as they are in languages like JavaScript, C#, etc. Func ---- -The ``func`` keyword introduces a shortcut for a `noSideEffect`:idx: proc. +The `func` keyword introduces a shortcut for a `noSideEffect`:idx: proc. .. code-block:: nim func binarySearch[T](a: openArray[T]; elem: T): int @@ -3678,6 +3679,48 @@ Is short for: +Routines +-------- + +A routine is a symbol of kind: `proc`, `func`, `method`, `iterator`, `macro`, `template`, `converter`. + +Type bound operators +-------------------- + +A type bound operator is a `proc` or `func` whose name starts with `=` but isn't an operator +(i.e. containing only symbols, such as `==`). These are unrelated to setters +(see `properties `_), which instead end in `=`. +A type bound operator declared for a type applies to the type regardless of whether +the operator is in scope (including if it is private). + +.. code-block:: nim + # foo.nim: + var witness* = 0 + type Foo[T] = object + proc initFoo*(T: typedesc): Foo[T] = discard + proc `=destroy`[T](x: var Foo[T]) = witness.inc # type bound operator + + # main.nim: + import foo + block: + var a = initFoo(int) + doAssert witness == 0 + doAssert witness == 1 + block: + var a = initFoo(int) + doAssert witness == 1 + `=destroy`(a) # can be called explicitly, even without being in scope + doAssert witness == 2 + # will still be called upon exiting scope + doAssert witness == 3 + +Type bound operators currently include: +`=destroy`, `=copy`, `=sink`, `=trace`, `=dispose`, `=deepcopy` +(some of which are still implementation defined and not yet documented). + +For more details on some of those procs, see +`lifetimeminustracking-hooks `_. + Nonoverloadable builtins ------------------------ @@ -3689,16 +3732,16 @@ simplicity (they require specialized semantic checking):: Thus they act more like keywords than like ordinary identifiers; unlike a keyword however, a redefinition may `shadow`:idx: the definition in -the ``system`` module. From this list the following should not be written in dot -notation ``x.f`` since ``x`` cannot be type-checked before it gets passed -to ``f``:: +the `system` module. From this list the following should not be written in dot +notation `x.f` since `x` cannot be type-checked before it gets passed +to `f`:: declared, defined, definedInScope, compiles, getAst, astToStr Var parameters -------------- -The type of a parameter may be prefixed with the ``var`` keyword: +The type of a parameter may be prefixed with the `var` keyword: .. code-block:: nim proc divmod(a, b: int; res, remainder: var int) = @@ -3712,7 +3755,7 @@ The type of a parameter may be prefixed with the ``var`` keyword: assert x == 1 assert y == 3 -In the example, ``res`` and ``remainder`` are `var parameters`. +In the example, `res` and `remainder` are `var parameters`. Var parameters can be modified by the procedure and the changes are visible to the caller. The argument passed to a var parameter has to be an l-value. Var parameters are implemented as hidden pointers. The @@ -3749,7 +3792,7 @@ One can use `tuple unpacking`:idx: to access the tuple's fields: assert y == 3 -**Note**: ``var`` parameters are never necessary for efficient parameter +**Note**: `var` parameters are never necessary for efficient parameter passing. Since non-var parameters cannot be modified the compiler is always free to pass arguments by reference if it considers it can speed up execution. @@ -3757,7 +3800,7 @@ free to pass arguments by reference if it considers it can speed up execution. Var return type --------------- -A proc, converter, or iterator may return a ``var`` type which means that the +A proc, converter, or iterator may return a `var` type which means that the returned value is an l-value and can be modified by the caller: .. code-block:: nim @@ -3777,15 +3820,15 @@ used to access a location beyond its lifetime: var g = 0 result = g # Error! -For iterators, a component of a tuple return type can have a ``var`` type too: +For iterators, a component of a tuple return type can have a `var` type too: .. code-block:: nim iterator mpairs(a: var seq[string]): tuple[key: int, val: var string] = for i in 0..a.high: yield (i, a[i]) -In the standard library every name of a routine that returns a ``var`` type -starts with the prefix ``m`` per convention. +In the standard library every name of a routine that returns a `var` type +starts with the prefix `m` per convention. .. include:: manual/var_t_return.rst @@ -3799,10 +3842,10 @@ a syntax like: .. code-block:: nim proc foo(other: Y; container: var X): var T from container -Here ``var T from container`` explicitly exposes that the +Here `var T from container` explicitly exposes that the location is derived from the second parameter (called -'container' in this case). The syntax ``var T from p`` specifies a type -``varTy[T, 2]`` which is incompatible with ``varTy[T, 1]``. +'container' in this case). The syntax `var T from p` specifies a type +`varTy[T, 2]` which is incompatible with `varTy[T, 1]`. NRVO @@ -3815,11 +3858,11 @@ See https://github.com/nim-lang/RFCs/issues/230 for more information. The return value is represented inside the body of a routine as the special `result`:idx: variable. This allows for a mechanism much like C++'s "named return value optimization" (`NRVO`:idx:). NRVO means that the stores -to ``result`` inside ``p`` directly affect the destination ``dest`` -in ``let/var dest = p(args)`` (definition of ``dest``) and also in ``dest = p(args)`` -(assignment to ``dest``). This is achieved by rewriting ``dest = p(args)`` -to ``p'(args, dest)`` where ``p'`` is a variation of ``p`` that returns ``void`` and -receives a hidden mutable parameter representing ``result``. +to `result` inside `p` directly affect the destination `dest` +in `let/var dest = p(args)` (definition of `dest`) and also in `dest = p(args)` +(assignment to `dest`). This is achieved by rewriting `dest = p(args)` +to `p'(args, dest)` where `p'` is a variation of `p` that returns `void` and +receives a hidden mutable parameter representing `result`. Informally: @@ -3837,11 +3880,11 @@ Informally: p(x) -Let ``T``'s be ``p``'s return type. NRVO applies for ``T`` -if ``sizeof(T) >= N`` (where ``N`` is implementation dependent), +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. -If ``p`` can raise an exception, NRVO applies regardless. This can produce +If `p` can raise an exception, NRVO applies regardless. This can produce observable differences in behavior: .. code-block:: nim @@ -3867,18 +3910,18 @@ observable differences in behavior: However, the current implementation produces a warning in these cases. There are different ways to deal with this warning: -1. Disable the warning via ``{.push warning[ObservableStores]: off.}`` ... ``{.pop.}``. - Then one may need to ensure that ``p`` only raises *before* any stores to ``result`` +1. Disable the warning via `{.push warning[ObservableStores]: off.}` ... `{.pop.}`. + Then one may need to ensure that `p` only raises *before* any stores to `result` happen. -2. One can use a temporary helper variable, for example instead of ``x = p(8)`` - use ``let tmp = p(8); x = tmp``. +2. One can use a temporary helper variable, for example instead of `x = p(8)` + use `let tmp = p(8); x = tmp`. Overloading of the subscript operator ------------------------------------- -The ``[]`` subscript operator for arrays/openarrays/sequences can be overloaded. +The `[]` subscript operator for arrays/openarrays/sequences can be overloaded. Methods @@ -3917,14 +3960,14 @@ type. echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) -In the example the constructors ``newLit`` and ``newPlus`` are procs -because they should use static binding, but ``eval`` is a method because it +In the example the constructors `newLit` and `newPlus` are procs +because they should use static binding, but `eval` is a method because it requires dynamic binding. As can be seen in the example, base methods have to be annotated with -the `base`:idx: pragma. The ``base`` pragma also acts as a reminder for the -programmer that a base method ``m`` is used as the foundation to determine all -the effects that a call to ``m`` might cause. +the `base`:idx: pragma. The `base` pragma also acts as a reminder for the +programmer that a base method `m` is used as the foundation to determine all +the effects that a call to `m` might cause. **Note**: Compile-time execution is not (yet) supported for methods. @@ -3935,9 +3978,10 @@ Multi-methods -------------- **Note:** Starting from Nim 0.20, to use multi-methods one must explicitly pass -``--multimethods:on`` when compiling. +`--multimethods:on` when compiling. -In a multi-method all parameters that have an object type are used for the dispatching: +In a multi-method, all parameters that have an object type are used for the +dispatching: .. code-block:: nim :test: "nim c --multiMethods:on $1" @@ -3989,20 +4033,20 @@ Iterators and the for statement =============================== The `for`:idx: statement is an abstract mechanism to iterate over the elements -of a container. It relies on an `iterator`:idx: to do so. Like ``while`` -statements, ``for`` statements open an `implicit block`:idx:, so that they -can be left with a ``break`` statement. +of a container. It relies on an `iterator`:idx: to do so. Like `while` +statements, `for` statements open an `implicit block`:idx: so that they +can be left with a `break` statement. -The ``for`` loop declares iteration variables - their scope reaches until the +The `for` loop declares iteration variables - their scope reaches until the end of the loop body. The iteration variables' types are inferred by the return type of the iterator. An iterator is similar to a procedure, except that it can be called in the -context of a ``for`` loop. Iterators provide a way to specify the iteration over -an abstract type. A key role in the execution of a ``for`` loop plays the -``yield`` statement in the called iterator. Whenever a ``yield`` statement is -reached the data is bound to the ``for`` loop variables and control continues -in the body of the ``for`` loop. The iterator's local variables and execution +context of a `for` loop. Iterators provide a way to specify the iteration over +an abstract type. The `yield` statement in the called iterator plays a key +role in the execution of a `for` loop. Whenever a `yield` statement is +reached, the data is bound to the `for` loop variables and control continues +in the body of the `for` loop. The iterator's local variables and execution state are automatically saved between calls. Example: .. code-block:: nim @@ -4031,20 +4075,20 @@ the type of the i'th component. In other words, implicit tuple unpacking in a for loop context is supported. Implicit items/pairs invocations -------------------------------- +-------------------------------- -If the for loop expression ``e`` does not denote an iterator and the for loop -has exactly 1 variable, the for loop expression is rewritten to ``items(e)``; -ie. an ``items`` iterator is implicitly invoked: +If the for loop expression `e` does not denote an iterator and the for loop +has exactly 1 variable, the for loop expression is rewritten to `items(e)`; +ie. an `items` iterator is implicitly invoked: .. code-block:: nim for x in [1,2,3]: echo x -If the for loop has exactly 2 variables, a ``pairs`` iterator is implicitly +If the for loop has exactly 2 variables, a `pairs` iterator is implicitly invoked. -Symbol lookup of the identifiers ``items``/``pairs`` is performed after -the rewriting step, so that all overloads of ``items``/``pairs`` are taken +Symbol lookup of the identifiers `items`/`pairs` is performed after +the rewriting step, so that all overloads of `items`/`pairs` are taken into account. @@ -4057,7 +4101,7 @@ leading to zero overhead for the abstraction, but may result in a heavy increase in code size. Caution: the body of a for loop over an inline iterator is inlined into -each ``yield`` statement appearing in the iterator code, +each `yield` statement appearing in the iterator code, so ideally the code should be refactored to contain a single yield when possible to avoid code bloat. @@ -4086,20 +4130,20 @@ In contrast to that, a `closure iterator`:idx: can be passed around more freely: Closure iterators and inline iterators have some restrictions: 1. For now, a closure iterator cannot be executed at compile time. -2. ``return`` is allowed in a closure iterator but not in an inline iterator +2. `return` is allowed in a closure iterator but not in an inline iterator (but rarely useful) and ends the iteration. 3. Neither inline nor closure iterators can be (directly)* recursive. -4. Neither inline nor closure iterators have the special ``result`` variable. -5. Closure iterators are not supported by the js backend. +4. Neither inline nor closure iterators have the special `result` variable. +5. Closure iterators are not supported by the JS backend. (*) Closure iterators can be co-recursive with a factory proc which results in similar syntax to a recursive iterator. More details follow. -Iterators that are neither marked ``{.closure.}`` nor ``{.inline.}`` explicitly +Iterators that are neither marked `{.closure.}` nor `{.inline.}` explicitly default to being inline, but this may change in future versions of the implementation. -The ``iterator`` type is always of the calling convention ``closure`` +The `iterator` type is always of the calling convention `closure` implicitly; the following example shows how to use iterators to implement a `collaborative tasking`:idx: system: @@ -4134,12 +4178,12 @@ a `collaborative tasking`:idx: system: runTasks(a1, a2) -The builtin ``system.finished`` can be used to determine if an iterator has +The builtin `system.finished` can be used to determine if an iterator has finished its operation; no exception is raised on an attempt to invoke an iterator that has already finished its work. -Note that ``system.finished`` is error prone to use because it only returns -``true`` one iteration after the iterator has finished: +Note that `system.finished` is error prone to use because it only returns +`true` one iteration after the iterator has finished: .. code-block:: nim iterator mycount(a, b: int): int {.closure.} = @@ -4168,7 +4212,7 @@ Instead this code has to be used: echo value It helps to think that the iterator actually returns a -pair ``(value, done)`` and ``finished`` is used to access the hidden ``done`` +pair `(value, done)` and `finished` is used to access the hidden `done` field. @@ -4192,7 +4236,7 @@ parameters of an outer factory proc: The call can be made more like an inline iterator with a for loop macro: .. code-block:: nim - import macros + import std/macros macro toItr(x: ForLoopStmt): untyped = let expr = x[0] let call = x[1][1] # Get foo out of toItr(foo) @@ -4210,7 +4254,7 @@ Because of full backend function call aparatus involvment, closure iterator invocation is typically higher cost than inline iterators. Adornment by a macro wrapper at the call site like this is a possibly useful reminder. -The factory ``proc``, as an ordinary procedure, can be recursive. The +The factory `proc`, as an ordinary procedure, can be recursive. The above macro allows such recursion to look much like a recursive iterator would. For example: @@ -4261,11 +4305,11 @@ Example: line: int # the line the symbol was declared in code: Node # the symbol's abstract syntax tree -A type section begins with the ``type`` keyword. It contains multiple +A type section begins with the `type` keyword. It contains multiple type definitions. A type definition binds a type to a name. Type definitions can be recursive or even mutually recursive. Mutually recursive types are only -possible within a single ``type`` section. Nominal types like ``objects`` -or ``enums`` can only be defined in a ``type`` section. +possible within a single `type` section. Nominal types like `objects` +or `enums` can only be defined in a `type` section. @@ -4299,14 +4343,14 @@ Example: close(f) -The statements after the ``try`` are executed in sequential order unless -an exception ``e`` is raised. If the exception type of ``e`` matches any -listed in an ``except`` clause the corresponding statements are executed. -The statements following the ``except`` clauses are called +The statements after the `try` are executed in sequential order unless +an exception `e` is raised. If the exception type of `e` matches any +listed in an `except` clause, the corresponding statements are executed. +The statements following the `except` clauses are called `exception handlers`:idx:. The empty `except`:idx: clause is executed if there is an exception that is -not listed otherwise. It is similar to an ``else`` clause in ``if`` statements. +not listed otherwise. It is similar to an `else` clause in `if` statements. If there is a `finally`:idx: clause, it is always executed after the exception handlers. @@ -4314,27 +4358,27 @@ exception handlers. The exception is *consumed* in an exception handler. However, an exception handler may raise another exception. If the exception is not handled, it is propagated through the call stack. This means that often -the rest of the procedure - that is not within a ``finally`` clause - +the rest of the procedure - that is not within a `finally` clause - is not executed (if an exception occurs). Try expression -------------- -Try can also be used as an expression; the type of the ``try`` branch then -needs to fit the types of ``except`` branches, but the type of the ``finally`` -branch always has to be ``void``: +Try can also be used as an expression; the type of the `try` branch then +needs to fit the types of `except` branches, but the type of the `finally` +branch always has to be `void`: .. code-block:: nim - from strutils import parseInt + from std/strutils import parseInt let x = try: parseInt("133a") except: -1 finally: echo "hi" -To prevent confusing code there is a parsing limitation; if the ``try`` -follows a ``(`` it has to be written as a one liner: +To prevent confusing code there is a parsing limitation; if the `try` +follows a `(` it has to be written as a one liner: .. code-block:: nim let x = (try: parseInt("133a") except: -1) @@ -4343,7 +4387,7 @@ follows a ``(`` it has to be written as a one liner: Except clauses -------------- -Within an ``except`` clause it is possible to access the current exception +Within an `except` clause it is possible to access the current exception using the following syntax: .. code-block:: nim @@ -4353,7 +4397,7 @@ using the following syntax: # Now use "e" echo "I/O error: " & e.msg -Alternatively, it is possible to use ``getCurrentException`` to retrieve the +Alternatively, it is possible to use `getCurrentException` to retrieve the exception that has been raised: .. code-block:: nim @@ -4363,9 +4407,9 @@ exception that has been raised: let e = getCurrentException() # Now use "e" -Note that ``getCurrentException`` always returns a ``ref Exception`` +Note that `getCurrentException` always returns a `ref Exception` type. If a variable of the proper type is needed (in the example -above, ``IOError``), one must convert it explicitly: +above, `IOError`), one must convert it explicitly: .. code-block:: nim try: @@ -4375,8 +4419,8 @@ above, ``IOError``), one must convert it explicitly: # "e" is now of the proper type However, this is seldom needed. The most common case is to extract an -error message from ``e``, and for such situations, it is enough to use -``getCurrentExceptionMsg``: +error message from `e`, and for such situations, it is enough to use +`getCurrentExceptionMsg`: .. code-block:: nim try: @@ -4387,15 +4431,15 @@ error message from ``e``, and for such situations, it is enough to use Custom exceptions ----------------- -Is it possible to create custom exceptions. A custom exception is a custom type: +It is possible to create custom exceptions. A custom exception is a custom type: .. code-block:: nim type LoadError* = object of Exception -Ending the custom exception's name with ``Error`` is recommended. +Ending the custom exception's name with `Error` is recommended. -Custom exceptions can be raised like any others, e.g.: +Custom exceptions can be raised just like any other exception, e.g.: .. code-block:: nim raise newException(LoadError, "Failed to load data") @@ -4403,11 +4447,11 @@ Custom exceptions can be raised like any others, e.g.: Defer statement --------------- -Instead of a ``try finally`` statement a ``defer`` statement can be used, which +Instead of a `try finally` statement a `defer` statement can be used, which avoids lexical nesting and offers more flexibility in terms of scoping as shown below. -Any statements following the ``defer`` in the current block will be considered +Any statements following the `defer` in the current block will be considered to be in an implicit try block: .. code-block:: nim @@ -4459,7 +4503,7 @@ to the block where the template is called from: f.write "abc" # adds a lexical scope finally: close(f) -Top-level ``defer`` statements are not supported +Top-level `defer` statements are not supported since it's unclear what such a statement should refer to. @@ -4472,13 +4516,13 @@ Example: raise newException(IOError, "IO failed") Apart from built-in operations like array indexing, memory allocation, etc. -the ``raise`` statement is the only way to raise an exception. +the `raise` statement is the only way to raise an exception. .. XXX document this better! If no exception name is given, the current exception is `re-raised`:idx:. The `ReraiseDefect`:idx: exception is raised if there is no exception to -re-raise. It follows that the ``raise`` statement *always* raises an +re-raise. It follows that the `raise` statement *always* raises an exception. @@ -4486,14 +4530,14 @@ Exception hierarchy ------------------- The exception tree is defined in the `system `_ module. -Every exception inherits from ``system.Exception``. Exceptions that indicate -programming bugs inherit from ``system.Defect`` (which is a subtype of ``Exception``) +Every exception inherits from `system.Exception`. Exceptions that indicate +programming bugs inherit from `system.Defect` (which is a subtype of `Exception`) and are strictly speaking not catchable as they can also be mapped to an operation that terminates the whole process. If panics are turned into exceptions, these exceptions inherit from `Defect`. Exceptions that indicate any other runtime error that can be caught inherit from -``system.CatchableError`` (which is a subtype of ``Exception``). +`system.CatchableError` (which is a subtype of `Exception`). Imported exceptions @@ -4559,7 +4603,7 @@ allowed to raise. The compiler verifies this: if what: raise newException(IOError, "IO") else: raise newException(OSError, "OS") -An empty ``raises`` list (``raises: []``) means that no exception may be raised: +An empty `raises` list (`raises: []`) means that no exception may be raised: .. code-block:: nim proc p(): bool {.raises: [].} = @@ -4570,7 +4614,7 @@ An empty ``raises`` list (``raises: []``) means that no exception may be raised: result = false -A ``raises`` list can also be attached to a proc type. This affects type +A `raises` list can also be attached to a proc type. This affects type compatibility: .. code-block:: nim @@ -4588,24 +4632,24 @@ compatibility: c = p # type error -For a routine ``p`` the compiler uses inference rules to determine the set of -possibly raised exceptions; the algorithm operates on ``p``'s call graph: +For a routine `p`, the compiler uses inference rules to determine the set of +possibly raised exceptions; the algorithm operates on `p`'s call graph: -1. Every indirect call via some proc type ``T`` is assumed to - raise ``system.Exception`` (the base type of the exception hierarchy) and - thus any exception unless ``T`` has an explicit ``raises`` list. - However, if the call is of the form ``f(...)`` where ``f`` is a parameter of the currently analyzed routine it is ignored. The call is optimistically assumed to have no effect. Rule 2 compensates for this case. +1. Every indirect call via some proc type `T` is assumed to + raise `system.Exception` (the base type of the exception hierarchy) and + thus any exception unless `T` has an explicit `raises` list. + However, if the call is of the form `f(...)` where `f` is a parameter of the currently analyzed routine it is ignored. The call is optimistically assumed to have no effect. Rule 2 compensates for this case. 2. Every expression of some proc type within a call that is not a call itself (and not nil) is assumed to be called indirectly somehow and thus - its raises list is added to ``p``'s raises list. -3. Every call to a proc ``q`` which has an unknown body (due to a forward - declaration or an ``importc`` pragma) is assumed to - raise ``system.Exception`` unless ``q`` has an explicit ``raises`` list. -4. Every call to a method ``m`` is assumed to - raise ``system.Exception`` unless ``m`` has an explicit ``raises`` list. -5. For every other call the analysis can determine an exact ``raises`` list. -6. For determining a ``raises`` list, the ``raise`` and ``try`` statements - of ``p`` are taken into consideration. + its raises list is added to `p`'s raises list. +3. Every call to a proc `q` which has an unknown body (due to a forward + declaration or an `importc` pragma) is assumed to + raise `system.Exception` unless `q` has an explicit `raises` list. +4. Every call to a method `m` is assumed to + raise `system.Exception` unless `m` has an explicit `raises` list. +5. For every other call, the analysis can determine an exact `raises` list. +6. For determining a `raises` list, the `raise` and `try` statements + of `p` are taken into consideration. Rules 1-2 ensure the following works: @@ -4624,16 +4668,16 @@ Rules 1-2 ensure the following works: So in many cases a callback does not cause the compiler to be overly conservative in its effect analysis. -Exceptions inheriting from ``system.Defect`` are not tracked with -the ``.raises: []`` exception tracking mechanism. This is more consistent with the -built-in operations. The following code is valid:: +Exceptions inheriting from `system.Defect` are not tracked with +the `.raises: []` exception tracking mechanism. This is more consistent with the +built-in operations. The following code is valid: .. code-block:: nim proc mydiv(a, b): int {.raises: [].} = a div b # can raise an DivByZeroDefect -And so is:: +And so is: .. code-block:: nim @@ -4642,17 +4686,17 @@ And so is:: else: result = a div b -The reason for this is that ``DivByZeroDefect`` inherits from ``Defect`` and -with ``--panics:on`` Defects become unrecoverable errors. +The reason for this is that `DivByZeroDefect` inherits from `Defect` and +with `--panics:on` Defects become unrecoverable errors. (Since version 1.4 of the language.) Tag tracking ------------ -The exception tracking is part of Nim's `effect system`:idx:. Raising an -exception is an *effect*. Other effects can also be defined. A user defined -effect is a means to *tag* a routine and to perform checks against this tag: +Exception tracking is part of Nim's `effect system`:idx:. Raising an exception +is an *effect*. Other effects can also be defined. A user defined effect is a +means to *tag* a routine and to perform checks against this tag: .. code-block:: nim :test: "nim c $1" @@ -4665,7 +4709,7 @@ effect is a means to *tag* a routine and to perform checks against this tag: # the compiler prevents this: let x = readLine() -A tag has to be a type name. A ``tags`` list - like a ``raises`` list - can +A tag has to be a type name. A `tags` list - like a `raises` list - can also be attached to a proc type. This affects type compatibility. The inference for tag tracking is analogous to the inference for @@ -4676,9 +4720,9 @@ exception tracking. Effects pragma -------------- -The ``effects`` pragma has been designed to assist the programmer with the +The `effects` pragma has been designed to assist the programmer with the effects analysis. It is a statement that makes the compiler output all inferred -effects up to the ``effects``'s position: +effects up to the `effects`'s position: .. code-block:: nim proc p(what: bool) = @@ -4688,8 +4732,8 @@ effects up to the ``effects``'s position: else: raise newException(OSError, "OS") -The compiler produces a hint message that ``IOError`` can be raised. ``OSError`` -is not listed as it cannot be raised in the branch the ``effects`` pragma +The compiler produces a hint message that `IOError` can be raised. `OSError` +is not listed as it cannot be raised in the branch the `effects` pragma appears in. @@ -4700,14 +4744,14 @@ Generics are Nim's means to parametrize procs, iterators or types with `type parameters`:idx:. Depending on the context, the brackets are used either to introduce type parameters or to instantiate a generic proc, iterator, or type. -The following example shows a generic binary tree can be modeled: +The following example shows how a generic binary tree can be modeled: .. code-block:: nim :test: "nim c $1" type BinaryTree*[T] = ref object # BinaryTree is a generic type with - # generic param ``T`` + # generic param `T` le, ri: BinaryTree[T] # left and right subtrees; may be nil data: T # the data stored in a node @@ -4722,8 +4766,8 @@ The following example shows a generic binary tree can be modeled: else: var it = root while it != nil: - # compare the data items; uses the generic ``cmp`` proc - # that works for any type that has a ``==`` and ``<`` operator + # compare the data items; uses the generic `cmp` proc + # that works for any type that has a `==` and `<` operator var c = cmp(it.data, n.data) if c < 0: if it.le == nil: @@ -4753,20 +4797,19 @@ The following example shows a generic binary tree can be modeled: n = n.le # and follow the left pointer var - root: BinaryTree[string] # instantiate a BinaryTree with ``string`` - add(root, newNode("hello")) # instantiates ``newNode`` and ``add`` - add(root, "world") # instantiates the second ``add`` proc + root: BinaryTree[string] # instantiate a BinaryTree with `string` + add(root, newNode("hello")) # instantiates `newNode` and `add` + add(root, "world") # instantiates the second `add` proc for str in preorder(root): stdout.writeLine(str) -The ``T`` is called a `generic type parameter`:idx: or +The `T` is called a `generic type parameter`:idx: or a `type variable`:idx:. - Is operator ----------- -The ``is`` operator is evaluated during semantic analysis to check for type +The `is` operator is evaluated during semantic analysis to check for type equivalence. It is therefore very useful for type specialization within generic code: @@ -4783,26 +4826,25 @@ Type Classes ------------ A type class is a special pseudo-type that can be used to match against -types in the context of overload resolution or the ``is`` operator. +types in the context of overload resolution or the `is` operator. Nim supports the following built-in type classes: ================== =================================================== type class matches ================== =================================================== -``object`` any object type -``tuple`` any tuple type +`object` any object type +`tuple` any tuple type -``enum`` any enumeration -``proc`` any proc type -``ref`` any ``ref`` type -``ptr`` any ``ptr`` type -``var`` any ``var`` type -``distinct`` any distinct type -``array`` any array type -``set`` any set type -``seq`` any seq type -``auto`` any type -``any`` distinct auto (see below) +`enum` any enumeration +`proc` any proc type +`ref` any `ref` type +`ptr` any `ptr` type +`var` any `var` type +`distinct` any distinct type +`array` any array type +`set` any set type +`seq` any seq type +`auto` any type ================== =================================================== Furthermore, every generic type automatically creates a type class of the same @@ -4819,6 +4861,12 @@ more complex type classes: for key, value in fieldPairs(rec): echo key, " = ", value +Type constraints on generic parameters can be grouped with `,` and propagation +stops with `;`, similarly to parameters for macros and templates: + +.. code-block:: nim + proc fn1[T; U, V: SomeFloat]() = discard # T is unconstrained + template fn2(t; u, v: SomeFloat) = discard # t is unconstrained Whilst the syntax of type classes appears to resemble that of ADTs/algebraic data types in ML-like languages, it should be understood that type classes are static @@ -4871,13 +4919,13 @@ Here is an example taken directly from the system module to illustrate this: .. code-block:: nim proc `==`*(x, y: tuple): bool = ## requires `x` and `y` to be of the same tuple type - ## generic ``==`` operator for tuples that is lifted from the components + ## generic `==` operator for tuples that is lifted from the components ## of `x` and `y`. result = true for a, b in fields(x, y): if a != b: result = false -Alternatively, the ``distinct`` type modifier can be applied to the type class +Alternatively, the `distinct` type modifier can be applied to the type class to allow each param matching the type class to bind to a different type. Such type classes are called `bind many`:idx: types. @@ -4964,7 +5012,7 @@ of "typedesc"-ness is stripped off: Generic inference restrictions ------------------------------ -The types ``var T`` and ``typedesc[T]`` cannot be inferred in a generic +The types `var T` and `typedesc[T]` cannot be inferred in a generic instantiation. The following is not allowed: .. code-block:: nim @@ -4998,7 +5046,7 @@ 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 +context, an "open" symbol can. Per default, overloaded symbols are open and every other symbol is closed. Open symbols are looked up in two different contexts: Both the context @@ -5017,9 +5065,9 @@ at definition and the context at instantiation are considered: echo a == b # works! -In the example, the generic ``==`` for tuples (as defined in the system module) -uses the ``==`` operators of the tuple's components. However, the ``==`` for -the ``Index`` type is defined *after* the ``==`` for tuples; yet the example +In the example, the generic `==` for tuples (as defined in the system module) +uses the `==` operators of the tuple's components. However, the `==` for +the `Index` type is defined *after* the `==` for tuples; yet the example compiles as the instantiation takes the currently defined symbols into account too. @@ -5038,13 +5086,13 @@ A symbol can be forced to be open by a `mixin`:idx: declaration: new result init result -``mixin`` statements only make sense in templates and generics. +`mixin` statements only make sense in templates and generics. Bind statement -------------- -The ``bind`` statement is the counterpart to the ``mixin`` statement. It +The `bind` statement is the counterpart to the `mixin` statement. It can be used to explicitly declare identifiers that should be bound early (i.e. the identifiers should be looked up in the scope of the template/generic definition): @@ -5065,10 +5113,54 @@ definition): echo genId() -But a ``bind`` is rarely useful because symbol binding from the definition +But a `bind` is rarely useful because symbol binding from the definition scope is the default. -``bind`` statements only make sense in templates and generics. +`bind` statements only make sense in templates and generics. + + +Delegating bind statements +-------------------------- + +The following example outlines a problem that can arise when generic +instantiations cross multiple different modules: + +.. code-block:: nim + + # module A + proc genericA*[T](x: T) = + mixin init + init(x) + + +.. code-block:: nim + + import C + + # module B + proc genericB*[T](x: T) = + # Without the `bind init` statement C's init proc is + # not available when `genericB` is instantiated: + bind init + genericA(x) + +.. code-block:: nim + + # module C + type O = object + proc init*(x: var O) = discard + +.. code-block:: nim + + # module main + import B, C + + genericB O() + +In module B has an `init` proc from module C in its scope that is not +taken into account when `genericB` is instantiated which leads to the +instantiation of `genericA`. The solution is to `forward`:idx these +symbols by a `bind` statement inside `genericB`. Templates @@ -5089,25 +5181,25 @@ Example: assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6)) -The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact +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 > b` is transformed into `b < a`. +| `a in b` is transformed into `contains(b, a)`. +| `notin` and `isnot` have the obvious meanings. -The "types" of templates can be the symbols ``untyped``, -``typed`` or ``typedesc``. These are "meta types", they can only be used in certain -contexts. Regular types can be used too; this implies that ``typed`` expressions +The "types" of templates can be the symbols `untyped`, +`typed` or `typedesc`. These are "meta types", they can only be used in certain +contexts. Regular types can be used too; this implies that `typed` expressions are expected. Typed vs untyped parameters --------------------------- -An ``untyped`` parameter means that symbol lookups and type resolution is not -performed before the expression is passed to the template. This means that for -example *undeclared* identifiers can be passed to the template: +An `untyped` parameter means that symbol lookups and type resolution is not +performed before the expression is passed to the template. This means that +*undeclared* identifiers, for example, can be passed to the template: .. code-block:: nim :test: "nim c $1" @@ -5128,21 +5220,21 @@ example *undeclared* identifiers can be passed to the template: declareInt(x) # invalid, because x has not been declared and so it has no type -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 +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. -**Note**: For historical reasons ``stmt`` was an alias for ``typed`` and -``expr`` was an alias for ``untyped``, but they are removed. +**Note**: For historical reasons, `stmt` was an alias for `typed` and +`expr` was an alias for `untyped`, but they are removed. Passing a code block to a template ---------------------------------- One can pass a block of statements as the last argument to a template -following the special ``:`` syntax: +following the special `:` syntax: .. code-block:: nim :test: "nim c $1" @@ -5161,12 +5253,12 @@ following the special ``:`` syntax: txt.writeLine("line 1") txt.writeLine("line 2") -In the example, the two ``writeLine`` statements are bound to the ``actions`` +In the example, the two `writeLine` statements are bound to the `actions` parameter. -Usually to pass a block of code to a template the parameter that accepts -the block needs to be of type ``untyped``. Because symbol lookups are then +Usually, to pass a block of code to a template, the parameter that accepts +the block needs to be of type `untyped`. Because symbol lookups are then delayed until template instantiation time: .. code-block:: nim @@ -5181,10 +5273,10 @@ delayed until template instantiation time: t: p() # fails with 'undeclared identifier: p' -The above code fails with the error message that ``p`` is not declared. -The reason for this is that the ``p()`` body is type-checked before getting -passed to the ``body`` parameter and type checking in Nim implies symbol lookups. -The same code works with ``untyped`` as the passed body is not required to be +The above code fails with the error message that `p` is not declared. +The reason for this is that the `p()` body is type-checked before getting +passed to the `body` parameter and type checking in Nim implies symbol lookups. +The same code works with `untyped` as the passed body is not required to be type-checked: .. code-block:: nim @@ -5202,8 +5294,8 @@ type-checked: Varargs of untyped ------------------ -In addition to the ``untyped`` meta-type that prevents type checking there is -also ``varargs[untyped]`` so that not even the number of parameters is fixed: +In addition to the `untyped` meta-type that prevents type checking, there is +also `varargs[untyped]` so that not even the number of parameters is fixed: .. code-block:: nim :test: "nim c $1" @@ -5237,7 +5329,7 @@ bound from the definition scope of the template: echo genId() # Works as 'lastId' has been bound in 'genId's defining scope -As in generics symbol binding can be influenced via ``mixin`` or ``bind`` +As in generics, symbol binding can be influenced via `mixin` or `bind` statements. @@ -5245,7 +5337,7 @@ statements. Identifier construction ----------------------- -In templates identifiers can be constructed with the backticks notation: +In templates, identifiers can be constructed with the backticks notation: .. code-block:: nim :test: "nim c $1" @@ -5258,15 +5350,15 @@ In templates identifiers can be constructed with the backticks notation: typedef(myint, int) var x: PMyInt -In the example ``name`` is instantiated with ``myint``, so \`T name\` becomes -``Tmyint``. +In the example, `name` is instantiated with `myint`, so \`T name\` becomes +`Tmyint`. Lookup rules for template parameters ------------------------------------ -A parameter ``p`` in a template is even substituted in the expression ``x.p``. -Thus template arguments can be used as field names and a global symbol can be +A parameter `p` in a template is even substituted in the expression `x.p`. +Thus, template arguments can be used as field names and a global symbol can be shadowed by the same argument name even when fully qualified: .. code-block:: nim @@ -5284,7 +5376,7 @@ shadowed by the same argument name even when fully qualified: tstLev(levA) # produces: 'levA levA' -But the global symbol can properly be captured by a ``bind`` statement: +But the global symbol can properly be captured by a `bind` statement: .. code-block:: nim # module 'm' @@ -5306,7 +5398,7 @@ But the global symbol can properly be captured by a ``bind`` statement: Hygiene in templates -------------------- -Per default templates are `hygienic`:idx:\: Local identifiers declared in a +Per default, templates are `hygienic`:idx:\: Local identifiers declared in a template cannot be accessed in the instantiation context: .. code-block:: nim @@ -5325,13 +5417,13 @@ template cannot be accessed in the instantiation context: Whether a symbol that is declared in a template is exposed to the instantiation -scope is controlled by the `inject`:idx: and `gensym`:idx: pragmas: gensym'ed -symbols are not exposed but inject'ed are. +scope is controlled by the `inject`:idx: and `gensym`:idx: pragmas: +`gensym`'ed symbols are not exposed but `inject`'ed symbols are. -The default for symbols of entity ``type``, ``var``, ``let`` and ``const`` -is ``gensym`` and for ``proc``, ``iterator``, ``converter``, ``template``, -``macro`` is ``inject``. However, if the name of the entity is passed as a -template parameter, it is an inject'ed symbol: +The default for symbols of entity `type`, `var`, `let` and `const` +is `gensym` and for `proc`, `iterator`, `converter`, `template`, +`macro` is `inject`. However, if the name of the entity is passed as a +template parameter, it is an `inject`'ed symbol: .. code-block:: nim template withFile(f, fn, mode: untyped, actions: untyped): untyped = @@ -5344,7 +5436,7 @@ template parameter, it is an inject'ed symbol: txt.writeLine("line 2") -The ``inject`` and ``gensym`` pragmas are second class annotations; they have +The `inject` and `gensym` pragmas are second class annotations; they have no semantics outside of a template definition and cannot be abstracted over: .. code-block:: nim @@ -5355,11 +5447,11 @@ no semantics outside of a template definition and cannot be abstracted over: To get rid of hygiene in templates, one can use the `dirty`:idx: pragma for -a template. ``inject`` and ``gensym`` have no effect in ``dirty`` templates. +a template. `inject` and `gensym` have no effect in `dirty` templates. -``gensym``'ed symbols cannot be used as ``field`` in the ``x.field`` syntax. -Nor can they be used in the ``ObjectConstruction(field: value)`` -and ``namedParameterCall(field = value)`` syntactic constructs. +`gensym`'ed symbols cannot be used as `field` in the `x.field` syntax. +Nor can they be used in the `ObjectConstruction(field: value)` +and `namedParameterCall(field = value)` syntactic constructs. The reason for this is that code like @@ -5378,7 +5470,7 @@ The reason for this is that code like should work as expected. However, this means that the method call syntax is not available for -``gensym``'ed symbols: +`gensym`'ed symbols: .. code-block:: nim :test: "nim c $1" @@ -5394,16 +5486,16 @@ However, this means that the method call syntax is not available for **Note**: The Nim compiler prior to version 1 was more lenient about this -requirement. Use the ``--useVersion:0.19`` switch for a transition period. +requirement. Use the `--useVersion:0.19` switch for a transition period. Limitations of the method call syntax ------------------------------------- -The expression ``x`` in ``x.f`` needs to be semantically checked (that means +The expression `x` in `x.f` needs to be semantically checked (that means symbol lookup and type checking) before it can be decided that it needs to be -rewritten to ``f(x)``. Therefore the dot syntax has some limitations when it +rewritten to `f(x)`. Therefore the dot syntax has some limitations when it is used to invoke templates/macros: .. code-block:: nim @@ -5423,7 +5515,7 @@ Another common example is this: :test: "nim c $1" :status: 1 - from sequtils import toSeq + from std/sequtils import toSeq iterator something: string = yield "Hello" @@ -5431,8 +5523,8 @@ Another common example is this: var info = something().toSeq -The problem here is that the compiler already decided that ``something()`` as -an iterator is not callable in this context before ``toSeq`` gets its +The problem here is that the compiler already decided that `something()` as +an iterator is not callable in this context before `toSeq` gets its chance to convert it into a sequence. It is also not possible to use fully qualified identifiers with module @@ -5443,7 +5535,7 @@ binds to symbols prohibits this. :test: "nim c $1" :status: 1 - import sequtils + import std/sequtils var myItems = @[1,3,3,7] let N1 = count(myItems, 3) # OK @@ -5459,7 +5551,7 @@ Macros ====== A macro is a special function that is executed at compile time. -Normally the input for a macro is an abstract syntax +Normally, the input for a macro is an abstract syntax tree (AST) of the code that is passed to it. The macro can then do transformations on it and return the transformed AST. This can be used to add custom language features and implement `domain-specific languages`:idx:. @@ -5481,15 +5573,15 @@ cannot change Nim's syntax. Debug Example ------------- -The following example implements a powerful ``debug`` command that accepts a +The following example implements a powerful `debug` command that accepts a variable number of arguments: .. code-block:: nim :test: "nim c $1" # to work with Nim syntax trees, we need an API that is defined in the - # ``macros`` module: - import macros + # `macros` module: + import std/macros macro debug(args: varargs[untyped]): untyped = # `args` is a collection of `NimNode` values that each contain the @@ -5531,24 +5623,24 @@ The macro call expands to: writeLine(stdout, x) -Arguments that are passed to a ``varargs`` parameter are wrapped in an array -constructor expression. This is why ``debug`` iterates over all of ``n``'s +Arguments that are passed to a `varargs` parameter are wrapped in an array +constructor expression. This is why `debug` iterates over all of `args`'s children. BindSym ------- -The above ``debug`` macro relies on the fact that ``write``, ``writeLine`` and -``stdout`` are declared in the system module and thus visible in the +The above `debug` macro relies on the fact that `write`, `writeLine` and +`stdout` are declared in the system module and are thus visible in the instantiating context. There is a way to use bound identifiers -(aka `symbols`:idx:) instead of using unbound identifiers. The ``bindSym`` +(aka `symbols`:idx:) instead of using unbound identifiers. The `bindSym` builtin can be used for that: .. code-block:: nim :test: "nim c $1" - import macros + import std/macros macro debug(n: varargs[typed]): untyped = result = newNimNode(nnkStmtList, n) @@ -5581,22 +5673,22 @@ The macro call expands to: write(stdout, ": ") writeLine(stdout, x) -However, the symbols ``write``, ``writeLine`` and ``stdout`` are already bound -and are not looked up again. As the example shows, ``bindSym`` does work with +However, the symbols `write`, `writeLine` and `stdout` are already bound +and are not looked up again. As the example shows, `bindSym` does work with overloaded symbols implicitly. Case-Of Macro ------------- -In Nim it is possible to have a macro with the syntax of a *case-of* -expression just with the difference that all of branches are passed to +In Nim, it is possible to have a macro with the syntax of a *case-of* +expression just with the difference that all *of-branches* are passed to and processed by the macro implementation. It is then up the macro implementation to transform the *of-branches* into a valid Nim statement. The following example should show how this feature could be used for a lexical analyzer. .. code-block:: nim - import macros + import std/macros macro case_token(args: varargs[untyped]): untyped = echo args.treeRepr @@ -5615,8 +5707,8 @@ used for a lexical analyzer. return tkUnknown -**Style note**: For code readability, it is the best idea to use the least -powerful programming construct that still suffices. So the "check list" is: +**Style note**: For code readability, it is best to use the least powerful +programming construct that still suffices. So the "check list" is: (1) Use an ordinary proc/iterator, if possible. (2) Else: Use a generic proc/iterator, if possible. @@ -5628,12 +5720,12 @@ For loop macro -------------- A macro that takes as its only input parameter an expression of the special -type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop: +type `system.ForLoopStmt` can rewrite the entirety of a `for` loop: .. code-block:: nim :test: "nim c $1" - import macros + import std/macros macro enumerate(x: ForLoopStmt): untyped = expectKind x, nnkForStmt @@ -5707,16 +5799,16 @@ Static params can also appear in the signatures of generic types: var m1: AffineTransform3D[float] # OK var m2: AffineTransform2D[string] # Error, `string` is not a `Number` -Please note that ``static T`` is just a syntactic convenience for the underlying -generic type ``static[T]``. The type param can be omitted to obtain the type +Please note that `static T` is just a syntactic convenience for the underlying +generic type `static[T]`. The type param can be omitted to obtain the type class of all constant expressions. A more specific type class can be created by -instantiating ``static`` with another type class. +instantiating `static` with another type class. One can force an expression to be evaluated at compile time as a constant -expression by coercing it to a corresponding ``static`` type: +expression by coercing it to a corresponding `static` type: .. code-block:: nim - import math + import std/math echo static(fac(5)), " ", static[bool](16.isPowerOfTwo) @@ -5728,15 +5820,15 @@ typedesc[T] In many contexts, Nim treats the names of types as regular values. These values exist only during the compilation phase, but since -all values must have a type, ``typedesc`` is considered their special type. +all values must have a type, `typedesc` is considered their special type. -``typedesc`` acts as a generic type. For instance, the type of the symbol -``int`` is ``typedesc[int]``. Just like with regular generic types, when the -generic param is omitted, ``typedesc`` denotes the type class of all types. -As a syntactic convenience, one can also use ``typedesc`` as a modifier. +`typedesc` acts as a generic type. For instance, the type of the symbol +`int` is `typedesc[int]`. Just like with regular generic types, when the +generic param is omitted, `typedesc` denotes the type class of all types. +As a syntactic convenience, one can also use `typedesc` as a modifier. -Procs featuring ``typedesc`` params are considered implicitly generic. -They will be instantiated for each unique combination of supplied types +Procs featuring `typedesc` params are considered implicitly generic. +They will be instantiated for each unique combination of supplied types, and within the body of the proc, the name of each param will refer to the bound concrete type: @@ -5750,7 +5842,7 @@ the bound concrete type: var tree = new(BinaryTree[int]) When multiple type params are present, they will bind freely to different -types. To force a bind-once behavior one can use an explicit generic param: +types. To force a bind-once behavior, one can use an explicit generic param: .. code-block:: nim proc acceptOnlyTypePairs[T, U](A, B: typedesc[T]; C, D: typedesc[U]) @@ -5790,16 +5882,16 @@ concrete type or a type class. echo "is float a number? ", isNumber(float) echo "is RootObj a number? ", isNumber(RootObj) -Passing ``typedesc`` almost identical, just with the differences that +Passing `typedesc` is almost identical, just with the difference that the macro is not instantiated generically. The type expression is -simply passed as a ``NimNode`` to the macro, like everything else. +simply passed as a `NimNode` to the macro, like everything else. .. code-block:: nim - import macros + import std/macros macro forwardType(arg: typedesc): typedesc = - # ``arg`` is of type ``NimNode`` + # `arg` is of type `NimNode` let tmp: NimNode = arg result = tmp @@ -5808,10 +5900,10 @@ simply passed as a ``NimNode`` to the macro, like everything else. typeof operator --------------- -**Note**: ``typeof(x)`` can for historical reasons also be written as -``type(x)`` but ``type(x)`` is discouraged. +**Note**: `typeof(x)` can for historical reasons also be written as +`type(x)` but `type(x)` is discouraged. -One can obtain the type of a given expression by constructing a ``typeof`` +One can obtain the type of a given expression by constructing a `typeof` value from it (in many other languages this is known as the `typeof`:idx: operator): @@ -5821,11 +5913,11 @@ operator): var y: typeof(x) # y has type int -If ``typeof`` is used to determine the result type of a proc/iterator/converter -call ``c(X)`` (where ``X`` stands for a possibly empty list of arguments), the -interpretation, where ``c`` is an iterator, is preferred over the +If `typeof` is used to determine the result type of a proc/iterator/converter +call `c(X)` (where `X` stands for a possibly empty list of arguments), the +interpretation, where `c` is an iterator, is preferred over the other interpretations, but this behavior can be changed by -passing ``typeOfProc`` as the second argument to ``typeof``: +passing `typeOfProc` as the second argument to `typeof`: .. code-block:: nim :test: "nim c $1" @@ -5833,7 +5925,7 @@ passing ``typeOfProc`` as the second argument to ``typeof``: iterator split(s: string): string = discard proc split(s: string): seq[string] = discard - # since an iterator is the preferred interpretation, `y` has the type ``string``: + # since an iterator is the preferred interpretation, `y` has the type `string`: assert typeof("a b c".split) is string assert typeof("a b c".split, typeOfProc) is seq[string] @@ -5846,24 +5938,24 @@ Nim supports splitting a program into pieces by a module concept. Each module needs to be in its own file and has its own `namespace`:idx:. Modules enable `information hiding`:idx: and `separate compilation`:idx:. A module may gain access to symbols of another module by the `import`:idx: -statement. `Recursive module dependencies`:idx: are allowed, but slightly -subtle. Only top-level symbols that are marked with an asterisk (``*``) are +statement. `Recursive module dependencies`:idx: are allowed, but are slightly +subtle. Only top-level symbols that are marked with an asterisk (`*`) are exported. A valid module name can only be a valid Nim identifier (and thus its -filename is ``identifier.nim``). +filename is `identifier.nim`). The algorithm for compiling modules is: -- compile the whole module as usual, following import statements recursively +- 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 +- If there is a cycle, only import the already parsed symbols (that are + exported); if an unknown identifier occurs then abort. This is best illustrated by an example: .. code-block:: nim # Module A type - T1* = int # Module A exports the type ``T1`` + T1* = int # Module A exports the type `T1` import B # the compiler starts parsing B proc main() = @@ -5884,39 +5976,40 @@ This is best illustrated by an example: Import statement -~~~~~~~~~~~~~~~~ +---------------- -After the ``import`` statement a list of module names can follow or a single -module name followed by an ``except`` list to prevent some symbols to be +After the `import` statement, a list of module names can follow or a single +module name followed by an `except` list to prevent some symbols from being imported: .. code-block:: nim :test: "nim c $1" :status: 1 - import strutils except `%`, toUpperAscii + import std/strutils except `%`, toUpperAscii # doesn't work then: echo "$1" % "abc".toUpperAscii -It is not checked that the ``except`` list is really exported from the module. +It is not checked that the `except` list is really exported from the module. This feature allows us to compile against an older version of the module that does not export these identifiers. -The ``import`` statement is only allowed at the top level. +The `import` statement is only allowed at the top level. Include statement -~~~~~~~~~~~~~~~~~ -The ``include`` statement does something fundamentally different than -importing a module: it merely includes the contents of a file. The ``include`` +----------------- + +The `include` statement does something fundamentally different than +importing a module: it merely includes the contents of a file. The `include` statement is useful to split up a large module into several files: .. code-block:: nim include fileA, fileB, fileC -The ``include`` statement can be used outside of the top level, as such: +The `include` statement can be used outside of the top level, as such: .. code-block:: nim # Module A @@ -5931,39 +6024,39 @@ The ``include`` statement can be used outside of the top level, as such: Module names in imports -~~~~~~~~~~~~~~~~~~~~~~~ +----------------------- -A module alias can be introduced via the ``as`` keyword: +A module alias can be introduced via the `as` keyword: .. code-block:: nim - import strutils as su, sequtils as qu + import std/strutils as su, std/sequtils as qu echo su.format("$1", "lalelu") The original module name is then not accessible. The notations -``path/to/module`` or ``"path/to/module"`` can be used to refer to a module +`path/to/module` or `"path/to/module"` can be used to refer to a module in subdirectories: .. code-block:: nim import lib/pure/os, "lib/pure/times" -Note that the module name is still ``strutils`` and not ``lib/pure/strutils`` +Note that the module name is still `strutils` and not `lib/pure/strutils` and so one **cannot** do: .. code-block:: nim import lib/pure/strutils echo lib/pure/strutils.toUpperAscii("abc") -Likewise, the following does not make sense as the name is ``strutils`` already: +Likewise, the following does not make sense as the name is `strutils` already: .. code-block:: nim import lib/pure/strutils as strutils Collective imports from a directory -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +----------------------------------- -The syntax ``import dir / [moduleA, moduleB]`` can be used to import multiple modules +The syntax `import dir / [moduleA, moduleB]` can be used to import multiple modules from the same directory. Path names are syntactically either Nim identifiers or string literals. If the path @@ -5974,47 +6067,47 @@ name is not a valid Nim identifier it needs to be a string literal: Pseudo import/include paths -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +--------------------------- A directory can also be a so-called "pseudo directory". They can be used to avoid ambiguity when there are multiple modules with the same path. There are two pseudo directories: -1. ``std``: The ``std`` pseudo directory is the abstract location of Nim's standard -library. For example, the syntax ``import std / strutils`` is used to unambiguously -refer to the standard library's ``strutils`` module. -2. ``pkg``: The ``pkg`` pseudo directory is used to unambiguously refer to a Nimble -package. However, for technical details that lie outside of the scope of this document +1. `std`: The `std` pseudo directory is the abstract location of Nim's standard +library. For example, the syntax `import std / strutils` is used to unambiguously +refer to the standard library's `strutils` module. +2. `pkg`: The `pkg` pseudo directory is used to unambiguously refer to a Nimble +package. However, for technical details that lie outside the scope of this document, its semantics are: *Use the search path to look for module name but ignore the standard -library locations*. In other words, it is the opposite of ``std``. +library locations*. In other words, it is the opposite of `std`. From import statement -~~~~~~~~~~~~~~~~~~~~~ +--------------------- -After the ``from`` statement, a module name follows followed by -an ``import`` to list the symbols one likes to use without explicit +After the `from` statement, a module name follows followed by +an `import` to list the symbols one likes to use without explicit full qualification: .. code-block:: nim :test: "nim c $1" - from strutils import `%` + from std/strutils import `%` echo "$1" % "abc" # always possible: full qualification: echo strutils.replace("abc", "a", "z") -It's also possible to use ``from module import nil`` if one wants to import +It's also possible to use `from module import nil` if one wants to import the module but wants to enforce fully qualified access to every symbol -in ``module``. +in `module`. Export statement -~~~~~~~~~~~~~~~~ +---------------- -An ``export`` statement can be used for symbol forwarding so that client +An `export` statement can be used for symbol forwarding so that client modules don't need to import a module's dependencies: .. code-block:: nim @@ -6038,7 +6131,7 @@ modules don't need to import a module's dependencies: echo $x When the exported symbol is another module, all of its definitions will -be forwarded. One can use an ``except`` list to exclude some of the symbols. +be forwarded. One can use an `except` list to exclude some of the symbols. Notice that when exporting, one needs to specify only the module name: @@ -6118,7 +6211,7 @@ 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 +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. @@ -6141,26 +6234,26 @@ This pragma can also take in an optional warning string to relay to developers. noSideEffect pragma ------------------- -The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side -effects. This means that the proc/iterator only changes locations that are +The `noSideEffect` pragma is used to mark a proc/iterator that can have only +side effects through parameters. This means that the proc/iterator only changes locations that are reachable from its parameters and the return value only depends on the -arguments. If none of its parameters have the type ``var T`` or ``ref T`` -or ``ptr T`` this means no locations are modified. It is a static error to -mark a proc/iterator to have no side effect if the compiler cannot verify -this. +parameters. If none of its parameters have the type `var`, `ref`, `ptr`, `cstring`, or `proc`, +then no locations are modified. + +It is a static error to mark a proc/iterator to have no side effect if the compiler cannot verify this. As a special semantic rule, the built-in `debugEcho -`_ pretends to be free of side effects, -so that it can be used for debugging routines marked as ``noSideEffect``. +`_ pretends to be free of side effects +so that it can be used for debugging routines marked as `noSideEffect`. -``func`` is syntactic sugar for a proc with no side effects: +`func` is syntactic sugar for a proc with no side effects: .. code-block:: nim func `+` (x, y: int): int -To override the compiler's side effect analysis a ``{.noSideEffect.}`` -``cast`` pragma block can be used: +To override the compiler's side effect analysis a `{.noSideEffect.}` +`cast` pragma block can be used: .. code-block:: nim @@ -6168,14 +6261,33 @@ To override the compiler's side effect analysis a ``{.noSideEffect.}`` {.cast(noSideEffect).}: echo "test" +When a `noSideEffect` proc has proc params `bar`, whether it can be used inside a `noSideEffect` context +depends on what the compiler knows about `bar`: + +.. code-block:: nim + :test: "nim c $1" + + func foo(bar: proc(): int): int = bar() + var count = 0 + proc fn1(): int = 1 + proc fn2(): int = (count.inc; count) + func fun1() = discard foo(fn1) # ok because fn1 is inferred as `func` + # func fun2() = discard foo(fn2) # would give: Error: 'fun2' can have side effects + + # with callbacks, the compiler is conservative, ie that bar will have side effects + var foo2: type(foo) = foo + func main() = + discard foo(fn1) # ok + # discard foo2(fn1) # now this errors + compileTime pragma ------------------ -The ``compileTime`` pragma is used to mark a proc or variable to be used only +The `compileTime` pragma is used to mark a proc or variable to be used only during compile-time execution. No code will be generated for it. Compile-time procs are useful as helpers for macros. Since version 0.12.0 of the language, a -proc that uses ``system.NimNode`` within its parameter types is implicitly -declared ``compileTime``: +proc that uses `system.NimNode` within its parameter types is implicitly +declared `compileTime`: .. code-block:: nim proc astHelper(n: NimNode): NimNode = @@ -6187,14 +6299,14 @@ Is the same as: proc astHelper(n: NimNode): NimNode {.compileTime.} = result = n -``compileTime`` variables are available at runtime too. This simplifies certain +`compileTime` variables are available at runtime too. This simplifies certain idioms where variables are filled at compile-time (for example, lookup tables) but accessed at runtime: .. code-block:: nim :test: "nim c -r $1" - import macros + import std/macros var nameToProc {.compileTime.}: seq[(string, proc (): string {.nimcall.})] @@ -6215,12 +6327,12 @@ but accessed at runtime: noReturn pragma --------------- -The ``noreturn`` pragma is used to mark a proc that never returns. +The `noreturn` pragma is used to mark a proc that never returns. acyclic pragma -------------- -The ``acyclic`` pragma can be used for object types to mark them as acyclic +The `acyclic` pragma can be used for object types to mark them as acyclic even though they seem to be cyclic. This is an **optimization** for the garbage collector to not consider objects of this type as part of a cycle: @@ -6239,26 +6351,26 @@ Or if we directly use a ref object: left, right: Node data: string -In the example, a tree structure is declared with the ``Node`` type. Note that +In the example, a tree structure is declared with the `Node` type. Note that the type definition is recursive and the GC has to assume that objects of -this type may form a cyclic graph. The ``acyclic`` pragma passes the +this type may form a cyclic graph. The `acyclic` pragma passes the information that this cannot happen to the GC. If the programmer uses the -``acyclic`` pragma for data types that are in reality cyclic, the memory leaks -can be the result, but memory safety is preserved. +`acyclic` pragma for data types that are in reality cyclic, this may result +in memory leaks, but memory safety is preserved. final pragma ------------ -The ``final`` pragma can be used for an object type to specify that it +The `final` pragma can be used for an object type to specify that it cannot be inherited from. Note that inheritance is only available for -objects that inherit from an existing object (via the ``object of SuperType`` -syntax) or that have been marked as ``inheritable``. +objects that inherit from an existing object (via the `object of SuperType` +syntax) or that have been marked as `inheritable`. shallow pragma -------------- -The ``shallow`` pragma affects the semantics of a type: The compiler is +The `shallow` pragma affects the semantics of a type: The compiler is allowed to make a shallow copy. This can cause serious semantic issues and break memory safety! However, it can speed up assignments considerably, because the semantics of Nim require deep copying of sequences and strings. @@ -6278,20 +6390,20 @@ structure: pure pragma ----------- -An object type can be marked with the ``pure`` pragma so that its type field +An object type can be marked with the `pure` pragma so that its type field which is used for runtime type identification is omitted. This used to be necessary for binary compatibility with other compiled languages. -An enum type can be marked as ``pure``. Then access of its fields always +An enum type can be marked as `pure`. Then access of its fields always requires full qualification. asmNoStackFrame pragma ---------------------- -A proc can be marked with the ``asmNoStackFrame`` pragma to tell the compiler +A proc can be marked with the `asmNoStackFrame` pragma to tell the compiler it should not generate a stack frame for the proc. There are also no exit -statements like ``return result;`` generated and the generated C function is -declared as ``__declspec(naked)`` or ``__attribute__((naked))`` (depending on +statements like `return result;` generated and the generated C function is +declared as `__declspec(naked)` or `__attribute__((naked))` (depending on the used C compiler). **Note**: This pragma should only be used by procs which consist solely of @@ -6299,11 +6411,11 @@ assembler statements. error pragma ------------ -The ``error`` pragma is used to make the compiler output an error message +The `error` pragma is used to make the compiler output an error message with the given content. The compilation does not necessarily abort after an error though. -The ``error`` pragma can also be used to +The `error` pragma can also be used to annotate a symbol (like an iterator or proc). The *usage* of the symbol then triggers a static error. This is especially useful to rule out that some operation is valid due to overloading and type conversions: @@ -6315,8 +6427,8 @@ operation is valid due to overloading and type conversions: fatal pragma ------------ -The ``fatal`` pragma is used to make the compiler output an error message -with the given content. In contrast to the ``error`` pragma, the compilation +The `fatal` pragma is used to make the compiler output an error message +with the given content. In contrast to the `error` pragma, the compilation is guaranteed to be aborted by this pragma. Example: .. code-block:: nim @@ -6325,17 +6437,17 @@ is guaranteed to be aborted by this pragma. Example: warning pragma -------------- -The ``warning`` pragma is used to make the compiler output a warning message +The `warning` pragma is used to make the compiler output a warning message with the given content. Compilation continues after the warning. hint pragma ----------- -The ``hint`` pragma is used to make the compiler output a hint message with +The `hint` pragma is used to make the compiler output a hint message with the given content. Compilation continues after the hint. line pragma ----------- -The ``line`` pragma can be used to affect line information of the annotated +The `line` pragma can be used to affect line information of the annotated statement, as seen in stack backtraces: .. code-block:: nim @@ -6346,14 +6458,14 @@ statement, as seen in stack backtraces: {.line: instantiationInfo().}: raise newException(EAssertionFailed, msg) -If the ``line`` pragma is used with a parameter, the parameter needs be a -``tuple[filename: string, line: int]``. If it is used without a parameter, -``system.InstantiationInfo()`` is used. +If the `line` pragma is used with a parameter, the parameter needs be a +`tuple[filename: string, line: int]`. If it is used without a parameter, +`system.InstantiationInfo()` is used. linearScanEnd pragma -------------------- -The ``linearScanEnd`` pragma can be used to tell the compiler how to +The `linearScanEnd` pragma can be used to tell the compiler how to compile a Nim `case`:idx: statement. Syntactically it has to be used as a statement: @@ -6367,22 +6479,22 @@ statement: of 2: echo "unlikely: use branch table" else: echo "unlikely too: use branch table for ", myInt -In the example, the case branches ``0`` and ``1`` are much more common than +In the example, the case branches `0` and `1` are much more common than the other cases. Therefore the generated assembler code should test for these values first so that the CPU's branch predictor has a good chance to succeed (avoiding an expensive CPU pipeline stall). The other cases might be put into a jump table for O(1) overhead but at the cost of a (very likely) pipeline stall. -The ``linearScanEnd`` pragma should be put into the last branch that should be +The `linearScanEnd` pragma should be put into the last branch that should be tested against via linear scanning. If put into the last branch of the -whole ``case`` statement, the whole ``case`` statement uses linear scanning. +whole `case` statement, the whole `case` statement uses linear scanning. computedGoto pragma ------------------- -The ``computedGoto`` pragma can be used to tell the compiler how to -compile a Nim `case`:idx: in a ``while true`` statement. +The `computedGoto` pragma can be used to tell the compiler how to +compile a Nim `case`:idx: in a `while true` statement. Syntactically it has to be used as a statement inside the loop: .. code-block:: nim @@ -6419,7 +6531,7 @@ Syntactically it has to be used as a statement inside the loop: vm() -As the example shows ``computedGoto`` is mostly useful for interpreters. If +As the example shows, `computedGoto` is mostly useful for interpreters. If the underlying backend (C compiler) does not support the computed goto extension the pragma is simply ignored. @@ -6506,18 +6618,18 @@ For third party pragmas, it depends on its implementation but uses the same synt register pragma --------------- -The ``register`` pragma is for variables only. It declares the variable as -``register``, giving the compiler a hint that the variable should be placed +The `register` pragma is for variables only. It declares the variable as +`register`, giving the compiler a hint that the variable should be placed in a hardware register for faster access. C compilers usually ignore this though and for good reasons: Often they do a better job without it anyway. -In highly specific cases (a dispatch loop of a bytecode interpreter for -example) it may provide benefits, though. +However, in highly specific cases (a dispatch loop of a bytecode interpreter +for example) it may provide benefits. global pragma ------------- -The ``global`` pragma can be applied to a variable within a proc to instruct +The `global` pragma can be applied to a variable within a proc to instruct the compiler to store it in a global location and initialize it once at program startup. @@ -6549,7 +6661,7 @@ used pragma ----------- Nim produces a warning for symbols that are not exported and not used either. -The ``used`` pragma can be attached to a symbol to suppress this warning. This +The `used` pragma can be attached to a symbol to suppress this warning. This is particularly useful when the symbol was generated by a macro: .. code-block:: nim @@ -6563,7 +6675,7 @@ is particularly useful when the symbol was generated by a macro: implementArithOps(int) echoAdd 3, 5 -``used`` can also be used as a top-level statement to mark a module as "used". +`used` can also be used as a top-level statement to mark a module as "used". This prevents the "Unused import" warning: .. code-block:: nim @@ -6579,7 +6691,7 @@ This prevents the "Unused import" warning: experimental pragma ------------------- -The ``experimental`` pragma enables experimental language features. Depending +The `experimental` pragma enables experimental language features. Depending on the concrete feature, this means that the feature is either considered too unstable for an otherwise stable release or that the future of the feature is uncertain (it may be removed at any time). @@ -6587,7 +6699,7 @@ is uncertain (it may be removed at any time). Example: .. code-block:: nim - import threadpool + import std/threadpool {.experimental: "parallel".} proc threadedEcho(s: string, i: int) = @@ -6604,7 +6716,7 @@ Example: As a top-level statement, the experimental pragma enables a feature for the rest of the module it's enabled in. This is problematic for macro and generic instantiations that cross a module scope. Currently, these usages have to be -put into a ``.push/pop`` environment: +put into a `.push/pop` environment: .. code-block:: nim @@ -6634,7 +6746,7 @@ supports but which should not be seen as part of the language specification. Bitsize pragma -------------- -The ``bitsize`` pragma is for object field members. It declares the field as +The `bitsize` pragma is for object field members. It declares the field as a bitfield in C/C++. .. code-block:: Nim @@ -6685,53 +6797,53 @@ This pragma has no effect on the JS backend. Volatile pragma --------------- -The ``volatile`` pragma is for variables only. It declares the variable as -``volatile``, whatever that means in C/C++ (its semantics are not well defined +The `volatile` pragma is for variables only. It declares the variable as +`volatile`, whatever that means in C/C++ (its semantics are not well defined in C/C++). **Note**: This pragma will not exist for the LLVM backend. -NoDecl pragma +nodecl pragma ------------- -The ``noDecl`` pragma can be applied to almost any symbol (variable, proc, +The `nodecl` pragma can be applied to almost any symbol (variable, proc, type, etc.) and is sometimes useful for interoperability with C: It tells Nim that it should not generate a declaration for the symbol in the C code. For example: .. code-block:: Nim var - EACCES {.importc, noDecl.}: cint # pretend EACCES was a variable, as + EACCES {.importc, nodecl.}: cint # pretend EACCES was a variable, as # Nim does not know its value -However, the ``header`` pragma is often the better alternative. +However, the `header` pragma is often the better alternative. **Note**: This will not work for the LLVM backend. Header pragma ------------- -The ``header`` pragma is very similar to the ``noDecl`` pragma: It can be +The `header` pragma is very similar to the `nodecl` pragma: It can be applied to almost any symbol and specifies that it should not be declared -and instead, the generated code should contain an ``#include``: +and instead, the generated code should contain an `#include`: .. code-block:: Nim type PFile {.importc: "FILE*", header: "".} = distinct pointer # import C's FILE* type; Nim will treat it as a new pointer type -The ``header`` pragma always expects a string constant. The string constant +The `header` pragma always expects a string constant. The string constant contains the header file: As usual for C, a system header file is enclosed -in angle brackets: ``<>``. If no angle brackets are given, Nim -encloses the header file in ``""`` in the generated C code. +in angle brackets: `<>`. If no angle brackets are given, Nim +encloses the header file in `""` in the generated C code. **Note**: This will not work for the LLVM backend. IncompleteStruct pragma ----------------------- -The ``incompleteStruct`` pragma tells the compiler to not use the -underlying C ``struct`` in a ``sizeof`` expression: +The `incompleteStruct` pragma tells the compiler to not use the +underlying C `struct` in a `sizeof` expression: .. code-block:: Nim type @@ -6741,14 +6853,14 @@ underlying C ``struct`` in a ``sizeof`` expression: Compile pragma -------------- -The ``compile`` pragma can be used to compile and link a C/C++ source file +The `compile` pragma can be used to compile and link a C/C++ source file with the project: .. code-block:: Nim {.compile: "myfile.cpp".} **Note**: Nim computes a SHA1 checksum and only recompiles the file if it -has changed. One can use the ``-f`` command-line option to force the recompilation +has changed. One can use the `-f` command-line option to force the recompilation of the file. Since 1.4 the `compile` pragma is also available with this syntax: @@ -6762,7 +6874,7 @@ that are passed to the C compiler when the file is recompiled. Link pragma ----------- -The ``link`` pragma can be used to link an additional file with the project: +The `link` pragma can be used to link an additional file with the project: .. code-block:: Nim {.link: "myfile.o".} @@ -6770,13 +6882,13 @@ The ``link`` pragma can be used to link an additional file with the project: PassC pragma ------------ -The ``passc`` pragma can be used to pass additional parameters to the C -compiler like one would using the command-line switch ``--passc``: +The `passc` pragma can be used to pass additional parameters to the C +compiler like one would using the command-line switch `--passc`: .. code-block:: Nim {.passc: "-Wall -Werror".} -Note that one can use ``gorge`` from the `system module `_ to +Note that one can use `gorge` from the `system module `_ to embed parameters from an external command that will be executed during semantic analysis: @@ -6786,7 +6898,7 @@ during semantic analysis: LocalPassc pragma ----------------- -The ``localPassc`` pragma can be used to pass additional parameters to the C +The `localPassc` pragma can be used to pass additional parameters to the C compiler, but only for the C/C++ file that is produced from the Nim module the pragma resides in: @@ -6798,13 +6910,13 @@ the pragma resides in: PassL pragma ------------ -The ``passL`` pragma can be used to pass additional parameters to the linker -like one would be using the command-line switch ``--passL``: +The `passL` pragma can be used to pass additional parameters to the linker +like one would be using the command-line switch `--passL`: .. code-block:: Nim {.passL: "-lSDLmain -lSDL".} -Note that one can use ``gorge`` from the `system module `_ to +Note that one can use `gorge` from the `system module `_ to embed parameters from an external command that will be executed during semantic analysis: @@ -6814,7 +6926,7 @@ during semantic analysis: Emit pragma ----------- -The ``emit`` pragma can be used to directly affect the output of the +The `emit` pragma can be used to directly affect the output of the compiler's code generator. The code is then unportable to other code generators/backends. Its usage is highly discouraged! However, it can be extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code. @@ -6835,8 +6947,8 @@ Example: embedsC() -``nimbase.h`` defines ``NIM_EXTERNC`` C macro that can be used for -``extern "C"`` code to work with both ``nim c`` and ``nim cpp``, e.g.: +`nimbase.h` defines `NIM_EXTERNC` C macro that can be used for +`extern "C"` code to work with both `nim c` and `nim cpp`, e.g.: .. code-block:: Nim proc foobar() {.importc:"$1".} @@ -6846,13 +6958,13 @@ Example: void fun(){} """.} -For backward compatibility, if the argument to the ``emit`` statement +For backward compatibility, if the argument to the `emit` statement is a single string literal, Nim symbols can be referred to via backticks. This usage is however deprecated. -For a toplevel emit statement the section where in the generated C/C++ file +For a top-level emit statement, the section where in the generated C/C++ file the code should be emitted can be influenced via the -prefixes ``/*TYPESECTION*/`` or ``/*VARSECTION*/`` or ``/*INCLUDESECTION*/``: +prefixes `/*TYPESECTION*/` or `/*VARSECTION*/` or `/*INCLUDESECTION*/`: .. code-block:: Nim {.emit: """/*TYPESECTION*/ @@ -6874,15 +6986,15 @@ ImportCpp pragma ---------------- **Note**: `c2nim `_ can parse a large subset of C++ and knows -about the ``importcpp`` pragma pattern language. It is not necessary +about the `importcpp` pragma pattern language. It is not necessary to know all the details described here. Similar to the `importc pragma for C <#foreign-function-interface-importc-pragma>`_, the -``importcpp`` pragma can be used to import `C++`:idx: methods or C++ symbols +`importcpp` pragma can be used to import `C++`:idx: methods or C++ symbols in general. The generated code then uses the C++ method calling -syntax: ``obj->method(arg)``. In combination with the ``header`` and ``emit`` +syntax: `obj->method(arg)`. In combination with the `header` and `emit` pragmas this allows *sloppy* interfacing with libraries written in C++: .. code-block:: Nim @@ -6912,16 +7024,16 @@ pragmas this allows *sloppy* interfacing with libraries written in C++: proc run(device: IrrlichtDevice): bool {. header: irr, importcpp: "#.run(@)".} -The compiler needs to be told to generate C++ (command ``cpp``) for -this to work. The conditional symbol ``cpp`` is defined when the compiler +The compiler needs to be told to generate C++ (command `cpp`) for +this to work. The conditional symbol `cpp` is defined when the compiler emits C++ code. Namespaces ~~~~~~~~~~ -The *sloppy interfacing* example uses ``.emit`` to produce ``using namespace`` +The *sloppy interfacing* example uses `.emit` to produce `using namespace` declarations. It is usually much better to instead refer to the imported name -via the ``namespace::identifier`` notation: +via the `namespace::identifier` notation: .. code-block:: nim type @@ -6932,21 +7044,21 @@ via the ``namespace::identifier`` notation: Importcpp for enums ~~~~~~~~~~~~~~~~~~~ -When ``importcpp`` is applied to an enum type the numerical enum values are -annotated with the C++ enum type, like in this example: ``((TheCppEnum)(3))``. +When `importcpp` is applied to an enum type the numerical enum values are +annotated with the C++ enum type, like in this example: `((TheCppEnum)(3))`. (This turned out to be the simplest way to implement it.) Importcpp for procs ~~~~~~~~~~~~~~~~~~~ -Note that the ``importcpp`` variant for procs uses a somewhat cryptic pattern +Note that the `importcpp` variant for procs uses a somewhat cryptic pattern language for maximum flexibility: -- A hash ``#`` symbol is replaced by the first or next argument. -- A dot following the hash ``#.`` indicates that the call should use C++'s dot +- A hash `#` symbol is replaced by the first or next argument. +- A dot following the hash `#.` indicates that the call should use C++'s dot or arrow notation. -- An at symbol ``@`` is replaced by the remaining arguments, separated by commas. +- An at symbol `@` is replaced by the remaining arguments, separated by commas. For example: @@ -6961,8 +7073,8 @@ Produces: x->CppMethod(1, 2, 3) As a special rule to keep backward compatibility with older versions of the -``importcpp`` pragma, if there is no special pattern -character (any of ``# ' @``) at all, C++'s +`importcpp` pragma, if there is no special pattern +character (any of `# ' @`) at all, C++'s dot or arrow notation is assumed, so the above example can also be written as: .. code-block:: nim @@ -6976,11 +7088,11 @@ capabilities: proc dictLookup(a: Dict, k: Key): Value {.importcpp: "#[#]".} -- An apostrophe ``'`` followed by an integer ``i`` in the range 0..9 +- An apostrophe `'` followed by an integer `i` in the range 0..9 is replaced by the i'th parameter *type*. The 0th position is the result type. This can be used to pass types to C++ function templates. Between - the ``'`` and the digit, an asterisk can be used to get to the base type - of the type. (So it "takes away a star" from the type; ``T*`` becomes ``T``.) + the `'` and the digit, an asterisk can be used to get to the base type + of the type. (So it "takes away a star" from the type; `T*` becomes `T`.) Two stars can be used to get to the element type of the element type etc. For example: @@ -6998,12 +7110,12 @@ Produces: x = SystemManager::getSubsystem() -- ``#@`` is a special case to support a ``cnew`` operation. It is required so +- `#@` is a special case to support a `cnew` operation. It is required so that the call expression is inlined directly, without going through a temporary location. This is only required to circumvent a limitation of the current code generator. -For example C++'s ``new`` operator can be "imported" like this: +For example C++'s `new` operator can be "imported" like this: .. code-block:: nim proc cnew*[T](x: T): ptr T {.importcpp: "(new '*0#@)", nodecl.} @@ -7018,7 +7130,7 @@ Produces: .. code-block:: C x = new Foo(3, 4) -However, depending on the use case ``new Foo`` can also be wrapped like this +However, depending on the use case `new Foo` can also be wrapped like this instead: .. code-block:: nim @@ -7031,7 +7143,7 @@ Wrapping constructors ~~~~~~~~~~~~~~~~~~~~~ Sometimes a C++ class has a private copy constructor and so code like -``Class c = Class(1,2);`` must not be generated but instead ``Class c(1,2);``. +`Class c = Class(1,2);` must not be generated but instead `Class c(1,2);`. For this purpose the Nim proc that wraps a C++ constructor needs to be annotated with the `constructor`:idx: pragma. This pragma also helps to generate faster C++ code since construction then doesn't invoke the copy constructor: @@ -7057,13 +7169,15 @@ everything that is required: Importcpp for objects ~~~~~~~~~~~~~~~~~~~~~ -Generic ``importcpp``'ed objects are mapped to C++ templates. This means that +Generic `importcpp`'ed objects are mapped to C++ templates. This means that one can import C++'s templates rather easily without the need for a pattern language for object types: .. code-block:: nim + :test: "nim cpp $1" + type - StdMap {.importcpp: "std::map", header: "".} [K, V] = object + StdMap[K, V] {.importcpp: "std::map", header: "".} = object proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {. importcpp: "#[#] = #", header: "".} @@ -7078,7 +7192,7 @@ Produces: x[6] = 91.4; -- If more precise control is needed, the apostrophe ``'`` can be used in the +- If more precise control is needed, the apostrophe `'` can be used in the supplied pattern to denote the concrete type parameters of the generic type. See the usage of the apostrophe operator in proc patterns for more details. @@ -7101,18 +7215,18 @@ ImportJs pragma --------------- Similar to the `importcpp pragma for C++ <#implementation-specific-pragmas-importcpp-pragma>`_, -the ``importjs`` pragma can be used to import Javascript methods or +the `importjs` pragma can be used to import Javascript methods or symbols in general. The generated code then uses the Javascript method -calling syntax: ``obj.method(arg)``. +calling syntax: `obj.method(arg)`. ImportObjC pragma ----------------- Similar to the `importc pragma for C -<#foreign-function-interface-importc-pragma>`_, the ``importobjc`` pragma can +<#foreign-function-interface-importc-pragma>`_, the `importobjc` pragma can be used to import `Objective C`:idx: methods. The generated code then uses the -Objective C method calling syntax: ``[obj method param1: arg]``. -In addition with the ``header`` and ``emit`` pragmas this +Objective C method calling syntax: `[obj method param1: arg]`. +In addition with the `header` and `emit` pragmas this allows *sloppy* interfacing with libraries written in Objective C: .. code-block:: Nim @@ -7151,15 +7265,15 @@ allows *sloppy* interfacing with libraries written in Objective C: g.greet(12, 34) g.free() -The compiler needs to be told to generate Objective C (command ``objc``) for -this to work. The conditional symbol ``objc`` is defined when the compiler +The compiler needs to be told to generate Objective C (command `objc`) for +this to work. The conditional symbol `objc` is defined when the compiler emits Objective C code. CodegenDecl pragma ------------------ -The ``codegenDecl`` pragma can be used to directly influence Nim's code +The `codegenDecl` pragma can be used to directly influence Nim's code generator. It receives a format string that determines how the variable or proc is declared in the generated code. @@ -7177,8 +7291,8 @@ will generate this C code: .. code-block:: c int progmem a -For procedures $1 is the return type of the procedure, $2 is the name of -the procedure and $3 is the parameter list. +For procedures, $1 is the return type of the procedure, $2 is the name of +the procedure, and $3 is the parameter list. The following nim code: @@ -7192,10 +7306,23 @@ will generate this code: __interrupt void myinterrupt() +`cppNonPod` pragma +------------------ + +The `.cppNonPod` pragma should be used for non-POD `importcpp` types so that they +work properly (in particular regarding constructor and destructor) for +`.threadvar` variables. This requires `--tlsEmulation:off`. + +.. code-block:: nim + type Foo {.cppNonPod, importcpp, header: "funs.h".} = object + x: cint + proc main()= + var a {.threadvar.}: Foo + InjectStmt pragma ----------------- -The ``injectStmt`` pragma can be used to inject a statement before every +The `injectStmt` pragma can be used to inject a statement before every other statement in the current module. It is only supposed to be used for debugging: @@ -7229,8 +7356,8 @@ pragma description nim c -d:FooBar=42 foobar.nim In the above example, providing the -d flag causes the symbol -``FooBar`` to be overwritten at compile-time, printing out 42. If the -``-d:FooBar=42`` were to be omitted, the default value of 5 would be +`FooBar` to be overwritten at compile-time, printing out 42. If the +`-d:FooBar=42` were to be omitted, the default value of 5 would be used. To see if a value was provided, `defined(FooBar)` can be used. The syntax `-d:flag` is actually just a shortcut for `-d:flag=true`. @@ -7242,7 +7369,7 @@ User-defined pragmas pragma pragma ------------- -The ``pragma`` pragma can be used to declare user-defined pragmas. This is +The `pragma` pragma can be used to declare user-defined pragmas. This is useful because Nim's templates and macros do not affect pragmas. User-defined pragmas are in a different module-wide scope than all other symbols. They cannot be imported from a module. @@ -7257,7 +7384,7 @@ Example: proc p*(a, b: int): int {.rtl.} = result = a+b -In the example, a new pragma named ``rtl`` is introduced that either imports +In the example, a new pragma named `rtl` is introduced that either imports a symbol from a dynamic library or exports the symbol for dynamic library generation. @@ -7266,7 +7393,7 @@ Custom annotations ------------------ It is possible to define custom typed pragmas. Custom pragmas do not affect code generation directly, but their presence can be detected by macros. -Custom pragmas are defined using templates annotated with pragma ``pragma``: +Custom pragmas are defined using templates annotated with pragma `pragma`: .. code-block:: nim template dbTable(name: string, table_space: string = "") {.pragma.} @@ -7275,7 +7402,8 @@ Custom pragmas are defined using templates annotated with pragma ``pragma``: template dbIgnore {.pragma.} -Consider stylized example of possible Object Relation Mapping (ORM) implementation: +Consider this stylized example of a possible Object Relation Mapping (ORM) +implementation: .. code-block:: nim const tblspace {.strdefine.} = "dev" # switch for dev, test and prod environments @@ -7305,10 +7433,11 @@ Custom pragmas can be used in all locations where ordinary pragmas can be specified. It is possible to annotate procs, templates, type and variable definitions, statements, etc. -Macros module includes helpers which can be used to simplify custom pragma -access `hasCustomPragma`, `getCustomPragmaVal`. Please consult the macros module -documentation for details. These macros are not magic, everything they do can -also be achieved by walking the AST of the object representation. +The macros module includes helpers which can be used to simplify custom pragma +access `hasCustomPragma`, `getCustomPragmaVal`. Please consult the +`macros `_ module documentation for details. These macros are not +magic, everything they do can also be achieved by walking the AST of the object +representation. More examples with custom pragmas: @@ -7364,7 +7493,7 @@ This is translated to: type MyObject {.schema: "schema.protobuf".} = object -This is translated to a call to the ``schema`` macro with a `nnkTypeDef` +This is translated to a call to the `schema` macro with a `nnkTypeDef` AST node capturing both the left-hand side and right-hand side of the definition. The macro can return a potentially modified `nnkTypeDef` tree which will replace the original row in the type section. @@ -7385,7 +7514,7 @@ are documented here. Importc pragma -------------- -The ``importc`` pragma provides a means to import a proc or a variable +The `importc` pragma provides a means to import a proc or a variable from C. The optional argument is a string containing the C identifier. If the argument is missing, the C name is the Nim identifier *exactly as spelled*: @@ -7393,8 +7522,8 @@ spelled*: .. code-block:: proc printf(formatstr: cstring) {.header: "", importc: "printf", varargs.} -When ``importc`` is applied to a ``let`` statement it can omit its value which -will then be expected to come from C. This can be used to import a C ``const``: +When `importc` is applied to a `let` statement it can omit its value which +will then be expected to come from C. This can be used to import a C `const`: .. code-block:: {.emit: "const int cconst = 42;".} @@ -7404,7 +7533,7 @@ will then be expected to come from C. This can be used to import a C ``const``: assert cconst == 42 Note that this pragma has been abused in the past to also work in the -js backend for js objects and functions. : Other backends do provide +JS backend for JS objects and functions. Other backends do provide the same feature under the same name. Also, when the target language is not set to C, other pragmas are available: @@ -7415,13 +7544,13 @@ is not set to C, other pragmas are available: .. code-block:: Nim proc p(s: cstring) {.importc: "prefix$1".} -In the example, the external name of ``p`` is set to ``prefixp``. Only ``$1`` -is available and a literal dollar sign must be written as ``$$``. +In the example, the external name of `p` is set to `prefixp`. Only `$1` +is available and a literal dollar sign must be written as `$$`. Exportc pragma -------------- -The ``exportc`` pragma provides a means to export a type, a variable, or a +The `exportc` pragma provides a means to export a type, a variable, or a procedure to C. Enums and constants can't be exported. The optional argument is a string containing the C identifier. If the argument is missing, the C name is the Nim identifier *exactly as spelled*: @@ -7432,37 +7561,37 @@ name is the Nim identifier *exactly as spelled*: Note that this pragma is somewhat of a misnomer: Other backends do provide the same feature under the same name. -The string literal passed to ``exportc`` can be a format string: +The string literal passed to `exportc` can be a format string: .. code-block:: Nim proc p(s: string) {.exportc: "prefix$1".} = echo s -In the example the external name of ``p`` is set to ``prefixp``. Only ``$1`` -is available and a literal dollar sign must be written as ``$$``. +In the example, the external name of `p` is set to `prefixp`. Only `$1` +is available and a literal dollar sign must be written as `$$`. -If the symbol should also be exported to a dynamic library, the ``dynlib`` -pragma should be used in addition to the ``exportc`` pragma. See +If the symbol should also be exported to a dynamic library, the `dynlib` +pragma should be used in addition to the `exportc` pragma. See `Dynlib pragma for export <#foreign-function-interface-dynlib-pragma-for-export>`_. Extern pragma ------------- -Like ``exportc`` or ``importc``, the ``extern`` pragma affects name -mangling. The string literal passed to ``extern`` can be a format string: +Like `exportc` or `importc`, the `extern` pragma affects name +mangling. The string literal passed to `extern` can be a format string: .. code-block:: Nim proc p(s: string) {.extern: "prefix$1".} = echo s -In the example, the external name of ``p`` is set to ``prefixp``. Only ``$1`` -is available and a literal dollar sign must be written as ``$$``. +In the example, the external name of `p` is set to `prefixp`. Only `$1` +is available and a literal dollar sign must be written as `$$`. Bycopy pragma ------------- -The ``bycopy`` pragma can be applied to an object or tuple type and +The `bycopy` pragma can be applied to an object or tuple type and instructs the compiler to pass the type by value to procs: .. code-block:: nim @@ -7474,13 +7603,13 @@ instructs the compiler to pass the type by value to procs: Byref pragma ------------ -The ``byref`` pragma can be applied to an object or tuple type and instructs +The `byref` pragma can be applied to an object or tuple type and instructs the compiler to pass the type by reference (hidden pointer) to procs. Varargs pragma -------------- -The ``varargs`` pragma can be applied to procedures only (and procedure +The `varargs` pragma can be applied to procedures only (and procedure types). It tells Nim that the proc can take a variable number of parameters after the last specified parameter. Nim string values will be converted to C strings automatically: @@ -7493,9 +7622,9 @@ strings automatically: Union pragma ------------ -The ``union`` pragma can be applied to any ``object`` type. It means all -of the object's fields are overlaid in memory. This produces a ``union`` -instead of a ``struct`` in the generated C/C++ code. The object declaration +The `union` pragma can be applied to any `object` type. It means all +of the object's fields are overlaid in memory. This produces a `union` +instead of a `struct` in the generated C/C++ code. The object declaration then must not use inheritance or any GC'ed memory but this is currently not checked. @@ -7505,7 +7634,7 @@ should scan unions conservatively. Packed pragma ------------- -The ``packed`` pragma can be applied to any ``object`` type. It ensures +The `packed` pragma can be applied to any `object` type. It ensures that the fields of an object are packed back-to-back in memory. It is useful to store packets or messages from/to network or hardware drivers, and for interoperability with C. Combining packed pragma with inheritance is not @@ -7517,8 +7646,8 @@ a static error. Usage with inheritance should be defined and documented. Dynlib pragma for import ------------------------ -With the ``dynlib`` pragma a procedure or a variable can be imported from -a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). +With the `dynlib` pragma, a procedure or a variable can be imported from +a dynamic library (`.dll` files for Windows, `lib*.so` files for UNIX). The non-optional argument has to be the name of the dynamic library: .. code-block:: Nim @@ -7529,13 +7658,13 @@ In general, importing a dynamic library does not require any special linker options or linking with import libraries. This also implies that no *devel* packages need to be installed. -The ``dynlib`` import mechanism supports a versioning scheme: +The `dynlib` import mechanism supports a versioning scheme: .. code-block:: nim proc Tcl_Eval(interp: pTcl_Interp, script: cstring): int {.cdecl, importc, dynlib: "libtcl(|8.5|8.4|8.3).so.(1|0)".} -At runtime the dynamic library is searched for (in this order):: +At runtime, the dynamic library is searched for (in this order):: libtcl.so.1 libtcl.so.0 @@ -7546,11 +7675,11 @@ At runtime the dynamic library is searched for (in this order):: libtcl8.3.so.1 libtcl8.3.so.0 -The ``dynlib`` pragma supports not only constant strings as an argument but also +The `dynlib` pragma supports not only constant strings as an argument but also string expressions in general: .. code-block:: nim - import os + import std/os proc getDllName: string = result = "mylib.dll" @@ -7561,37 +7690,37 @@ string expressions in general: proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().} -**Note**: Patterns like ``libtcl(|8.5|8.4).so`` are only supported in constant +**Note**: Patterns like `libtcl(|8.5|8.4).so` are only supported in constant strings, because they are precompiled. -**Note**: Passing variables to the ``dynlib`` pragma will fail at runtime +**Note**: Passing variables to the `dynlib` pragma will fail at runtime because of order of initialization problems. -**Note**: A ``dynlib`` import can be overridden with -the ``--dynlibOverride:name`` command-line option. The Compiler User Guide -contains further information. +**Note**: A `dynlib` import can be overridden with +the `--dynlibOverride:name` command-line option. The +`Compiler User Guide `_ contains further information. Dynlib pragma for export ------------------------ -With the ``dynlib`` pragma a procedure can also be exported to +With the `dynlib` pragma, a procedure can also be exported to a dynamic library. The pragma then has no argument and has to be used in -conjunction with the ``exportc`` pragma: +conjunction with the `exportc` pragma: .. code-block:: Nim proc exportme(): int {.cdecl, exportc, dynlib.} This is only useful if the program is compiled as a dynamic library via the -``--app:lib`` command-line option. +`--app:lib` command-line option. Threads ======= -To enable thread support the ``--threads:on`` command-line switch needs to -be used. The ``system`` module then contains several threading primitives. +To enable thread support the `--threads:on` command-line switch needs to +be used. The `system` module then contains several threading primitives. See the `threads `_ and `channels `_ modules for the low-level thread API. There are also high-level parallelism constructs available. See `spawn `_ for @@ -7608,35 +7737,35 @@ Thread pragma ------------- A proc that is executed as a new thread of execution should be marked by the -``thread`` pragma for reasons of readability. The compiler checks for +`thread` pragma for reasons of readability. The compiler checks for violations of the `no heap sharing restriction`:idx:\: This restriction implies that it is invalid to construct a data structure that consists of memory allocated from different (thread-local) heaps. -A thread proc is passed to ``createThread`` or ``spawn`` and invoked -indirectly; so the ``thread`` pragma implies ``procvar``. +A thread proc is passed to `createThread` or `spawn` and invoked +indirectly; so the `thread` pragma implies `procvar`. GC safety --------- -We call a proc ``p`` `GC safe`:idx: when it doesn't access any global variable -that contains GC'ed memory (``string``, ``seq``, ``ref`` or a closure) either +We call a proc `p` `GC safe`:idx: when it doesn't access any global variable +that contains GC'ed memory (`string`, `seq`, `ref` or a closure) either directly or indirectly through a call to a GC unsafe proc. The `gcsafe`:idx: annotation can be used to mark a proc to be gcsafe, -otherwise this property is inferred by the compiler. Note that ``noSideEffect`` -implies ``gcsafe``. The only way to create a thread is via ``spawn`` or -``createThread``. The invoked proc must not use ``var`` parameters nor must -any of its parameters contain a ``ref`` or ``closure`` type. This enforces +otherwise this property is inferred by the compiler. Note that `noSideEffect` +implies `gcsafe`. The only way to create a thread is via `spawn` or +`createThread`. The invoked proc must not use `var` parameters nor must +any of its parameters contain a `ref` or `closure` type. This enforces the *no heap sharing restriction*. -Routines that are imported from C are always assumed to be ``gcsafe``. -To disable the GC-safety checking the ``--threadAnalysis:off`` command-line +Routines that are imported from C are always assumed to be `gcsafe`. +To disable the GC-safety checking the `--threadAnalysis:off` command-line switch can be used. This is a temporary workaround to ease the porting effort from old code to the new threading model. -To override the compiler's gcsafety analysis a ``{.cast(gcsafe).}`` pragma block can +To override the compiler's gcsafety analysis a `{.cast(gcsafe).}` pragma block can be used: .. code-block:: nim @@ -7652,21 +7781,21 @@ be used: See also: -- `Shared heap memory management. `_. +- `Shared heap memory management `_. Threadvar pragma ---------------- -A variable can be marked with the ``threadvar`` pragma, which makes it a +A variable can be marked with the `threadvar` pragma, which makes it a `thread-local`:idx: variable; Additionally, this implies all the effects -of the ``global`` pragma. +of the `global` pragma. .. code-block:: nim var checkpoints* {.threadvar.}: seq[string] -Due to implementation restrictions thread-local variables cannot be -initialized within the ``var`` section. (Every thread-local variable needs to +Due to implementation restrictions, thread-local variables cannot be +initialized within the `var` section. (Every thread-local variable needs to be replicated at thread creation.) diff --git a/doc/manual/var_t_return.rst b/doc/manual/var_t_return.rst index c6de8cf7ce..e34993e3ef 100644 --- a/doc/manual/var_t_return.rst +++ b/doc/manual/var_t_return.rst @@ -1,6 +1,8 @@ -Memory safety for returning by ``var T`` is ensured by a simple borrowing -rule: If ``result`` does not refer to a location pointing to the heap -(that is in ``result = X`` the ``X`` involves a ``ptr`` or ``ref`` access) +.. default-role:: code + +Memory safety for returning by `var T` is ensured by a simple borrowing +rule: If `result` does not refer to a location pointing to the heap +(that is in `result = X` the `X` involves a `ptr` or `ref` access) then it has to be derived from the routine's first parameter: .. code-block:: nim @@ -11,10 +13,10 @@ then it has to be derived from the routine's first parameter: var x: int # we know 'forward' provides a view into the location derived from # its first argument 'x'. - result = forward(x) # Error: location is derived from ``x`` + result = forward(x) # Error: location is derived from `x` # which is not p's first parameter and lives # on the stack. -In other words, the lifetime of what ``result`` points to is attached to the +In other words, the lifetime of what `result` points to is attached to the lifetime of the first parameter and that is enough knowledge to verify memory safety at the call site. diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index dadcf62d45..cf2e0c2470 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ========================= Nim Experimental Features ========================= @@ -12,8 +14,8 @@ About this document =================== This document describes features of Nim that are to be considered experimental. -Some of these are not covered by the ``.experimental`` pragma or -``--experimental`` switch because they are already behind a special syntax and +Some of these are not covered by the `.experimental` pragma or +`--experimental` switch because they are already behind a special syntax and one may want to use Nim libraries using these features without using them oneself. @@ -28,13 +30,13 @@ Every Nim module resides in a (nimble) package. An object type can be attached to the package it resides in. If that is done, the type can be referenced from other modules as an `incomplete`:idx: object type. This feature allows to break up recursive type dependencies across module boundaries. Incomplete -object types are always passed ``byref`` and can only be used in pointer like -contexts (``var/ref/ptr IncompleteObject``) in general since the compiler does +object types are always passed `byref` and can only be used in pointer like +contexts (`var/ref/ptr IncompleteObject`) in general since the compiler does not yet know the size of the object. To complete an incomplete object -the ``package`` pragma has to be used. ``package`` implies ``byref``. +the `package` pragma has to be used. `package` implies `byref`. -As long as a type ``T`` is incomplete, neither ``sizeof(T)`` nor runtime -type information for ``T`` is available. +As long as a type `T` is incomplete, neither `sizeof(T)` nor runtime +type information for `T` is available. Example: @@ -63,8 +65,8 @@ Example: Void type ========= -The ``void`` type denotes the absence of any type. Parameters of -type ``void`` are treated as non-existent, ``void`` as a return type means that +The `void` type denotes the absence of any type. Parameters of +type `void` are treated as non-existent, `void` as a return type means that the procedure does not return a value: .. code-block:: nim @@ -73,7 +75,7 @@ the procedure does not return a value: nothing() # writes "ha" to stdout -The ``void`` type is particularly useful for generic code: +The `void` type is particularly useful for generic code: .. code-block:: nim proc callProc[T](p: proc (x: T), x: T) = @@ -88,7 +90,7 @@ The ``void`` type is particularly useful for generic code: callProc[int](intProc, 12) callProc[void](emptyProc) -However, a ``void`` type cannot be inferred in generic code: +However, a `void` type cannot be inferred in generic code: .. code-block:: nim callProc(emptyProc) @@ -96,8 +98,8 @@ However, a ``void`` type cannot be inferred in generic code: # but expected one of: # callProc(p: proc (T), x: T) -The ``void`` type is only valid for parameters and return types; other symbols -cannot have the type ``void``. +The `void` type is only valid for parameters and return types; other symbols +cannot have the type `void`. @@ -105,19 +107,19 @@ Covariance ========== Covariance in Nim can be introduced only through pointer-like types such -as ``ptr`` and ``ref``. Sequence, Array and OpenArray types, instantiated +as `ptr` and `ref`. Sequence, Array and OpenArray types, instantiated with pointer-like types will be considered covariant if and only if they -are also immutable. The introduction of a ``var`` modifier or additional -``ptr`` or ``ref`` indirections would result in invariant treatment of +are also immutable. The introduction of a `var` modifier or additional +`ptr` or `ref` indirections would result in invariant treatment of these types. -``proc`` types are currently always invariant, but future versions of Nim +`proc` types are currently always invariant, but future versions of Nim may relax this rule. User-defined generic types may also be covariant with respect to some of their parameters. By default, all generic params are considered invariant, -but you may choose the apply the prefix modifier ``in`` to a parameter to -make it contravariant or ``out`` to make it covariant: +but you may choose the apply the prefix modifier `in` to a parameter to +make it contravariant or `out` to make it covariant: .. code-block:: nim type @@ -166,10 +168,10 @@ values: # to point to a ComboBox On the other hand, in the `RingBuffer` example above, the designated generic -param is used to instantiate the non-pointer ``seq`` type, which means that +param is used to instantiate the non-pointer `seq` type, which means that the resulting generic type will have covariance that mimics an array or -sequence (i.e. it will be covariant only when instantiated with ``ptr`` and -``ref`` types): +sequence (i.e. it will be covariant only when instantiated with `ptr` and +`ref` types): .. code-block:: nim @@ -196,7 +198,7 @@ as `seq[AnnotatedPtr[T]]` or `RingBuffer[AnnotatedPtr[T]]` will also be considered covariant and you can create new pointer-like types by instantiating other user-defined pointer-like types. -The contravariant parameters introduced with the ``in`` modifier are currently +The contravariant parameters introduced with the `in` modifier are currently useful only when interfacing with imported types having such semantics. @@ -204,7 +206,7 @@ Automatic dereferencing ======================= Automatic dereferencing is performed for the first argument of a routine call. -This feature has to be only enabled via ``{.experimental: "implicitDeref".}``: +This feature has to be enabled via `{.experimental: "implicitDeref".}`: .. code-block:: nim {.experimental: "implicitDeref".} @@ -257,7 +259,7 @@ preface definitions inside a module. 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. + required, using `nim check` provides this option as well. Example: @@ -290,10 +292,10 @@ what code is executed at the top level: .. 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 + 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 + 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. @@ -325,7 +327,7 @@ Named argument overloading ========================== Routines with the same type signature can be called differently if a parameter -has different names. This does not need an ``experimental`` switch, but is an +has different names. This does not need an `experimental` switch, but is an unstable feature. .. code-block::nim @@ -344,7 +346,7 @@ Do notation =========== As a special more convenient notation, proc expressions involved in procedure -calls can use the ``do`` keyword: +calls can use the `do` keyword: .. code-block:: nim sort(cities) do (x,y: string) -> int: @@ -359,13 +361,13 @@ calls can use the ``do`` keyword: if not `ex`: echo `info`, ": Check failed: ", `expString` -``do`` is written after the parentheses enclosing the regular proc params. +`do` is written after the parentheses enclosing the regular proc params. The proc expression represented by the do block is appended to them. In calls using the command syntax, the do block will bind to the immediately preceding expression, transforming it in a call. -``do`` with parentheses is an anonymous ``proc``; however a ``do`` without -parentheses is just a block of code. The ``do`` notation can be used to +`do` with parentheses is an anonymous `proc`; however a `do` without +parentheses is just a block of code. The `do` notation can be used to pass multiple blocks to a macro: .. code-block:: nim @@ -385,7 +387,7 @@ dot operators ------------- **Note**: Dot operators are still experimental and so need to be enabled -via ``{.experimental: "dotOperators".}``. +via `{.experimental: "dotOperators".}`. Nim offers a special family of dot operators that can be used to intercept and rewrite proc call and field access attempts, referring @@ -398,7 +400,7 @@ When Nim encounters an expression that cannot be resolved by the standard overload resolution rules, the current scope will be searched for a dot operator that can be matched against a re-written form of the expression, where the unknown field or proc name is passed to -an ``untyped`` parameter: +an `untyped` parameter: .. code-block:: nim a.b # becomes `.`(a, b) @@ -408,7 +410,7 @@ The matched dot operators can be symbols of any callable kind (procs, templates and macros), depending on the desired effect: .. code-block:: nim - template `.` (js: PJsonNode, field: untyped): JSON = js[astToStr(field)] + template `.`(js: PJsonNode, field: untyped): JSON = js[astToStr(field)] var js = parseJson("{ x: 1, y: 2}") echo js.x # outputs 1 @@ -434,15 +436,47 @@ This operator will be matched against assignments to missing fields. .. code-block:: nim a.b = c # becomes `.=`(a, b, c) +Call operator +------------- +The call operator, `()`, matches all kinds of unresolved calls and takes +precedence over dot operators, however it does not match missing overloads +for existing routines. The experimental `callOperator` switch must be enabled +to use this operator. + +.. code-block:: nim + {.experimental: "callOperator".} + + template `()`(a: int, b: float): untyped = $(a, b) + + block: + let a = 1.0 + let b = 2 + doAssert b(a) == `()`(b, a) + doAssert a.b == `()`(b, a) + + block: + let a = 1.0 + proc b(): int = 2 + doAssert not compiles(b(a)) + doAssert not compiles(a.b) # `()` not called + + block: + let a = 1.0 + proc b(x: float): int = int(x + 1) + let c = 3.0 + + doAssert not compiles(a.b(c)) # gives a type mismatch error same as b(a, c) + doAssert (a.b)(c) == `()`(a.b, c) + Not nil annotation ================== **Note:** This is an experimental feature. It can be enabled with -``{.experimental: "notnil"}``. +`{.experimental: "notnil"}`. -All types for which ``nil`` is a valid value can be annotated with the ``not -nil`` annotation to exclude ``nil`` as a valid value: +All types for which `nil` is a valid value can be annotated with the `not +nil` annotation to exclude `nil` as a valid value: .. code-block:: nim {.experimental: "notnil"} @@ -465,6 +499,7 @@ The compiler ensures that every code path initializes variables which contain non-nilable pointers. The details of this analysis are still to be specified here. +.. include:: manual_experimental_strictnotnil.rst Concepts ======== @@ -493,9 +528,9 @@ The concept is a match if: a) all of the expressions within the body can be compiled for the tested type b) all statically evaluable boolean expressions in the body must be true -The identifiers following the ``concept`` keyword represent instances of the +The identifiers following the `concept` keyword represent instances of the currently matched type. You can apply any of the standard type modifiers such -as ``var``, ``ref``, ``ptr`` and ``static`` to denote a more specific type of +as `var`, `ref`, `ptr` and `static` to denote a more specific type of instance. You can also apply the `type` modifier to create a named instance of the type itself: @@ -513,9 +548,9 @@ the presence of callable symbols with specific signatures: OutputStream = concept var s s.write(string) -In order to check for symbols accepting ``type`` params, you must prefix -the type with the explicit ``type`` modifier. The named instance of the -type, following the ``concept`` keyword is also considered to have the +In order to check for symbols accepting `type` params, you must prefix +the type with the explicit `type` modifier. The named instance of the +type, following the `concept` keyword is also considered to have the explicit modifier and will be matched only as a type. .. code-block:: nim @@ -537,7 +572,7 @@ explicit modifier and will be matched only as a type. -x is T x - y is T -Please note that the ``is`` operator allows one to easily verify the precise +Please note that the `is` operator allows one to easily verify the precise type signatures of the required operations, but since type inference and default parameters are still applied in the concept body, it's also possible to describe usage protocols that do not reveal implementation details. @@ -553,7 +588,7 @@ By default, the compiler will report the matching errors in concepts only when no other overload can be selected and a normal compilation error is produced. When you need to understand why the compiler is not matching a particular concept and, as a result, a wrong overload is selected, you can apply the -``explain`` pragma to either the concept body or a particular call-site. +`explain` pragma to either the concept body or a particular call-site. .. code-block:: nim type @@ -573,7 +608,7 @@ The concept types can be parametric just like the regular generic types: .. code-block:: nim ### matrixalgo.nim - import typetraits + import std/typetraits type AnyMatrix*[R, C: static int; T] = concept m, var mvar, type M @@ -637,7 +672,7 @@ resembles the way generic parameters of callable symbols are inferred on call sites. Unbound types can appear both as params to calls such as `s.push(T)` and -on the right-hand side of the ``is`` operator in cases such as `x.pop is T` +on the right-hand side of the `is` operator in cases such as `x.pop is T` and `x.data is seq[T]`. Unbound static params will be inferred from expressions involving the `==` @@ -651,8 +686,8 @@ operator and also when types dependent on them are being matched: The Nim compiler includes a simple linear equation solver, allowing it to infer static params in some situations where integer arithmetic is involved. -Just like in regular type classes, Nim discriminates between ``bind once`` -and ``bind many`` types when matching the concept. You can add the ``distinct`` +Just like in regular type classes, Nim discriminates between `bind once` +and `bind many` types when matching the concept. You can add the `distinct` modifier to any of the otherwise inferable types to get a type that will be matched without permanently inferring it. This may be useful when you need to match several procs accepting the same wide class of types: @@ -675,7 +710,7 @@ to match several procs accepting the same wide class of types: type Enum = distinct Enumerable o.baz is Enum -On the other hand, using ``bind once`` types allows you to test for equivalent +On the other hand, using `bind once` types allows you to test for equivalent types used in multiple signatures, without actually requiring any concrete types, thus allowing you to encode implementation-defined types: @@ -710,7 +745,7 @@ type is an instance of it: .. code-block:: nim :test: "nim c $1" - import sugar, typetraits + import std/[sugar, typetraits] type Functor[A] = concept f @@ -728,7 +763,7 @@ type is an instance of it: # the Functor to a instance of a different type, given # a suitable `map` operation for the enclosed values - import options + import std/options echo Option[int] is Functor # prints true @@ -771,7 +806,7 @@ concept, we say that the outer concept is a refinement of the inner concept and thus it is more-specific. When both concepts are matched in a call during overload resolution, Nim will assign a higher precedence to the most specific one. As an alternative way of defining concept refinements, you can use the -object inheritance syntax involving the ``of`` keyword: +object inheritance syntax involving the `of` keyword: .. code-block:: nim type @@ -862,8 +897,8 @@ object inheritance syntax involving the ``of`` keyword: any type can implement an unlimited number of protocols or interfaces not originally envisioned by the type's author. - Any concept type can be turned into a VTable type by using the ``vtref`` - or the ``vtptr`` compiler magics. Under the hood, these magics generate + Any concept type can be turned into a VTable type by using the `vtref` + or the `vtptr` compiler magics. Under the hood, these magics generate a converter type class, which converts the regular instances of the matching types to the corresponding VTable type. @@ -895,8 +930,8 @@ object inheritance syntax involving the ``of`` keyword: but it will include a smaller number of captured procs. A completely empty vtable will be reported as an error. - The ``vtref`` magic produces types which can be bound to ``ref`` types and - the ``vtptr`` magic produced types bound to ``ptr`` types. + The `vtref` magic produces types which can be bound to `ref` types and + the `vtptr` magic produced types bound to `ptr` types. Type bound operations @@ -911,12 +946,12 @@ There are 4 operations that are bound to a type: These operations can be *overridden* instead of *overloaded*. This means the implementation is automatically lifted to structured types. For instance if type -``T`` has an overridden assignment operator ``=`` this operator is also used -for assignments of the type ``seq[T]``. Since these operations are bound to a +`T` has an overridden assignment operator `=` this operator is also used +for assignments of the type `seq[T]`. Since these operations are bound to a type they have to be bound to a nominal type for reasons of simplicity of -implementation: This means an overridden ``deepCopy`` for ``ref T`` is really -bound to ``T`` and not to ``ref T``. This also means that one cannot override -``deepCopy`` for both ``ptr T`` and ``ref T`` at the same time; instead a +implementation: This means an overridden `deepCopy` for `ref T` is really +bound to `T` and not to `ref T`. This also means that one cannot override +`deepCopy` for both `ptr T` and `ref T` at the same time; instead a helper distinct or object type has to be used for one pointer type. Assignments, moves and destruction are specified in @@ -926,9 +961,9 @@ the `destructors `_ document. deepCopy -------- -``=deepCopy`` is a builtin that is invoked whenever data is passed to -a ``spawn``'ed proc to ensure memory safety. The programmer can override its -behaviour for a specific ``ref`` or ``ptr`` type ``T``. (Later versions of the +`=deepCopy` is a builtin that is invoked whenever data is passed to +a `spawn`'ed proc to ensure memory safety. The programmer can override its +behaviour for a specific `ref` or `ptr` type `T`. (Later versions of the language may weaken this restriction.) The signature has to be: @@ -939,27 +974,26 @@ The signature has to be: This mechanism will be used by most data structures that support shared memory like channels to implement thread safe automatic memory management. -The builtin ``deepCopy`` can even clone closures and their environments. See +The builtin `deepCopy` can even clone closures and their environments. See the documentation of `spawn <#parallel-amp-spawn-spawn-statement>`_ for details. Case statement macros ===================== -A macro that needs to be called `match`:idx: can be used to rewrite -``case`` statements in order to implement `pattern matching`:idx: for -certain types. The following example implements a simplistic form of -pattern matching for tuples, leveraging the existing equality operator -for tuples (as provided in ``system.==``): +Macros named `case` can rewrite `case` statements for certain types in order to +implement `pattern matching`:idx:. The following example implements a +simplistic form of pattern matching for tuples, leveraging the existing +equality operator for tuples (as provided in `system.==`): .. code-block:: nim :test: "nim c $1" {.experimental: "caseStmtMacros".} - import macros + import std/macros - macro match(n: tuple): untyped = + macro `case`(n: tuple): untyped = result = newTree(nnkIfStmt) let selector = n[0] for i in 1 ..< n.len: @@ -972,8 +1006,7 @@ for tuples (as provided in ``system.==``): let cond = newCall("==", selector, it[j]) result.add newTree(nnkElifBranch, cond, it[^1]) else: - error "'match' cannot handle this node", it - echo repr result + error "custom 'case' for tuple cannot handle this node", it case ("foo", 78) of ("foo", 78): echo "yes" @@ -982,14 +1015,14 @@ for tuples (as provided in ``system.==``): Currently case statement macros must be enabled explicitly -via ``{.experimental: "caseStmtMacros".}``. +via `{.experimental: "caseStmtMacros".}`. -``match`` macros are subject to overload resolution. First the -``case``'s selector expression is used to determine which ``match`` -macro to call. To this macro is then passed the complete ``case`` -statement body and the macro is evaluated. +`case` macros are subject to overload resolution. The type of the +`case` statement's selector expression is matched against the type +of the first argument of the `case` macro. Then the complete `case` +statement is passed in place of the argument and the macro is evaluated. -In other words, the macro needs to transform the full ``case`` statement +In other words, the macro needs to transform the full `case` statement but only the statement's selector expression is used to determine which macro to call. @@ -1008,10 +1041,10 @@ compilation pipeline with user defined optimizations: let x = 3 echo x * 2 -The compiler now rewrites ``x * 2`` as ``x + x``. The code inside the -curlies is the pattern to match against. The operators ``*``, ``**``, -``|``, ``~`` have a special meaning in patterns if they are written in infix -notation, so to match verbatim against ``*`` the ordinary function call syntax +The compiler now rewrites `x * 2` as `x + x`. The code inside the +curlies is the pattern to match against. The operators `*`, `**`, +`|`, `~` have a special meaning in patterns if they are written in infix +notation, so to match verbatim against `*` the ordinary function call syntax needs to be used. Term rewriting macro are applied recursively, up to a limit. This means that @@ -1049,7 +1082,7 @@ You can make one overload matching with a constraint and one without, and the one with a constraint will have precedence, and so you can handle both cases differently. -So what about ``2 * a``? We should tell the compiler ``*`` is commutative. We +So what about `2 * a`? We should tell the compiler `*` is commutative. We cannot really do that however as the following code only swaps arguments blindly: @@ -1061,59 +1094,59 @@ What optimizers really need to do is a *canonicalization*: .. code-block:: nim template canonMul{`*`(a, b)}(a: int{lit}, b: int): int = b*a -The ``int{lit}`` parameter pattern matches against an expression of -type ``int``, but only if it's a literal. +The `int{lit}` parameter pattern matches against an expression of +type `int`, but only if it's a literal. Parameter constraints --------------------- -The `parameter constraint`:idx: expression can use the operators ``|`` (or), -``&`` (and) and ``~`` (not) and the following predicates: +The `parameter constraint`:idx: expression can use the operators `|` (or), +`&` (and) and `~` (not) and the following predicates: =================== ===================================================== Predicate Meaning =================== ===================================================== -``atom`` The matching node has no children. -``lit`` The matching node is a literal like "abc", 12. -``sym`` The matching node must be a symbol (a bound +`atom` The matching node has no children. +`lit` The matching node is a literal like "abc", 12. +`sym` The matching node must be a symbol (a bound identifier). -``ident`` The matching node must be an identifier (an unbound +`ident` The matching node must be an identifier (an unbound identifier). -``call`` The matching AST must be a call/apply expression. -``lvalue`` The matching AST must be an lvalue. -``sideeffect`` The matching AST must have a side effect. -``nosideeffect`` The matching AST must have no side effect. -``param`` A symbol which is a parameter. -``genericparam`` A symbol which is a generic parameter. -``module`` A symbol which is a module. -``type`` A symbol which is a type. -``var`` A symbol which is a variable. -``let`` A symbol which is a ``let`` variable. -``const`` A symbol which is a constant. -``result`` The special ``result`` variable. -``proc`` A symbol which is a proc. -``method`` A symbol which is a method. -``iterator`` A symbol which is an iterator. -``converter`` A symbol which is a converter. -``macro`` A symbol which is a macro. -``template`` A symbol which is a template. -``field`` A symbol which is a field in a tuple or an object. -``enumfield`` A symbol which is a field in an enumeration. -``forvar`` A for loop variable. -``label`` A label (used in ``block`` statements). -``nk*`` The matching AST must have the specified kind. - (Example: ``nkIfStmt`` denotes an ``if`` statement.) -``alias`` States that the marked parameter needs to alias +`call` The matching AST must be a call/apply expression. +`lvalue` The matching AST must be an lvalue. +`sideeffect` The matching AST must have a side effect. +`nosideeffect` The matching AST must have no side effect. +`param` A symbol which is a parameter. +`genericparam` A symbol which is a generic parameter. +`module` A symbol which is a module. +`type` A symbol which is a type. +`var` A symbol which is a variable. +`let` A symbol which is a `let` variable. +`const` A symbol which is a constant. +`result` The special `result` variable. +`proc` A symbol which is a proc. +`method` A symbol which is a method. +`iterator` A symbol which is an iterator. +`converter` A symbol which is a converter. +`macro` A symbol which is a macro. +`template` A symbol which is a template. +`field` A symbol which is a field in a tuple or an object. +`enumfield` A symbol which is a field in an enumeration. +`forvar` A for loop variable. +`label` A label (used in `block` statements). +`nk*` The matching AST must have the specified kind. + (Example: `nkIfStmt` denotes an `if` statement.) +`alias` States that the marked parameter needs to alias with *some* other parameter. -``noalias`` States that *every* other parameter must not alias +`noalias` States that *every* other parameter must not alias with the marked parameter. =================== ===================================================== Predicates that share their name with a keyword have to be escaped with backticks. -The ``alias`` and ``noalias`` predicates refer not only to the matching AST, +The `alias` and `noalias` predicates refer not only to the matching AST, but also to every other bound parameter; syntactically they need to occur after the ordinary AST predicates: @@ -1127,14 +1160,14 @@ the ordinary AST predicates: Pattern operators ----------------- -The operators ``*``, ``**``, ``|``, ``~`` have a special meaning in patterns +The operators `*`, `**`, `|`, `~` have a special meaning in patterns if they are written in infix notation. -The ``|`` operator +The `|` operator ~~~~~~~~~~~~~~~~~~ -The ``|`` operator if used as infix operator creates an ordered choice: +The `|` operator if used as infix operator creates an ordered choice: .. code-block:: nim template t{0|1}(): untyped = 3 @@ -1151,15 +1184,15 @@ constant folding, so the following does not work: echo 1 The reason is that the compiler already transformed the 1 into "1" for -the ``echo`` statement. However, a term rewriting macro should not change the -semantics anyway. In fact they can be deactivated with the ``--patterns:off`` -command line option or temporarily with the ``patterns`` pragma. +the `echo` statement. However, a term rewriting macro should not change the +semantics anyway. In fact they can be deactivated with the `--patterns:off` +command line option or temporarily with the `patterns` pragma. -The ``{}`` operator +The `{}` operator ~~~~~~~~~~~~~~~~~~~ -A pattern expression can be bound to a pattern parameter via the ``expr{param}`` +A pattern expression can be bound to a pattern parameter via the `expr{param}` notation: .. code-block:: nim @@ -1169,10 +1202,10 @@ notation: echo a -The ``~`` operator +The `~` operator ~~~~~~~~~~~~~~~~~~ -The ``~`` operator is the **not** operator in patterns: +The `~` operator is the **not** operator in patterns: .. code-block:: nim template t{x = (~x){y} and (~x){z}}(x, y, z: bool) = @@ -1187,11 +1220,11 @@ The ``~`` operator is the **not** operator in patterns: echo a -The ``*`` operator +The `*` operator ~~~~~~~~~~~~~~~~~~ -The ``*`` operator can *flatten* a nested binary expression like ``a & b & c`` -to ``&(a, b, c)``: +The `*` operator can *flatten* a nested binary expression like `a & b & c` +to `&(a, b, c)`: .. code-block:: nim var @@ -1212,23 +1245,23 @@ to ``&(a, b, c)``: The second operator of `*` must be a parameter; it is used to gather all the -arguments. The expression ``"my" && (space & "awe" && "some " ) && "concat"`` -is passed to ``optConc`` in ``a`` as a special list (of kind ``nkArgList``) -which is flattened into a call expression; thus the invocation of ``optConc`` +arguments. The expression `"my" && (space & "awe" && "some " ) && "concat"` +is passed to `optConc` in `a` as a special list (of kind `nkArgList`) +which is flattened into a call expression; thus the invocation of `optConc` produces: .. code-block:: nim `&&`("my", space & "awe", "some ", "concat") -The ``**`` operator +The `**` operator ~~~~~~~~~~~~~~~~~~~ -The ``**`` is much like the ``*`` operator, except that it gathers not only +The `**` is much like the `*` operator, except that it gathers not only all the arguments, but also the matched operators in reverse polish notation: .. code-block:: nim - import macros + import std/macros type Matrix = object @@ -1249,8 +1282,8 @@ all the arguments, but also the matched operators in reverse polish notation: echo x + y * z - x -This passes the expression ``x + y * z - x`` to the ``optM`` macro as -an ``nnkArglist`` node containing:: +This passes the expression `x + y * z - x` to the `optM` macro as +an `nnkArglist` node containing:: Arglist Sym "x" @@ -1261,14 +1294,14 @@ an ``nnkArglist`` node containing:: Sym "x" Sym "-" -(Which is the reverse polish notation of ``x + y * z - x``.) +(Which is the reverse polish notation of `x + y * z - x`.) Parameters ---------- Parameters in a pattern are type checked in the matching process. If a -parameter is of the type ``varargs`` it is treated specially and it can match +parameter is of the type `varargs` it is treated specially and it can match 0 or more arguments in the AST to be matched against: .. code-block:: nim @@ -1300,7 +1333,7 @@ Example: Hoisting The following example shows how some form of hoisting can be implemented: .. code-block:: nim - import pegs + import std/pegs template optPeg{peg(pattern)}(pattern: string{lit}): Peg = var gl {.global, gensym.} = peg(pattern) @@ -1310,9 +1343,9 @@ The following example shows how some form of hoisting can be implemented: echo match("(a b c)", peg"'(' @ ')'") echo match("W_HI_Le", peg"\y 'while'") -The ``optPeg`` template optimizes the case of a peg constructor with a string +The `optPeg` template optimizes the case of a peg constructor with a string literal, so that the pattern will only be parsed once at program startup and -stored in a global ``gl`` which is then re-used. This optimization is called +stored in a global `gl` which is then re-used. This optimization is called hoisting because it is comparable to classical loop hoisting. @@ -1338,7 +1371,7 @@ constraints affect ordinary overloading resolution then: optLit(constant) optLit(variable) -However, the constraints ``alias`` and ``noalias`` are not available in +However, the constraints `alias` and `noalias` are not available in ordinary routines. @@ -1346,26 +1379,26 @@ Parallel & Spawn ================ Nim has two flavors of parallelism: -1) `Structured`:idx: parallelism via the ``parallel`` statement. -2) `Unstructured`:idx: parallelism via the standalone ``spawn`` statement. +1) `Structured`:idx: parallelism via the `parallel` statement. +2) `Unstructured`:idx: parallelism via the standalone `spawn` statement. Nim has a builtin thread pool that can be used for CPU intensive tasks. For -IO intensive tasks the ``async`` and ``await`` features should be +IO intensive tasks the `async` and `await` features should be used instead. Both parallel and spawn need the `threadpool `_ module to work. -Somewhat confusingly, ``spawn`` is also used in the ``parallel`` statement -with slightly different semantics. ``spawn`` always takes a call expression of -the form ``f(a, ...)``. Let ``T`` be ``f``'s return type. If ``T`` is ``void`` -then ``spawn``'s return type is also ``void`` otherwise it is ``FlowVar[T]``. +Somewhat confusingly, `spawn` is also used in the `parallel` statement +with slightly different semantics. `spawn` always takes a call expression of +the form `f(a, ...)`. Let `T` be `f`'s return type. If `T` is `void` +then `spawn`'s return type is also `void` otherwise it is `FlowVar[T]`. -Within a ``parallel`` section sometimes the ``FlowVar[T]`` is eliminated -to ``T``. This happens when ``T`` does not contain any GC'ed memory. -The compiler can ensure the location in ``location = spawn f(...)`` is not -read prematurely within a ``parallel`` section and so there is no need for -the overhead of an indirection via ``FlowVar[T]`` to ensure correctness. +Within a `parallel` section sometimes the `FlowVar[T]` is eliminated +to `T`. This happens when `T` does not contain any GC'ed memory. +The compiler can ensure the location in `location = spawn f(...)` is not +read prematurely within a `parallel` section and so there is no need for +the overhead of an indirection via `FlowVar[T]` to ensure correctness. -**Note**: Currently exceptions are not propagated between ``spawn``'ed tasks! +**Note**: Currently exceptions are not propagated between `spawn`'ed tasks! Spawn statement @@ -1374,7 +1407,7 @@ Spawn statement `spawn`:idx: can be used to pass a task to the thread pool: .. code-block:: nim - import threadpool + import std/threadpool proc processLine(line: string) = discard "do some heavy lifting here" @@ -1384,29 +1417,29 @@ Spawn statement sync() For reasons of type safety and implementation simplicity the expression -that ``spawn`` takes is restricted: +that `spawn` takes is restricted: -* It must be a call expression ``f(a, ...)``. -* ``f`` must be ``gcsafe``. -* ``f`` must not have the calling convention ``closure``. -* ``f``'s parameters may not be of type ``var``. - This means one has to use raw ``ptr``'s for data passing reminding the +* It must be a call expression `f(a, ...)`. +* `f` must be `gcsafe`. +* `f` must not have the calling convention `closure`. +* `f`'s parameters may not be of type `var`. + This means one has to use raw `ptr`'s for data passing reminding the programmer to be careful. -* ``ref`` parameters are deeply copied which is a subtle semantic change and +* `ref` parameters are deeply copied which is a subtle semantic change and can cause performance problems but ensures memory safety. This deep copy - is performed via ``system.deepCopy`` and so can be overridden. -* For *safe* data exchange between ``f`` and the caller a global ``TChannel`` + is performed via `system.deepCopy` and so can be overridden. +* For *safe* data exchange between `f` and the caller a global `TChannel` needs to be used. However, since spawn can return a result, often no further communication is required. -``spawn`` executes the passed expression on the thread pool and returns -a `data flow variable`:idx: ``FlowVar[T]`` that can be read from. The reading -with the ``^`` operator is **blocking**. However, one can use ``blockUntilAny`` to +`spawn` executes the passed expression on the thread pool and returns +a `data flow variable`:idx: `FlowVar[T]` that can be read from. The reading +with the `^` operator is **blocking**. However, one can use `blockUntilAny` to wait on multiple flow variables at the same time: .. code-block:: nim - import threadpool, ... + import std/threadpool, ... # wait until 2 out of 3 servers received the update: proc main = @@ -1419,8 +1452,8 @@ wait on multiple flow variables at the same time: discard blockUntilAny(responses) Data flow variables ensure that no data races -are possible. Due to technical limitations not every type ``T`` is possible in -a data flow variable: ``T`` has to be of the type ``ref``, ``string``, ``seq`` +are possible. Due to technical limitations not every type `T` is possible in +a data flow variable: `T` has to be of the type `ref`, `string`, `seq` or of a type that doesn't contain a type that is garbage collected. This restriction is not hard to work-around in practice. @@ -1435,7 +1468,7 @@ Example: :test: "nim c --threads:on $1" # Compute PI in an inefficient way - import strutils, math, threadpool + import std/[strutils, math, threadpool] {.experimental: "parallel".} proc term(k: float): float = 4 * math.pow(-1, k) / (2*k + 1) @@ -1452,7 +1485,7 @@ Example: The parallel statement is the preferred mechanism to introduce parallelism in a -Nim program. A subset of the Nim language is valid within a ``parallel`` +Nim program. A subset of the Nim language is valid within a `parallel` section. This subset is checked during semantic analysis to be free of data races. A sophisticated `disjoint checker`:idx: ensures that no data races are possible even though shared memory is extensively supported! @@ -1460,25 +1493,25 @@ possible even though shared memory is extensively supported! The subset is in fact the full language with the following restrictions / changes: -* ``spawn`` within a ``parallel`` section has special semantics. -* Every location of the form ``a[i]`` and ``a[i..j]`` and ``dest`` where - ``dest`` is part of the pattern ``dest = spawn f(...)`` has to be +* `spawn` within a `parallel` section has special semantics. +* Every location of the form `a[i]` and `a[i..j]` and `dest` where + `dest` is part of the pattern `dest = spawn f(...)` has to be provably disjoint. This is called the *disjoint check*. -* Every other complex location ``loc`` that is used in a spawned - proc (``spawn f(loc)``) has to be immutable for the duration of - the ``parallel`` section. This is called the *immutability check*. Currently +* Every other complex location `loc` that is used in a spawned + proc (`spawn f(loc)`) has to be immutable for the duration of + the `parallel` section. This is called the *immutability check*. Currently it is not specified what exactly "complex location" means. We need to make this an optimization! * Every array access has to be provably within bounds. This is called the *bounds check*. * Slices are optimized so that no copy is performed. This optimization is not - yet performed for ordinary slices outside of a ``parallel`` section. + yet performed for ordinary slices outside of a `parallel` section. Guards and locks ================ -Apart from ``spawn`` and ``parallel`` Nim also provides all the common low level +Apart from `spawn` and `parallel` Nim also provides all the common low level concurrency mechanisms like locks, atomic intrinsics or condition variables. Nim significantly improves on the safety of these features via additional @@ -1497,13 +1530,13 @@ Guards and the locks section Protecting global variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Object fields and global variables can be annotated via a ``guard`` pragma: +Object fields and global variables can be annotated via a `guard` pragma: .. code-block:: nim var glock: TLock var gdata {.guard: glock.}: int -The compiler then ensures that every access of ``gdata`` is within a ``locks`` +The compiler then ensures that every access of `gdata` is within a `locks` section: .. code-block:: nim @@ -1516,11 +1549,11 @@ section: {.locks: [glock].}: echo gdata -Top level accesses to ``gdata`` are always allowed so that it can be initialized +Top level accesses to `gdata` are always allowed so that it can be initialized conveniently. It is *assumed* (but not enforced) that every top level statement is executed before any concurrent action happens. -The ``locks`` section deliberately looks ugly because it has no runtime +The `locks` section deliberately looks ugly because it has no runtime semantics and should not be used directly! It should only be used in templates that also implement some form of locking at runtime: @@ -1549,7 +1582,7 @@ model low level lockfree mechanisms: echo atomicRead(atomicCounter) -The ``locks`` pragma takes a list of lock expressions ``locks: [a, b, ...]`` +The `locks` pragma takes a list of lock expressions `locks: [a, b, ...]` in order to support *multi lock* statements. Why these are essential is explained in the `lock levels <#guards-and-locks-lock-levels>`_ section. @@ -1557,7 +1590,7 @@ explained in the `lock levels <#guards-and-locks-lock-levels>`_ section. Protecting general locations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``guard`` annotation can also be used to protect fields within an object. +The `guard` annotation can also be used to protect fields within an object. The guard then needs to be another field within the same object or a global variable. @@ -1575,7 +1608,7 @@ expressivity of the language: lock counters[i].L: inc counters[i].v -The access to field ``x.v`` is allowed since its guard ``x.L`` is active. +The access to field `x.v` is allowed since its guard `x.L` is active. After template expansion, this amounts to: .. code-block:: nim @@ -1588,10 +1621,10 @@ After template expansion, this amounts to: finally: pthread_mutex_unlock(counters[i].L) -There is an analysis that checks that ``counters[i].L`` is the lock that -corresponds to the protected location ``counters[i].v``. This analysis is called +There is an analysis that checks that `counters[i].L` is the lock that +corresponds to the protected location `counters[i].v`. This analysis is called `path analysis`:idx: because it deals with paths to locations -like ``obj.field[i].fieldB[j]``. +like `obj.field[i].fieldB[j]`. The path analysis is **currently unsound**, but that doesn't make it useless. Two paths are considered equivalent if they are syntactically the same. @@ -1613,10 +1646,10 @@ potential deadlocks during semantic analysis. A lock level is an constant integer in the range 0..1_000. Lock level 0 means that no lock is acquired at all. -If a section of code holds a lock of level ``M`` than it can also acquire any -lock of level ``N < M``. Another lock of level ``M`` cannot be acquired. Locks +If a section of code holds a lock of level `M` than it can also acquire any +lock of level `N < M`. Another lock of level `M` cannot be acquired. Locks of the same level can only be acquired *at the same time* within a -single ``locks`` section: +single `locks` section: .. code-block:: nim var a, b: TLock[2] @@ -1641,8 +1674,8 @@ single ``locks`` section: Here is how a typical multilock statement can be implemented in Nim. Note how -the runtime check is required to ensure a global ordering for two locks ``a`` -and ``b`` of the same lock level: +the runtime check is required to ensure a global ordering for two locks `a` +and `b` of the same lock level: .. code-block:: nim template multilock(a, b: ptr TLock; body: untyped) = @@ -1660,9 +1693,9 @@ and ``b`` of the same lock level: pthread_mutex_unlock(b) -Whole routines can also be annotated with a ``locks`` pragma that takes a lock +Whole routines can also be annotated with a `locks` pragma that takes a lock level. This then means that the routine may acquire locks of up to this level. -This is essential so that procs can be called within a ``locks`` section: +This is essential so that procs can be called within a `locks` section: .. code-block:: nim proc p() {.locks: 3.} = discard @@ -1673,17 +1706,17 @@ This is essential so that procs can be called within a ``locks`` section: p() -As usual ``locks`` is an inferred effect and there is a subtype -relation: ``proc () {.locks: N.}`` is a subtype of ``proc () {.locks: M.}`` +As usual `locks` is an inferred effect and there is a subtype +relation: `proc () {.locks: N.}` is a subtype of `proc () {.locks: M.}` iff (M <= N). -The ``locks`` pragma can also take the special value ``"unknown"``. This +The `locks` pragma can also take the special value `"unknown"`. This is useful in the context of dynamic method dispatching. In the following -example, the compiler can infer a lock level of 0 for the ``base`` case. +example, the compiler can infer a lock level of 0 for the `base` case. However, one of the overloaded methods calls a procvar which is -potentially locking. Thus, the lock level of calling ``g.testMethod`` +potentially locking. Thus, the lock level of calling `g.testMethod` cannot be inferred statically, leading to compiler warnings. By using -``{.locks: "unknown".}``, the base method can be marked explicitly as +`{.locks: "unknown".}`, the base method can be marked explicitly as having unknown lock level as well: .. code-block:: nim @@ -1705,38 +1738,16 @@ they will rewrite as long as there is a match. There was no way to ensure some rewrite happens only once, e.g. when rewriting term to same term plus extra content. -``noRewrite`` pragma can actually prevent further rewriting on marked code, -e.g. with given example ``echo("ab")`` will be rewritten just once: +`noRewrite` pragma can actually prevent further rewriting on marked code, +e.g. with given example `echo("ab")` will be rewritten just once: .. code-block:: nim - template pwnEcho{echo(x)}(x: expr) = + template pwnEcho{echo(x)}(x: untyped) = {.noRewrite.}: echo("pwned!") echo "ab" -``noRewrite`` pragma can be useful to control term-rewriting macros recursion. - - -Taint mode -========== - -The Nim compiler and most parts of the standard library support -a taint mode. Input strings are declared with the `TaintedString`:idx: -string type declared in the ``system`` module. - -If the taint mode is turned on (via the ``--taintMode:on`` command line -option) it is a distinct string type which helps to detect input -validation errors: - -.. code-block:: nim - echo "your name: " - var name: TaintedString = stdin.readline - # it is safe here to output the name without any input validation, so - # we simply convert `name` to string to make the compiler happy: - echo "hi, ", name.string - -If the taint mode is turned off, ``TaintedString`` is simply an alias for -``string``. +`noRewrite` pragma can be useful to control term-rewriting macros recursion. Aliasing restrictions in parameter passing @@ -1746,8 +1757,8 @@ Aliasing restrictions in parameter passing implementation and need to be fleshed out further. "Aliasing" here means that the underlying storage locations overlap in memory -at runtime. An "output parameter" is a parameter of type ``var T``, -an input parameter is any parameter that is not of type ``var``. +at runtime. An "output parameter" is a parameter of type `var T`, +an input parameter is any parameter that is not of type `var`. 1. Two output parameters should never be aliased. 2. An input and an output parameter should not be aliased. @@ -1758,25 +1769,25 @@ an input parameter is any parameter that is not of type ``var``. 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: +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. + can only passed to a parameter of a `.noSideEffect` proc. Noalias annotation ================== -Since version 1.4 of the Nim compiler, there is a ``.noalias`` annotation for variables -and parameters. It is mapped directly to C/C++'s ``restrict`` keyword and means that +Since version 1.4 of the Nim compiler, there is a `.noalias` annotation for variables +and parameters. It is mapped directly to C/C++'s `restrict` keyword and means that the underlying pointer is pointing to a unique location in memory, no other aliases to this location exist. It is *unchecked* that this alias restriction is followed, if the restriction is violated, the backend optimizer is free to miscompile the code. This is an **unsafe** language feature. Ideally in later versions of the language, the restriction will be enforced at -compile time. (Which is also why the name ``noalias`` was choosen instead of a more -verbose name like ``unsafeAssumeNoAlias``.) +compile time. (Which is also why the name `noalias` was choosen instead of a more +verbose name like `unsafeAssumeNoAlias`.) Strict funcs @@ -1787,7 +1798,7 @@ to the existing rule that a side effect is calling a function with side effects the following rule is also enforced: Any mutation to an object does count as a side effect if that object is reachable -via a parameter that is not declared as a ``var`` parameter. +via a parameter that is not declared as a `var` parameter. For example: @@ -1821,14 +1832,14 @@ the `view types section <#view-types-algorithm>`_. View types ========== -**Note**: ``--experimental:views`` is more effective -with ``--experimental:strictFuncs``. +**Note**: `--experimental:views` is more effective +with `--experimental:strictFuncs`. A view type is a type that is or contains one of the following types: -- ``var T`` (mutable view into ``T``) -- ``lent T`` (immutable view into ``T``) -- ``openArray[T]`` (pair of (pointer to array of ``T``, size)) +- `var T` (mutable view into `T`) +- `lent T` (immutable view into `T`) +- `openArray[T]` (pair of (pointer to array of `T`, size)) For example: @@ -1841,7 +1852,7 @@ For example: View4 = Table[openArray[char], int] -Exceptions to this rule are types constructed via ``ptr`` or ``proc``. +Exceptions to this rule are types constructed via `ptr` or `proc`. For example, the following types are **not** view types: .. code-block:: nim @@ -1852,13 +1863,13 @@ For example, the following types are **not** view types: NotView3 = ptr array[4, var int] -A *mutable* view type is a type that is or contains a ``var T`` type. +A *mutable* view type is a type that is or contains a `var T` type. An *immutable* view type is a view type that is not a mutable view type. A *view* is a symbol (a let, var, const, etc.) that has a view type. Since version 1.4 Nim allows view types to be used as local variables. -This feature needs to be enabled via ``{.experimental: "views".}``. +This feature needs to be enabled via `{.experimental: "views".}`. A local variable of a view type *borrows* from the locations and it is statically enforced that the view does not outlive the location @@ -1892,47 +1903,47 @@ For example: A local variable of a view type can borrow from a location -derived from a parameter, another local variable, a global ``const`` or ``let`` -symbol or a thread-local ``var`` or ``let``. +derived from a parameter, another local variable, a global `const` or `let` +symbol or a thread-local `var` or `let`. -Let ``p`` the proc that is analysed for the correctness of the borrow operation. +Let `p` the proc that is analysed for the correctness of the borrow operation. -Let ``source`` be one of: +Let `source` be one of: -- A formal parameter of ``p``. Note that this does not cover parameters of +- A formal parameter of `p`. Note that this does not cover parameters of inner procs. -- The ``result`` symbol of ``p``. -- A local ``var`` or ``let`` or ``const`` of ``p``. Note that this does +- The `result` symbol of `p`. +- A local `var` or `let` or `const` of `p`. Note that this does not cover locals of inner procs. -- A thread-local ``var`` or ``let``. -- A global ``let`` or ``const``. +- A thread-local `var` or `let`. +- A global `let` or `const`. - A constant array/seq/object/tuple constructor. Path expressions ---------------- -A location derived from ``source`` is then defined as a path expression that -has ``source`` as the owner. A path expression ``e`` is defined recursively: +A location derived from `source` is then defined as a path expression that +has `source` as the owner. A path expression `e` is defined recursively: -- ``source`` itself is a path expression. -- Container access like ``e[i]`` is a path expression. -- Tuple access ``e[0]`` is a path expression. -- Object field access ``e.field`` is a path expression. -- ``system.toOpenArray(e, ...)`` is a path expression. -- Pointer dereference ``e[]`` is a path expression. -- An address ``addr e``, ``unsafeAddr e`` is a path expression. -- A type conversion ``T(e)`` is a path expression. -- A cast expression ``cast[T](e)`` is a path expression. -- ``f(e, ...)`` is a path expression if ``f``'s return type is a view type. - Because the view can only have been borrowed from ``e``, we then know - that owner of ``f(e, ...)`` is ``e``. +- `source` itself is a path expression. +- Container access like `e[i]` is a path expression. +- Tuple access `e[0]` is a path expression. +- Object field access `e.field` is a path expression. +- `system.toOpenArray(e, ...)` is a path expression. +- Pointer dereference `e[]` is a path expression. +- An address `addr e`, `unsafeAddr e` is a path expression. +- A type conversion `T(e)` is a path expression. +- A cast expression `cast[T](e)` is a path expression. +- `f(e, ...)` is a path expression if `f`'s return type is a view type. + Because the view can only have been borrowed from `e`, we then know + that owner of `f(e, ...)` is `e`. If a view type is used as a return type, the location must borrow from a location that is derived from the first parameter that is passed to the proc. See https://nim-lang.org/docs/manual.html#procedures-var-return-type for -details about how this is done for ``var T``. +details about how this is done for `var T`. A mutable view can borrow from a mutable location, an immutable view can borrow from both a mutable or an immutable location. @@ -1970,8 +1981,8 @@ The scope of the view does not matter: The analysis requires as much precision about mutations as is reasonably obtainable, so it is more effective with the experimental `strict funcs <#strict-funcs>`_ -feature. In other words ``--experimental:views`` works better -with ``--experimental:strictFuncs``. +feature. In other words `--experimental:views` works better +with `--experimental:strictFuncs`. The analysis is currently control flow insensitive: @@ -1983,8 +1994,8 @@ The analysis is currently control flow insensitive: s.setLen 0 echo v.field -In this example, the compiler assumes that ``s.setLen 0`` invalidates the -borrow operation of ``v`` even though a human being can easily see that it +In this example, the compiler assumes that `s.setLen 0` invalidates the +borrow operation of `v` even though a human being can easily see that it will never do that at runtime. @@ -2007,9 +2018,9 @@ A borrow operation ends with the last usage of the view variable. Reborrows --------- -A view ``v`` can borrow from multiple different locations. However, the borrow -is always the full span of ``v``'s lifetime and every location that is borrowed -from is sealed during ``v``'s lifetime. +A view `v` can borrow from multiple different locations. However, the borrow +is always the full span of `v`'s lifetime and every location that is borrowed +from is sealed during `v`'s lifetime. Algorithm @@ -2025,41 +2036,41 @@ a notion of an "abstract time", in the implementation it's a simple integer that incremented for every visited node. In the second pass information about the underlying object "graphs" is computed. -Let ``v`` be a parameter or a local variable. Let ``G(v)`` be the graph -that ``v`` belongs to. A graph is defined by the set of variables that belong -to the graph. Initially for all ``v``: ``G(v) = {v}``. Every variable can only +Let `v` be a parameter or a local variable. Let `G(v)` be the graph +that `v` belongs to. A graph is defined by the set of variables that belong +to the graph. Initially for all `v`: `G(v) = {v}`. Every variable can only be part of a single graph. -Assignments like ``a = b`` "connect" two variables, both variables end up in the -same graph ``{a, b} = G(a) = G(b)``. Unfortunately, the pattern to look for is +Assignments like `a = b` "connect" two variables, both variables end up in the +same graph `{a, b} = G(a) = G(b)`. Unfortunately, the pattern to look for is much more complex than that and can involve multiple assignment targets and sources:: f(x, y) = g(a, b) -connects ``x`` and ``y`` to ``a`` and ``b``: ``G(x) = G(y) = G(a) = G(b) = {x, y, a, b}``. +connects `x` and `y` to `a` and `b`: `G(x) = G(y) = G(a) = G(b) = {x, y, a, b}`. A type based alias analysis rules out some of these combinations, for example -a ``string`` value cannot possibly be connected to a ``seq[int]``. +a `string` value cannot possibly be connected to a `seq[int]`. -A pattern like ``v[] = value`` or ``v.field = value`` marks ``G(v)`` as mutated. +A pattern like `v[] = value` or `v.field = value` marks `G(v)` as mutated. After the second pass a set of disjoint graphs was computed. For strict functions it is then enforced that there is no graph that is both mutated and has an element that is an immutable parameter (that is a parameter that is not -of type ``var T``). +of type `var T`). -For borrow checking a different set of checks is performed. Let ``v`` be the view -and ``b`` the location that is borrowed from. +For borrow checking a different set of checks is performed. Let `v` be the view +and `b` the location that is borrowed from. -- The lifetime of ``v`` must not exceed ``b``'s lifetime. Note: The lifetime of +- The lifetime of `v` must not exceed `b`'s lifetime. Note: The lifetime of a parameter is the complete proc body. -- If ``v`` is a mutable view and ``v`` is used to actually mutate the - borrowed location, then ``b`` has to be a mutable location. +- If `v` is a mutable view and `v` is used to actually mutate the + borrowed location, then `b` has to be a mutable location. Note: If it is not actually used for mutation, borrowing a mutable view from an immutable location is allowed! This allows for many important idioms and will be justified in an upcoming RFC. -- During ``v``'s lifetime, ``G(b)`` can only be modified by ``v`` (and only if - ``v`` is a mutable view). -- If ``v`` is ``result`` then ``b`` has to be a location derived from the first +- During `v`'s lifetime, `G(b)` can only be modified by `v` (and only if + `v` is a mutable view). +- If `v` is `result` then `b` has to be a location derived from the first formal parameter or from a constant location. - A view cannot be used for a read or a write access before it was assigned to. diff --git a/doc/manual_experimental_strictnotnil.rst b/doc/manual_experimental_strictnotnil.rst new file mode 100644 index 0000000000..c7c045683a --- /dev/null +++ b/doc/manual_experimental_strictnotnil.rst @@ -0,0 +1,236 @@ +.. default-role:: code + +Strict not nil checking +========================= + +**Note:** This feature is experimental, you need to enable it with + +.. code-block:: nim + {.experimental: "strictNotNil".} + +or + +.. code-block:: bash + nim c --experimental:strictNotNil + +In the second case it would check builtin and imported modules as well. + +It checks the nilability of ref-like types and makes dereferencing safer based on flow typing and `not nil` annotations. + +Its implementation is different than the `notnil` one: defined under `strictNotNil`. Keep in mind the difference in option names, be careful with distinguishing them. + +We check several kinds of types for nilability: + +- ref types +- pointer types +- proc types +- cstrings + +nil +------- + +The default kind of nilability types is the nilable kind: they can have the value `nil`. +If you have a non-nilable type `T`, you can use `T nil` to get a nilable type for it. + + +not nil +-------- + +You can annotate a type where nil isn't a valid value with `not nil`. + +.. code-block:: nim + type + NilableObject = ref object + a: int + Object = NilableObject not nil + + Proc = (proc (x, y: int)) + + proc p(x: Object) = + echo x.a # ensured to dereference without an error + # compiler catches this: + p(nil) + # and also this: + var x: NilableObject + if x.isNil: + p(x) + else: + p(x) # ok + + + +If a type can include `nil` as a valid value, dereferencing values of the type +is checked by the compiler: if a value which might be nil is derefenced, this produces a warning by default, you can turn this into an error using the compiler options `--warningAsError:strictNotNil` + +If a type is nilable, you should dereference its values only after a `isNil` or equivalent check. + +local turn on/off +--------------------- + +You can still turn off nil checking on function/module level by using a `{.strictNotNil: off}.` pragma. +Note: test that/TODO for code/manual. + +nilability state +----------------- + +Currently a nilable value can be `Safe`, `MaybeNil` or `Nil` : we use internally `Parent` and `Unreachable` but this is an implementation detail(a parent layer has the actual nilability). + +`Safe` means it shouldn't be nil at that point: e.g. after assignment to a non-nil value or `not a.isNil` check +`MaybeNil` means it might be nil, but it might not be nil: e.g. an argument, a call argument or a value after an `if` and `else`. +`Nil` means it should be nil at that point; e.g. after an assignment to `nil` or a `.isNil` check. + +`Unreachable` means it shouldn't be possible to access this in this branch: so we do generate a warning as well. + +We show an error for each dereference (`[]`, `.field`, `[index]` `()` etc) which is of a tracked expression which is +in `MaybeNil` or `Nil` state. + + +type nilability +---------------- + +Types are either nilable or non-nilable. +When you pass a param or a default value, we use the type : for nilable types we return `MaybeNil` +and for non-nilable `Safe`. + +TODO: fix the manual here. (This is not great, as default values for non-nilables and nilables are usually actually `nil` , so we should think a bit more about this section.) + +params rules +------------ + +Param's nilability is detected based on type nilability. We use the type of the argument to detect the nilability. + + +assignment rules +----------------- + +Let's say we have `left = right`. + +When we assign, we pass the right's nilability to the left's expression. There should be special handling of aliasing and compound expressions which we specify in their sections. (Assignment is a possible alias `move` or `move out`). + +call args rules +----------------- + +When we call with arguments, we have two cases when we might change the nilability. + +.. code-block:: nim + callByVar(a) + +Here `callByVar` can re-assign `a`, so this might change `a`'s nilability, so we change it to `MaybeNil`. +This is also a possible aliasing `move out` (moving out of a current alias set). + +.. code-block:: nim + call(a) + +Here `call` can change a field or element of `a`, so if we have a dependant expression of `a` : e.g. `a.field`. Dependats become `MaybeNil`. + + +branches rules +--------------- + +Branches are the reason we do nil checking like this: with flow checking. +Sources of brancing are `if`, `while`, `for`, `and`, `or`, `case`, `try` and combinations with `return`, `break`, `continue` and `raise` + +We create a new layer/"scope" for each branch where we map expressions to nilability. This happens when we "fork": usually on the beginning of a construct. +When branches "join" we usually unify their expression maps or/and nilabilities. + +Merging usually merges maps and alias sets: nilabilities are merged like this: + +.. code-block:: nim + template union(l: Nilability, r: Nilability): Nilability = + ## unify two states + if l == r: + l + else: + MaybeNil + +Special handling is for `.isNil` and ` == nil`, also for `not`, `and` and `or`. + +`not` reverses the nilability, `and` is similar to "forking" : the right expression is checked in the layer resulting from the left one and `or` is similar to "merging": the right and left expression should be both checked in the original layer. + +`isNil`, `== nil` make expressions `Nil`. If there is a `not` or `!= nil`, they make them `Safe`. +We also reverse the nilability in the opposite branch: e.g. `else`. + +compound expressions: field, index expressions +----------------------------------------------- + +We want to track also field(dot) and index(bracket) expressions. + +We track some of those compound expressions which might be nilable as dependants of their bases: `a.field` is changed if `a` is moved (re-assigned), +similarly `a[index]` is dependent on `a` and `a.field.field` on `a.field`. + +When we move the base, we update dependants to `MaybeNil`. Otherwise we usually start with type nilability. + +When we call args, we update the nilability of their dependants to `MaybeNil` as the calls usually can change them. +We might need to check for `strictFuncs` pure funcs and not do that then. + +For field expressions `a.field`, we calculate an integer value based on a hash of the tree and just accept equivalent trees as equivalent expressions. + +For item expression `a[index]`, we also calculate an integer value based on a hash of the tree and accept equivalent trees as equivalent expressions: for static values only. +For now we support only constant indices: we dont track expression with no-const indices. For those we just report a warning even if they are safe for now: one can use a local variable to workaround. For loops this might be annoying: so one should be able to turn off locally the warning using the `{.warning[StrictCheckNotNil]:off}.`. + +For bracket expressions, in the future we might count `a[]` as the same general expression. +This means we should should the index but otherwise handle it the same for assign (maybe "aliasing" all the non-static elements) and differentiate only for static: e.g. `a[0]` and `a[1]`. + +element tracking +----------------- + +When we assign an object construction, we should track the fields as well: + + +.. code-block:: nim + var a = Nilable(field: Nilable()) # a : Safe, a.field: Safe + +Usually we just track the result of an expression: probably this should apply for elements in other cases as well. +Also related to tracking initialization of expressions/fields. + +unstructured control flow rules +------------------------------- + +Unstructured control flow keywords as `return`, `break`, `continue`, `raise` mean that we jump from a branch out. +This means that if there is code after the finishing of the branch, it would be ran if one hasn't hit the direct parent branch of those: so it is similar to an `else`. In those cases we should use the reverse nilabilities for the local to the condition expressions. E.g. + +.. code-block:: nim + for a in c: + if not a.isNil: + b() + break + code # here a: Nil , because if not, we would have breaked + + +aliasing +------------ + +We support alias detection for local expressions. + +We track sets of aliased expressions. We start with all nilable local expressions in separate sets. +Assignments and other changes to nilability can move / move out expressions of sets. + +`move`: Moving `left` to `right` means we remove `left` from its current set and unify it with the `right`'s set. +This means it stops being aliased with its previous aliases. + +.. code-block:: nim + var left = b + left = right # moving left to right + +`move out`: Moving out `left` might remove it from the current set and ensure that it's in its own set as a single element. +e.g. + + +.. code-block:: nim + var left = b + left = nil # moving out + + +initialization of non nilable and nilable values +------------------------------------------------- + +TODO + +warnings and errors +--------------------- + +We show an error for each dereference (`[]`, `.field`, `[index]` `()` etc) which is of a tracked expression which is +in `MaybeNil` or `Nil` state. + +We might also show a history of the transitions and the reasons for them that might change the nilability of the expression. + diff --git a/doc/nep1.rst b/doc/nep1.rst index 73e4d84331..3bae6a00bb 100644 --- a/doc/nep1.rst +++ b/doc/nep1.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ========================================================== Nim Enhancement Proposal #1 - Standard Library Style Guide ========================================================== @@ -62,15 +64,6 @@ Spacing and Whitespace Conventions Naming Conventions ------------------ -Note: While the rules outlined below are the *current* naming conventions, -these conventions have not always been in place. Previously, the naming -conventions for identifiers followed the Pascal tradition of prefixes which -indicated the base type of the identifier - PFoo for pointer and reference -types, TFoo for value types, EFoo for exceptions, etc. Though this has since -changed, there are many places in the standard library which still use this -convention. Such style remains in place purely for legacy reasons, and will be -changed in the future. - - Type identifiers should be in PascalCase. All other identifiers should be in camelCase with the exception of constants which **may** use PascalCase but are not required to. @@ -133,11 +126,11 @@ changed in the future. - In the age of HTTP, HTML, FTP, TCP, IP, UTF, WWW it is foolish to pretend these are somewhat special words requiring all uppercase. Instead treat them - as what they are: Real words. So it's ``parseUrl`` rather than - ``parseURL``, ``checkHttpHeader`` instead of ``checkHTTPHeader`` etc. + as what they are: Real words. So it's `parseUrl` rather than + `parseURL`, `checkHttpHeader` instead of `checkHTTPHeader` etc. -- Operations like ``mitems`` or ``mpairs`` (or the now deprecated ``mget``) - that allow a *mutating view* into some data structure should start with an ``m``. +- Operations like `mitems` or `mpairs` (or the now deprecated `mget`) + that allow a *mutating view* into some data structure should start with an `m`. - When both in-place mutation and 'returns transformed copy' are available the latter is a past participle of the former: @@ -145,8 +138,8 @@ changed in the future. - sort and sorted - rotate and rotated -- When the 'returns transformed copy' version already exists like ``strutils.replace`` - an in-place version should get an ``-In`` suffix (``replaceIn`` for this example). +- When the 'returns transformed copy' version already exists like `strutils.replace` + an in-place version should get an `-In` suffix (`replaceIn` for this example). - Use `subjectVerb`, not `verbSubject`, e.g.: `fileExists`, not `existsFile`. @@ -162,22 +155,25 @@ to keep the names short but meaningful. ------------------- ------------ -------------------------------------- English word To use Notes ------------------- ------------ -------------------------------------- -initialize initT ``init`` is used to create a - value type ``T`` -new newP ``new`` is used to create a - reference type ``P`` +initialize initFoo initializes a value type `Foo` +new newFoo initializes a reference type `Foo` + via `new` +this or self self for method like procs, e.g.: + `proc fun(self: Foo, a: int)` + rationale: `self` is more unique in English + than `this`, and `foo` would not be DRY. find find should return the position where something was found; for a bool result - use ``contains`` -contains contains often short for ``find() >= 0`` -append add use ``add`` instead of ``append`` + use `contains` +contains contains often short for `find() >= 0` +append add use `add` instead of `append` compare cmp should return an int with the - ``< 0`` ``== 0`` or ``> 0`` semantics; - for a bool result use ``sameXYZ`` -put put, ``[]=`` consider overloading ``[]=`` for put -get get, ``[]`` consider overloading ``[]`` for get; - consider to not use ``get`` as a - prefix: ``len`` instead of ``getLen`` + `< 0` `== 0` or `> 0` semantics; + for a bool result use `sameXYZ` +put put, `[]=` consider overloading `[]=` for put +get get, `[]` consider overloading `[]` for get; + consider to not use `get` as a + prefix: `len` instead of `getLen` length len also used for *number of elements* size size, len size should refer to a byte size capacity cap @@ -236,14 +232,14 @@ Coding Conventions proc repeat(text: string, x: int): string = result = "" - for i in 0 .. x: + for i in 0..x: result.add($i) - Use a proc when possible, only using the more powerful facilities of macros, templates, iterators, and converters when necessary. -- Use the ``let`` statement (not the ``var`` statement) when declaring variables that - do not change within their scope. Using the ``let`` statement ensures that +- Use the `let` statement (not the `var` statement) when declaring variables that + do not change within their scope. Using the `let` statement ensures that variables remain immutable, and gives those who read the code a better idea of the code's purpose. @@ -277,3 +273,30 @@ Conventions for multi-line statements and expressions .. code-block:: nim startProcess(nimExecutable, currentDirectory, compilerArguments environment, processOptions) + +Miscellaneous +------------- + +- Use `a..b` instead of `a .. b`, except when `b` contains an operator, for example `a .. -3`. + Likewise with `a..`_ and `defined proc `_. The typical use of this switch is -to enable builds in release mode (``-d:release``) where optimizations are -enabled for better performance. Another common use is the ``-d:ssl`` switch to +to enable builds in release mode (`-d:release`) where optimizations are +enabled for better performance. Another common use is the `-d:ssl` switch to activate SSL sockets. -Additionally, you may pass a value along with the symbol: ``-d:x=y`` +Additionally, you may pass a value along with the symbol: `-d:x=y` which may be used in conjunction with the `compile-time define pragmas`_ to override symbols during build time. Compile-time symbols are completely **case insensitive** and underscores are -ignored too. ``--define:FOO`` and ``--define:foo`` are identical. +ignored too. `--define:FOO` and `--define:foo` are identical. -Compile-time symbols starting with the ``nim`` prefix are reserved for the +Compile-time symbols starting with the `nim` prefix are reserved for the implementation and should not be used elsewhere. Configuration files ------------------- -**Note:** The *project file name* is the name of the ``.nim`` file that is +**Note:** The *project file name* is the name of the `.nim` file that is passed as a command-line argument to the compiler. -The ``nim`` executable processes configuration files in the following +The `nim` executable processes configuration files in the following directories (in this order; later files overwrite previous settings): -1) ``$nim/config/nim.cfg``, ``/etc/nim/nim.cfg`` (UNIX) or ``\config\nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option. -2) If environment variable ``XDG_CONFIG_HOME`` is defined, ``$XDG_CONFIG_HOME/nim/nim.cfg`` or ``~/.config/nim/nim.cfg`` (POSIX) or ``%APPDATA%/nim/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option. -3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command-line option. -4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project file's path. This file can be skipped with the ``--skipProjCfg`` command-line option. -5) A project can also have a project-specific configuration file named ``$project.nim.cfg`` that resides in the same directory as ``$project.nim``. This file can be skipped with the ``--skipProjCfg`` command-line option. +1) `$nim/config/nim.cfg`, `/etc/nim/nim.cfg` (UNIX) or ``\config\nim.cfg`` (Windows). This file can be skipped with the `--skipCfg` command line option. +2) If environment variable `XDG_CONFIG_HOME` is defined, `$XDG_CONFIG_HOME/nim/nim.cfg` or `~/.config/nim/nim.cfg` (POSIX) or `%APPDATA%/nim/nim.cfg` (Windows). This file can be skipped with the `--skipUserCfg` command line option. +3) `$parentDir/nim.cfg` where `$parentDir` stands for any parent directory of the project file's path. These files can be skipped with the `--skipParentCfg` command-line option. +4) `$projectDir/nim.cfg` where `$projectDir` stands for the project file's path. This file can be skipped with the `--skipProjCfg` command-line option. +5) A project can also have a project-specific configuration file named `$project.nim.cfg` that resides in the same directory as `$project.nim`. This file can be skipped with the `--skipProjCfg` command-line option. Command-line settings have priority over configuration file settings. The default build of a project is a `debug build`:idx:. To compile a -`release build`:idx: define the ``release`` symbol:: +`release build`:idx: define the `release` symbol:: nim c -d:release myproject.nim - To compile a `dangerous release build`:idx: define the ``danger`` symbol:: + To compile a `dangerous release build`:idx: define the `danger` symbol:: nim c -d:danger myproject.nim @@ -186,10 +188,10 @@ Nim has the concept of a global search path (PATH) that is queried to determine where to find imported modules or include files. If multiple files are found an ambiguity error is produced. -``nim dump`` shows the contents of the PATH. +`nim dump` shows the contents of the PATH. However before the PATH is used the current directory is checked for the -file's existence. So if PATH contains ``$lib`` and ``$lib/bar`` and the +file's existence. So if PATH contains `$lib` and `$lib/bar` and the directory structure looks like this:: $lib/x.nim @@ -198,27 +200,27 @@ directory structure looks like this:: foo/main.nim other.nim -And ``main`` imports ``x``, ``foo/x`` is imported. If ``other`` imports ``x`` -then both ``$lib/x.nim`` and ``$lib/bar/x.nim`` match but ``$lib/x.nim`` is used +And `main` imports `x`, `foo/x` is imported. If `other` imports `x` +then both `$lib/x.nim` and `$lib/bar/x.nim` match but `$lib/x.nim` is used as it is the first match. Generated C code directory -------------------------- The generated files that Nim produces all go into a subdirectory called -``nimcache``. Its full path is +`nimcache`. Its full path is -- ``$XDG_CACHE_HOME/nim/$projectname(_r|_d)`` or ``~/.cache/nim/$projectname(_r|_d)`` +- `$XDG_CACHE_HOME/nim/$projectname(_r|_d)` or `~/.cache/nim/$projectname(_r|_d)` on Posix -- ``$HOME/nimcache/$projectname(_r|_d)`` on Windows. +- `$HOME/nimcache/$projectname(_r|_d)` on Windows. -The ``_r`` suffix is used for release builds, ``_d`` is for debug builds. +The `_r` suffix is used for release builds, `_d` is for debug builds. This makes it easy to delete all generated files. -The ``--nimcache`` +The `--nimcache` `compiler switch <#compiler-usage-commandminusline-switches>`_ can be used to -to change the ``nimcache`` directory. +to change the `nimcache` directory. However, the generated C code is not platform-independent. C code generated for Linux does not compile on Windows, for instance. The comment on top of the @@ -232,16 +234,16 @@ To change the compiler from the default compiler (at the command line):: nim c --cc:llvm_gcc --compile_only myfile.nim -This uses the configuration defined in ``config\nim.cfg`` for ``lvm_gcc``. +This uses the configuration defined in ``config\nim.cfg`` for `lvm_gcc`. If nimcache already contains compiled code from a different compiler for the same project, -add the ``-f`` flag to force all files to be recompiled. +add the `-f` flag to force all files to be recompiled. The default compiler is defined at the top of ``config\nim.cfg``. -Changing this setting affects the compiler used by ``koch`` to (re)build Nim. +Changing this setting affects the compiler used by `koch` to (re)build Nim. -To use the ``CC`` environment variable, use ``nim c --cc:env myfile.nim``. To use the -``CXX`` environment variable, use ``nim cpp --cc:env myfile.nim``. ``--cc:env`` is available +To use the `CC` environment variable, use `nim c --cc:env myfile.nim`. To use the +`CXX` environment variable, use `nim cpp --cc:env myfile.nim`. `--cc:env` is available since Nim version 1.4. @@ -252,7 +254,7 @@ To cross compile, use for example:: nim c --cpu:i386 --os:linux --compileOnly --genScript myproject.nim -Then move the C code and the compile script ``compile_myproject.sh`` to your +Then move the C code and the compile script `compile_myproject.sh` to your Linux i386 machine and run the script. Another way is to make Nim invoke a cross compiler toolchain:: @@ -260,8 +262,8 @@ Another way is to make Nim invoke a cross compiler toolchain:: nim c --cpu:arm --os:linux myproject.nim For cross compilation, the compiler invokes a C compiler named -like ``$cpu.$os.$cc`` (for example arm.linux.gcc) and the configuration -system is used to provide meaningful defaults. For example for ``ARM`` your +like `$cpu.$os.$cc` (for example arm.linux.gcc) and the configuration +system is used to provide meaningful defaults. For example for `ARM` your configuration file should contain something like:: arm.linux.gcc.path = "/usr/bin" @@ -275,7 +277,7 @@ To cross-compile for Windows from Linux or macOS using the MinGW-w64 toolchain:: nim c -d:mingw myproject.nim -Use ``--cpu:i386`` or ``--cpu:amd64`` to switch the CPU architecture. +Use `--cpu:i386` or `--cpu:amd64` to switch the CPU architecture. The MinGW-w64 toolchain can be installed as follows:: @@ -295,7 +297,7 @@ The first one is to treat Android as a simple Linux and use directly on android as if it was Linux. These programs are console-only programs that can't be distributed in the Play Store. -Use regular ``nim c`` inside termux to make Android terminal programs. +Use regular `nim c` inside termux to make Android terminal programs. Normal Android apps are written in Java, to use Nim inside an Android app you need a small Java stub that calls out to a native library written in @@ -303,16 +305,16 @@ Nim using the `NDK `_. You can also use `native-activity `_ to have the Java stub be auto-generated for you. -Use ``nim c -c --cpu:arm --os:android -d:androidNDK --noMain:on`` to +Use `nim c -c --cpu:arm --os:android -d:androidNDK --noMain:on` to generate the C source files you need to include in your Android Studio project. Add the generated C files to CMake build script in your Android project. Then do the final compile with Android Studio which uses Gradle to call CMake to compile the project. -Because Nim is part of a library it can't have its own c style ``main()`` -so you would need to define your own ``android_main`` and init the Java +Because Nim is part of a library it can't have its own c style `main()` +so you would need to define your own `android_main` and init the Java environment, or use a library like SDL2 or GLFM to do it. After the Android -stuff is done, it's very important to call ``NimMain()`` in order to +stuff is done, it's very important to call `NimMain()` in order to initialize Nim's garbage collector and to run the top level statements of your program. @@ -331,14 +333,14 @@ Normal languages for iOS development are Swift and Objective C. Both of these use LLVM and can be compiled into object files linked together with C, C++ or Objective C code produced by Nim. -Use ``nim c -c --os:ios --noMain:on`` to generate C files and include them in +Use `nim c -c --os:ios --noMain:on` to generate C files and include them in your XCode project. Then you can use XCode to compile, link, package and sign everything. -Because Nim is part of a library it can't have its own c style ``main()`` so you -would need to define `main` that calls ``autoreleasepool`` and -``UIApplicationMain`` to do it, or use a library like SDL2 or GLFM. After -the iOS setup is done, it's very important to call ``NimMain()`` to +Because Nim is part of a library it can't have its own c style `main()` so you +would need to define `main` that calls `autoreleasepool` and +`UIApplicationMain` to do it, or use a library like SDL2 or GLFM. After +the iOS setup is done, it's very important to call `NimMain()` to initialize Nim's garbage collector and to run the top-level statements of your program. @@ -356,8 +358,8 @@ Cross-compilation for Nintendo Switch ===================================== Simply add --os:nintendoswitch -to your usual ``nim c`` or ``nim cpp`` command and set the ``passC`` -and ``passL`` command line switches to something like: +to your usual `nim c` or `nim cpp` command and set the `passC` +and `passL` command line switches to something like: .. code-block:: console nim c ... --passC="-I$DEVKITPRO/libnx/include" ... @@ -378,8 +380,8 @@ For example, with the above-mentioned config:: nim c --os:nintendoswitch switchhomebrew.nim -This will generate a file called ``switchhomebrew.elf`` which can then be turned into -an nro file with the ``elf2nro`` tool in the DevkitPro release. Examples can be found at +This will generate a file called `switchhomebrew.elf` which can then be turned into +an nro file with the `elf2nro` tool in the DevkitPro release. Examples can be found at `the nim-libnx github repo `_. There are a few things that don't work because the DevkitPro libraries don't support them. @@ -399,62 +401,62 @@ DLL generation Nim supports the generation of DLLs. However, there must be only one instance of the GC per process/address space. This instance is contained in -``nimrtl.dll``. This means that every generated Nim DLL depends -on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command:: +`nimrtl.dll`. This means that every generated Nim DLL depends +on `nimrtl.dll`. To generate the "nimrtl.dll" file, use the command:: nim c -d:release lib/nimrtl.nim -To link against ``nimrtl.dll`` use the command:: +To link against `nimrtl.dll` use the command:: nim c -d:useNimRtl myprog.nim -**Note**: Currently the creation of ``nimrtl.dll`` with thread support has +**Note**: Currently the creation of `nimrtl.dll` with thread support has never been tested and is unlikely to work! Additional compilation switches =============================== -The standard library supports a growing number of ``useX`` conditional defines +The standard library supports a growing number of `useX` conditional defines affecting how some features are implemented. This section tries to give a complete list. ====================== ========================================================= Define Effect ====================== ========================================================= -``release`` Turns on the optimizer. +`release` Turns on the optimizer. More aggressive optimizations are possible, e.g.: - ``--passC:-ffast-math`` (but see issue #10305) -``danger`` Turns off all runtime checks and turns on the optimizer. -``useFork`` Makes ``osproc`` use ``fork`` instead of ``posix_spawn``. -``useNimRtl`` Compile and link against ``nimrtl.dll``. -``useMalloc`` Makes Nim use C's `malloc`:idx: instead of Nim's + `--passC:-ffast-math` (but see issue #10305) +`danger` Turns off all runtime checks and turns on the optimizer. +`useFork` Makes `osproc` use `fork` instead of `posix_spawn`. +`useNimRtl` Compile and link against `nimrtl.dll`. +`useMalloc` Makes Nim use C's `malloc`:idx: instead of Nim's own memory manager, albeit prefixing each allocation with its size to support clearing memory on reallocation. - This only works with ``gc:none`` and - with ``--newruntime``. -``useRealtimeGC`` Enables support of Nim's GC for *soft* realtime + This only works with `gc:none`, `gc:arc` and + `--gc:orc`. +`useRealtimeGC` Enables support of Nim's GC for *soft* realtime systems. See the documentation of the `gc `_ for further information. -``logGC`` Enable GC logging to stdout. -``nodejs`` The JS target is actually ``node.js``. -``ssl`` Enables OpenSSL support for the sockets module. -``memProfiler`` Enables memory profiling for the native GC. -``uClibc`` Use uClibc instead of libc. (Relevant for Unix-like OSes) -``checkAbi`` When using types from C headers, add checks that compare +`logGC` Enable GC logging to stdout. +`nodejs` The JS target is actually `node.js`. +`ssl` Enables OpenSSL support for the sockets module. +`memProfiler` Enables memory profiling for the native GC. +`uClibc` Use uClibc instead of libc. (Relevant for Unix-like OSes) +`checkAbi` When using types from C headers, add checks that compare what's in the Nim file with what's in the C header. This may become enabled by default in the future. -``tempDir`` This symbol takes a string as its value, like - ``--define:tempDir:/some/temp/path`` to override the - temporary directory returned by ``os.getTempDir()``. +`tempDir` This symbol takes a string as its value, like + `--define:tempDir:/some/temp/path` to override the + temporary directory returned by `os.getTempDir()`. The value **should** end with a directory separator character. (Relevant for the Android platform) -``useShPath`` This symbol takes a string as its value, like - ``--define:useShPath:/opt/sh/bin/sh`` to override the - path for the ``sh`` binary, in cases where it is not - located in the default location ``/bin/sh``. -``noSignalHandler`` Disable the crash handler from ``system.nim``. -``globalSymbols`` Load all ``{.dynlib.}`` libraries with the ``RTLD_GLOBAL`` +`useShPath` This symbol takes a string as its value, like + `--define:useShPath:/opt/sh/bin/sh` to override the + path for the `sh` binary, in cases where it is not + located in the default location `/bin/sh`. +`noSignalHandler` Disable the crash handler from `system.nim`. +`globalSymbols` Load all `{.dynlib.}` libraries with the `RTLD_GLOBAL` flag on Posix systems to resolve symbols in subsequently loaded libraries. ====================== ========================================================= @@ -471,20 +473,20 @@ generator and are subject to change. LineDir option -------------- -The ``lineDir`` option can be turned on or off. If turned on the -generated C code contains ``#line`` directives. This may be helpful for +The `lineDir` option can be turned on or off. If turned on the +generated C code contains `#line` directives. This may be helpful for debugging with GDB. StackTrace option ----------------- -If the ``stackTrace`` option is turned on, the generated C contains code to +If the `stackTrace` option is turned on, the generated C contains code to ensure that proper stack traces are given if the program crashes or some uncaught exception is raised. LineTrace option ---------------- -The ``lineTrace`` option implies the ``stackTrace`` option. If turned on, +The `lineTrace` option implies the `stackTrace` option. If turned on, the generated C contains code to ensure that proper stack traces with line number information are given if the program crashes or an uncaught exception is raised. @@ -493,10 +495,10 @@ is raised. DynlibOverride ============== -By default Nim's ``dynlib`` pragma causes the compiler to generate -``GetProcAddress`` (or their Unix counterparts) -calls to bind to a DLL. With the ``dynlibOverride`` command line switch this -can be prevented and then via ``--passL`` the static library can be linked +By default Nim's `dynlib` pragma causes the compiler to generate +`GetProcAddress` (or their Unix counterparts) +calls to bind to a DLL. With the `dynlibOverride` command line switch this +can be prevented and then via `--passL` the static library can be linked against. For instance, to link statically against Lua this command might work on Linux:: @@ -506,8 +508,8 @@ on Linux:: Backend language options ======================== -The typical compiler usage involves using the ``compile`` or ``c`` command to -transform a ``.nim`` file into one or more ``.c`` files which are then +The typical compiler usage involves using the `compile` or `c` command to +transform a `.nim` file into one or more `.c` files which are then compiled with the platform's C compiler into a static binary. However, there are other commands to compile to C++, Objective-C, or JavaScript. More details can be read in the `Nim Backend Integration document `_. @@ -517,7 +519,7 @@ Nim documentation tools ======================= Nim provides the `doc`:idx: command to generate HTML -documentation from ``.nim`` source files. Only exported symbols will appear in +documentation from `.nim` source files. Only exported symbols will appear in the output. For more details `see the docgen documentation `_. Nim idetools integration @@ -533,15 +535,15 @@ for further information. The Nim compiler supports an interactive mode. This is also known as a `REPL`:idx: (*read eval print loop*). If Nim has been built with the - ``-d:nimUseLinenoise`` switch, it uses the GNU readline library for terminal + `-d:nimUseLinenoise` switch, it uses the GNU readline library for terminal input management. To start Nim in interactive mode use the command - ``nim secret``. To quit use the ``quit()`` command. To determine whether an input + `nim secret`. To quit use the `quit()` command. To determine whether an input line is an incomplete statement to be continued these rules are used: 1. The line ends with ``[-+*/\\<>!\?\|%&$@~,;:=#^]\s*$`` (operator symbol followed by optional whitespace). 2. The line starts with a space (indentation). 3. The line is within a triple quoted string literal. However, the detection - does not work if the line contains more than one ``"""``. + does not work if the line contains more than one `"""`. Nim for embedded systems @@ -552,22 +554,22 @@ modern PC hardware and operating systems with ample memory, it is very well possible to run Nim code and a good part of the Nim standard libraries on small embedded microprocessors with only a few kilobytes of memory. -A good start is to use the ``any`` operating target together with the -``malloc`` memory allocator and the ``arc`` garbage collector. For example: +A good start is to use the `any` operating target together with the +`malloc` memory allocator and the `arc` garbage collector. For example: -``nim c --os:any --gc:arc -d:useMalloc [...] x.nim`` +`nim c --os:any --gc:arc -d:useMalloc [...] x.nim` -- ``--gc:arc`` will enable the reference counting memory management instead +- `--gc:arc` will enable the reference counting memory management instead of the default garbage collector. This enables Nim to use heap memory which is required for strings and seqs, for example. -- The ``--os:any`` target makes sure Nim does not depend on any specific +- The `--os:any` target makes sure Nim does not depend on any specific operating system primitives. Your platform should support only some basic - ANSI C library ``stdlib`` and ``stdio`` functions which should be available + ANSI C library `stdlib` and `stdio` functions which should be available on almost any platform. -- The ``-d:useMalloc`` option configures Nim to use only the standard C memory - manage primitives ``malloc()``, ``free()``, ``realloc()``. +- The `-d:useMalloc` option configures Nim to use only the standard C memory + manage primitives `malloc()`, `free()`, `realloc()`. If your platform does not provide these functions it should be trivial to provide an implementation for them and link these to your program. @@ -577,10 +579,10 @@ additional flags to both the Nim compiler and the C compiler and/or linker to optimize the build for size. For example, the following flags can be used when targeting a gcc compiler: -``--opt:size --passC:-flto --passL:-flto`` +`--opt:size --passC:-flto --passL:-flto` -The ``--opt:size`` flag instructs Nim to optimize code generation for small -size (with the help of the C compiler), the ``flto`` flags enable link-time +The `--opt:size` flag instructs Nim to optimize code generation for small +size (with the help of the C compiler), the `flto` flags enable link-time optimization in the compiler and linker. Check the `Cross-compilation` section for instructions on how to compile the @@ -600,7 +602,7 @@ The Nim programming language has no concept of Posix's signal handling mechanisms. However, the standard library offers some rudimentary support for signal handling, in particular, segmentation faults are turned into fatal errors that produce a stack trace. This can be disabled with the -``-d:noSignalHandler`` switch. +`-d:noSignalHandler` switch. Optimizing for Nim @@ -642,7 +644,7 @@ However, it is not efficient to do: .. code-block:: Nim var s = varA # assignment has to copy the whole string into a new buffer! -For ``let`` symbols a copy is not always necessary: +For `let` symbols a copy is not always necessary: .. code-block:: Nim let s = varA # may only copy a pointer if it safe to do so @@ -656,7 +658,7 @@ objects as `shallow`:idx:\: shallow(s) # mark 's' as a shallow string var x = s # now might not copy the string! -Usage of ``shallow`` is always safe once you know the string won't be modified +Usage of `shallow` is always safe once you know the string won't be modified anymore, similar to Ruby's `freeze`:idx:. diff --git a/doc/nimdoc.css b/doc/nimdoc.css index 2d9533cebb..db9a7ce979 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -14,6 +14,9 @@ Modified by Boyd Greenfield and narimiran --primary-background: #fff; --secondary-background: ghostwhite; --third-background: #e8e8e8; + --info-background: #50c050; + --warning-background: #c0a000; + --error-background: #e04040; --border: #dde; --text: #222; --anchor: #07b; @@ -39,6 +42,9 @@ Modified by Boyd Greenfield and narimiran --primary-background: #171921; --secondary-background: #1e202a; --third-background: #2b2e3b; + --info-background: #008000; + --warning-background: #807000; + --error-background: #c03000; --border: #0e1014; --text: #fff; --anchor: #8be9fd; @@ -378,6 +384,7 @@ h2 { margin-top: 2em; } h2.subtitle { + margin-top: 0em; text-align: center; } h3 { @@ -491,6 +498,19 @@ hr { 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; +} + blockquote { font-size: 0.9em; font-style: italic; @@ -561,6 +581,7 @@ table.line-nums-table { .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; @@ -609,6 +630,34 @@ table.borderless td, table.borderless th { 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; } @@ -872,6 +921,7 @@ dt pre > span.Operator ~ span.Identifier, dt pre > span.Other ~ span.Identifier 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; } diff --git a/doc/nimfix.rst b/doc/nimfix.rst index 62064fe69b..d105346da2 100644 --- a/doc/nimfix.rst +++ b/doc/nimfix.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ===================== Nimfix User Guide ===================== @@ -14,12 +16,12 @@ It performs 3 different actions: 1. It makes your code case consistent. 2. It renames every symbol that has a deprecation rule. So if a module has a - rule ``{.deprecated: [TFoo: Foo].}`` then ``TFoo`` is replaced by ``Foo``. + rule `{.deprecated: [TFoo: Foo].}` then `TFoo` is replaced by `Foo`. 3. It can also check that your identifiers adhere to the official style guide - and optionally modify them to do so (via ``--styleCheck:auto``). + and optionally modify them to do so (via `--styleCheck:auto`). -Note that ``nimfix`` defaults to **overwrite** your code unless you -use ``--overwriteFiles:off``! But hey, if you do not use a version control +Note that `nimfix` defaults to **overwrite** your code unless you +use `--overwriteFiles:off`! But hey, if you do not use a version control system by this day and age, your project is already in big trouble. diff --git a/doc/nimgrep.rst b/doc/nimgrep.rst index 791ead1624..5b0fe0dbb7 100644 --- a/doc/nimgrep.rst +++ b/doc/nimgrep.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ========================= nimgrep User's manual ========================= @@ -22,7 +24,7 @@ Compile nimgrep with the command:: nim c -d:release tools/nimgrep.nim -And copy the executable somewhere in your ``$PATH``. +And copy the executable somewhere in your `$PATH`. Command line switches diff --git a/doc/niminst.rst b/doc/niminst.rst index adb5e6f1fb..3ccb47cc85 100644 --- a/doc/niminst.rst +++ b/doc/niminst.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ========================= niminst User's manual ========================= @@ -31,8 +33,8 @@ configuration file. Here's an example of how the syntax looks like: :literal: The value of a key-value pair can reference user-defined variables via -the ``$variable`` notation: They can be defined in the command line with the -``--var:name=value`` switch. This is useful to not hard-coding the +the `$variable` notation: They can be defined in the command line with the +`--var:name=value` switch. This is useful to not hard-coding the program's version number into the configuration file, for instance. It follows a description of each possible section and how it affects the @@ -47,28 +49,28 @@ contain the following key-value pairs: ==================== ======================================================= Key description ==================== ======================================================= -``Name`` the project's name; this needs to be a single word -``DisplayName`` the project's long name; this can contain spaces. If - not specified, this is the same as ``Name``. -``Version`` the project's version -``OS`` the OSes to generate C code for; for example: - ``"windows;linux;macosx"`` -``CPU`` the CPUs to generate C code for; for example: - ``"i386;amd64;powerpc"`` -``Authors`` the project's authors -``Description`` the project's description -``App`` the application's type: "Console" or "GUI". If +`Name` the project's name; this needs to be a single word +`DisplayName` the project's long name; this can contain spaces. If + not specified, this is the same as `Name`. +`Version` the project's version +`OS` the OSes to generate C code for; for example: + `"windows;linux;macosx"` +`CPU` the CPUs to generate C code for; for example: + `"i386;amd64;powerpc"` +`Authors` the project's authors +`Description` the project's description +`App` the application's type: "Console" or "GUI". If "Console", niminst generates a special batch file for Windows to open up the command-line shell. -``License`` the filename of the application's license +`License` the filename of the application's license ==================== ======================================================= -``files`` key +`files` key ------------- -Many sections support the ``files`` key. Listed filenames -can be separated by semicolon or the ``files`` key can be repeated. Wildcards +Many sections support the `files` key. Listed filenames +can be separated by semicolon or the `files` key can be repeated. Wildcards in filenames are supported. If it is a directory name, all files in the directory are used:: @@ -80,63 +82,63 @@ directory are used:: Config section -------------- -The ``config`` section currently only supports the ``files`` key. Listed files +The `config` section currently only supports the `files` key. Listed files will be installed into the OS's configuration directory. Documentation section --------------------- -The ``documentation`` section supports the ``files`` key. +The `documentation` section supports the `files` key. Listed files will be installed into the OS's native documentation directory -(which might be ``$appdir/doc``). +(which might be `$appdir/doc`). -There is a ``start`` key which determines whether the Windows installer -generates a link to e.g. the ``index.html`` of your documentation. +There is a `start` key which determines whether the Windows installer +generates a link to e.g. the `index.html` of your documentation. Other section ------------- -The ``other`` section currently only supports the ``files`` key. +The `other` section currently only supports the `files` key. Listed files will be installed into the application installation directory -(``$appdir``). +(`$appdir`). Lib section ----------- -The ``lib`` section currently only supports the ``files`` key. +The `lib` section currently only supports the `files` key. Listed files will be installed into the OS's native library directory -(which might be ``$appdir/lib``). +(which might be `$appdir/lib`). Windows section --------------- -The ``windows`` section supports the ``files`` key for Windows-specific files. +The `windows` section supports the `files` key for Windows-specific files. Listed files will be installed into the application installation directory -(``$appdir``). +(`$appdir`). Other possible options are: ==================== ======================================================= Key description ==================== ======================================================= -``BinPath`` paths to add to the Windows ``%PATH%`` environment +`BinPath` paths to add to the Windows `%PATH%` environment variable. Example: ``BinPath: r"bin;dist\mingw\bin"`` -``InnoSetup`` boolean flag whether an Inno Setup installer should be - generated for Windows. Example: ``InnoSetup: "Yes"`` +`InnoSetup` boolean flag whether an Inno Setup installer should be + generated for Windows. Example: `InnoSetup: "Yes"` ==================== ======================================================= UnixBin section --------------- -The ``UnixBin`` section currently only supports the ``files`` key. +The `UnixBin` section currently only supports the `files` key. Listed files will be installed into the OS's native bin directory -(e.g. ``/usr/local/bin``). The exact location depends on the -installation path the user specifies when running the ``install.sh`` script. +(e.g. `/usr/local/bin`). The exact location depends on the +installation path the user specifies when running the `install.sh` script. Unix section @@ -147,11 +149,11 @@ Possible options are: ==================== ======================================================= Key description ==================== ======================================================= -``InstallScript`` boolean flag whether an installation shell script - should be generated. Example: ``InstallScript: "Yes"`` -``UninstallScript`` boolean flag whether a de-installation shell script +`InstallScript` boolean flag whether an installation shell script + should be generated. Example: `InstallScript: "Yes"` +`UninstallScript` boolean flag whether a de-installation shell script should be generated. - Example: ``UninstallScript: "Yes"`` + Example: `UninstallScript: "Yes"` ==================== ======================================================= @@ -163,10 +165,10 @@ Possible options are: ==================== ======================================================= Key description ==================== ======================================================= -``path`` Path to Inno Setup. +`path` Path to Inno Setup. Example: ``path = r"c:\inno setup 5\iscc.exe"`` -``flags`` Flags to pass to Inno Setup. - Example: ``flags = "/Q"`` +`flags` Flags to pass to Inno Setup. + Example: `flags = "/Q"` ==================== ======================================================= @@ -178,9 +180,9 @@ Possible options are: ==================== ======================================================= Key description ==================== ======================================================= -``path`` Path to the C compiler. -``flags`` Flags to pass to the C Compiler. - Example: ``flags = "-w"`` +`path` Path to the C compiler. +`flags` Flags to pass to the C Compiler. + Example: `flags = "-w"` ==================== ======================================================= diff --git a/doc/nims.rst b/doc/nims.rst index 03afa258a9..f81637d734 100644 --- a/doc/nims.rst +++ b/doc/nims.rst @@ -1,30 +1,32 @@ +.. default-role:: code + ================================ NimScript ================================ -Strictly speaking, ``NimScript`` is the subset of Nim that can be evaluated +Strictly speaking, `NimScript` is the subset of Nim that can be evaluated by Nim's builtin virtual machine (VM). This VM is used for Nim's compiletime function evaluation features. -The ``nim`` executable processes the ``.nims`` configuration files in +The `nim` executable processes the `.nims` configuration files in the following directories (in this order; later files overwrite previous settings): -1) If environment variable ``XDG_CONFIG_HOME`` is defined, - ``$XDG_CONFIG_HOME/nim/config.nims`` or - ``~/.config/nim/config.nims`` (POSIX) or - ``%APPDATA%/nim/config.nims`` (Windows). This file can be skipped - with the ``--skipUserCfg`` command line option. -2) ``$parentDir/config.nims`` where ``$parentDir`` stands for any +1) If environment variable `XDG_CONFIG_HOME` is defined, + `$XDG_CONFIG_HOME/nim/config.nims` or + `~/.config/nim/config.nims` (POSIX) or + `%APPDATA%/nim/config.nims` (Windows). This file can be skipped + with the `--skipUserCfg` command line option. +2) `$parentDir/config.nims` where `$parentDir` stands for any parent directory of the project file's path. These files can be - skipped with the ``--skipParentCfg`` command line option. -3) ``$projectDir/config.nims`` where ``$projectDir`` stands for the - project's path. This file can be skipped with the ``--skipProjCfg`` + skipped with the `--skipParentCfg` command line option. +3) `$projectDir/config.nims` where `$projectDir` stands for the + project's path. This file can be skipped with the `--skipProjCfg` command line option. 4) A project can also have a project specific configuration file named - ``$project.nims`` that resides in the same directory as - ``$project.nim``. This file can be skipped with the same - ``--skipProjCfg`` command line option. + `$project.nims` that resides in the same directory as + `$project.nim`. This file can be skipped with the same + `--skipProjCfg` command line option. For available procs and implementation details see `nimscript `_. @@ -36,13 +38,13 @@ NimScript is subject to some limitations caused by the implementation of the VM (virtual machine): * Nim's FFI (foreign function interface) is not available in NimScript. This - means that any stdlib module which relies on ``importc`` can not be used in + means that any stdlib module which relies on `importc` can not be used in the VM. -* ``ptr`` operations are are hard to emulate with the symbolic representation +* `ptr` operations are are hard to emulate with the symbolic representation the VM uses. They are available and tested extensively but there are bugs left. -* ``var T`` function arguments rely on ``ptr`` operations internally and might +* `var T` function arguments rely on `ptr` operations internally and might also be problematic in some cases. * More than one level of `ref` is generally not supported (for example, the type @@ -50,7 +52,7 @@ NimScript is subject to some limitations caused by the implementation of the VM * Multimethods are not available. -* ``random.randomize()`` requires an ``int64`` explicitly passed as argument, you *must* pass a Seed integer. +* `random.randomize()` requires an `int64` explicitly passed as argument, you *must* pass a Seed integer. Standard library modules @@ -109,11 +111,11 @@ See also: NimScript as a configuration file ================================= -A command-line switch ``--FOO`` is written as ``switch("FOO")`` in -NimScript. Similarly, command-line ``--FOO:VAL`` translates to -``switch("FOO", "VAL")``. +A command-line switch `--FOO` is written as `switch("FOO")` in +NimScript. Similarly, command-line `--FOO:VAL` translates to +`switch("FOO", "VAL")`. -Here are few examples of using the ``switch`` proc: +Here are few examples of using the `switch` proc: .. code-block:: nim # command-line: --opt:size @@ -123,7 +125,7 @@ Here are few examples of using the ``switch`` proc: # command-line: --forceBuild switch("forceBuild") -NimScripts also support ``--`` templates for convenience, which look +NimScripts also support `--` templates for convenience, which look like command-line switches written as-is in the NimScript file. So the above example can be rewritten as: @@ -133,17 +135,17 @@ above example can be rewritten as: --forceBuild **Note**: In general, the *define* switches can also be set in -NimScripts using ``switch`` or ``--``, as shown in above -examples. Only the ``release`` define (``-d:release``) cannot be set +NimScripts using `switch` or `--`, as shown in above +examples. Only the `release` define (`-d:release`) cannot be set in NimScripts. NimScript as a build tool ========================= -The ``task`` template that the ``system`` module defines allows a NimScript +The `task` template that the `system` module defines allows a NimScript file to be used as a build tool. The following example defines a -task ``build`` that is an alias for the ``c`` command: +task `build` that is an alias for the `c` command: .. code-block:: nim task build, "builds an example": @@ -155,11 +157,11 @@ In fact, as a convention the following tasks should be available: ========= =================================================== Task Description ========= =================================================== -``help`` List all the available NimScript tasks along with their docstrings. -``build`` Build the project with the required - backend (``c``, ``cpp`` or ``js``). -``tests`` Runs the tests belonging to the project. -``bench`` Runs benchmarks belonging to the project. +`help` List all the available NimScript tasks along with their docstrings. +`build` Build the project with the required + backend (`c`, `cpp` or `js`). +`tests` Runs the tests belonging to the project. +`bench` Runs benchmarks belonging to the project. ========= =================================================== @@ -178,7 +180,7 @@ Standalone NimScript ==================== NimScript can also be used directly as a portable replacement for Bash and -Batch files. Use ``nim myscript.nims`` to run ``myscript.nims``. For example, +Batch files. Use `nim myscript.nims` to run `myscript.nims`. For example, installation of Nimble could be accomplished with this simple script: .. code-block:: nim @@ -196,8 +198,8 @@ installation of Nimble could be accomplished with this simple script: mvFile "nimble" & $id & "/src/nimble".toExe, "bin/nimble".toExe -On Unix, you can also use the shebang ``#!/usr/bin/env nim``, as long as your filename -ends with ``.nims``: +On Unix, you can also use the shebang `#!/usr/bin/env nim`, as long as your filename +ends with `.nims`: .. code-block:: nim @@ -206,7 +208,7 @@ ends with ``.nims``: echo "hello world" -Use ``#!/usr/bin/env -S nim --hints:off`` to disable hints. +Use `#!/usr/bin/env -S nim --hints:off` to disable hints. Benefits @@ -228,7 +230,7 @@ See the following (incomplete) example: .. code-block:: nim - import distros + import std/distros # Architectures. if defined(amd64): @@ -268,7 +270,7 @@ Powerful Metaprogramming NimScript can use Nim's templates, macros, types, concepts, effect tracking system, and more, you can create modules that work on compiled Nim and also on interpreted NimScript. -``func`` will still check for side effects, ``debugEcho`` also works as expected, +`func` will still check for side effects, `debugEcho` also works as expected, making it ideal for functional scripting metaprogramming. This is an example of a third party module that uses macros and templates to @@ -286,7 +288,7 @@ translations.cfg [cat] ES = gato - PT = minino + IT = gatto RU = kot FR = chat @@ -315,7 +317,7 @@ See the following NimScript: echo CompileDate -``likely()``, ``unlikely()``, ``static:`` and ``{.compiletime.}`` +`likely()`, `unlikely()`, `static:` and `{.compiletime.}` will produce no code at all when run on NimScript, but still no error nor warning is produced and the code just works. diff --git a/doc/nimsuggest.rst b/doc/nimsuggest.rst index a5d0d65b9a..509f72e8a7 100644 --- a/doc/nimsuggest.rst +++ b/doc/nimsuggest.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ================================ Nim IDE Integration Guide ================================ @@ -11,8 +13,8 @@ Nim differs from many other compilers in that it is really fast, and being so fast makes it suited to provide external queries for text editors about the source code being written. Through the -``nimsuggest`` tool, any IDE -can query a ``.nim`` source file and obtain useful information like +`nimsuggest` tool, any IDE +can query a `.nim` source file and obtain useful information like definition of symbols or suggestions for completion. This document will guide you through the available options. If you @@ -33,45 +35,50 @@ Nimsuggest is part of Nim's core. Build it via:: Nimsuggest invocation ===================== -Run it via ``nimsuggest --stdin --debug myproject.nim``. Nimsuggest is a -server that takes queries that are related to ``myproject``. There is some -support so that you can throw random ``.nim`` files which are not part -of ``myproject`` at Nimsuggest too, but usually the query refer to modules/files -that are part of ``myproject``. +Run it via `nimsuggest --stdin --debug myproject.nim`. Nimsuggest is a +server that takes queries that are related to `myproject`. There is some +support so that you can throw random `.nim` files which are not part +of `myproject` at Nimsuggest too, but usually the query refer to modules/files +that are part of `myproject`. -``--stdin`` means that Nimsuggest reads the query from ``stdin``. This is great +`--stdin` means that Nimsuggest reads the query from `stdin`. This is great for testing things out and playing with it but for an editor communication via sockets is more reasonable so that is the default. It listens to port 6000 by default. +Nimsuggest is basically a frontend for the nim compiler so `--path` flags and +`config files `_ +can be used to specify additional dependencies like +`nimsuggest --stdin --debug --path:"dependencies" myproject.nim`. + Specifying the location of the query ------------------------------------ Nimsuggest then waits for queries to process. A query consists of a -cryptic 3 letter "command" ``def`` or ``con`` or ``sug`` or ``use`` followed by +cryptic 3 letter "command" `def` or `con` or `sug` or `use` followed by a location. A query location consists of: -``file.nim`` +`file.nim` This is the name of the module or include file the query refers to. -``dirtyfile.nim`` +`dirtyfile.nim` This is optional. - The ``file`` parameter is enough for static analysis, but IDEs + The `file` parameter is enough for static analysis, but IDEs tend to have *unsaved buffers* where the user may still be in the middle of typing a line. In such situations the IDE can save the current contents to a temporary file and then use the - ``dirtyfile.nim`` option to tell Nimsuggest that ``foobar.nim`` should - be taken from ``temporary/foobar.nim``. + `dirtyfile.nim` option to tell Nimsuggest that `foobar.nim` should + be taken from `temporary/foobar.nim`. -``line`` +`line` An integer with the line you are going to query. For the compiler lines start at **1**. -``col`` +`col` An integer with the column you are going to query. For the compiler columns start at **0**. @@ -79,7 +86,7 @@ a location. A query location consists of: Definitions ----------- -The ``def`` Nimsuggest command performs a query about the definition +The `def` Nimsuggest command performs a query about the definition of a specific symbol. If available, Nimsuggest will answer with the type, source file, line/column information and other accessory data if available like a docstring. With this information an IDE can @@ -100,7 +107,7 @@ can't find any valid symbol matching the position of the query. Suggestions ----------- -The ``sug`` Nimsuggest command performs a query about possible +The `sug` Nimsuggest command performs a query about possible completion symbols at some point in the file. The typical usage scenario for this option is to call it after the @@ -113,7 +120,7 @@ Nimsuggest will try to return the suggestions sorted first by scope Invocation context ------------------ -The ``con`` Nimsuggest command is very similar to the suggestions +The `con` Nimsuggest command is very similar to the suggestions command, but instead of being used after the user has typed a dot character, this one is meant to be used after the user has typed an opening brace to start typing parameters. @@ -122,7 +129,7 @@ an opening brace to start typing parameters. Symbol usages ------------- -The ``use`` Nimsuggest command lists all usages of the symbol at +The `use` Nimsuggest command lists all usages of the symbol at a position. IDEs can use this to find all the places in the file where the symbol is used and offer the user to rename it in all places at the same time. @@ -140,15 +147,15 @@ Nimsuggest output is always returned on single lines separated by tab characters (``\t``). The values of each column are: 1. Three characters indicating the type of returned answer (e.g. - ``def`` for definition, ``sug`` for suggestion, etc). -2. Type of the symbol. This can be ``skProc``, ``skLet``, and just - about any of the enums defined in the module ``compiler/ast.nim``. + `def` for definition, `sug` for suggestion, etc). +2. Type of the symbol. This can be `skProc`, `skLet`, and just + about any of the enums defined in the module `compiler/ast.nim`. 3. Fully qualified path of the symbol. If you are querying a symbol - defined in the ``proj.nim`` file, this would have the form - ``proj.symbolName``. + defined in the `proj.nim` file, this would have the form + `proj.symbolName`. 4. Type/signature. For variables and enums this will contain the type of the symbol, for procs, methods and templates this will - contain the full unique signature (e.g. ``proc (File)``). + contain the full unique signature (e.g. `proc (File)`). 5. Full path to the file containing the symbol. 6. Line where the symbol is located in the file. Lines start to count at **1**. diff --git a/doc/prelude.rst b/doc/prelude.rst deleted file mode 100644 index 47fa70b70e..0000000000 --- a/doc/prelude.rst +++ /dev/null @@ -1,29 +0,0 @@ -Prelude -======= - -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 - - -Examples -======== - -Get the basic most common imports ready to start coding using ``prelude``: - -.. code-block:: nim - include prelude - - echo now() - echo getCurrentDir() - echo "Hello $1".format("World") - - -See also: -- `Sugar `_ diff --git a/doc/spawn.txt b/doc/spawn.txt index ab667ff48d..c437e8aa32 100644 --- a/doc/spawn.txt +++ b/doc/spawn.txt @@ -29,7 +29,7 @@ the passed expression on the thread pool and returns a `data flow variable`:idx: variables at the same time: .. code-block:: nim - import threadpool, ... + import std/threadpool, ... # wait until 2 out of 3 servers received the update: proc main = @@ -56,7 +56,7 @@ Example: .. code-block:: nim # Compute PI in an inefficient way - import strutils, math, threadpool + import std/[strutils, math, threadpool] proc term(k: float): float = 4 * math.pow(-1, k) / (2*k + 1) diff --git a/doc/testament.rst b/doc/testament.rst index 253afb33df..04c966ffe1 100644 --- a/doc/testament.rst +++ b/doc/testament.rst @@ -1,3 +1,5 @@ +.. default-role:: code + Testament is an advanced automatic unittests runner for Nim tests, is used for the development of Nim itself, offers process isolation for your tests, it can generate statistics about test cases, supports multiple targets (C, C++, ObjectiveC, JavaScript, etc), @@ -9,29 +11,29 @@ so can be useful to run your tests, even the most complex ones. Test files location =================== -By default Testament looks for test files on ``"./tests/*.nim"``. -You can overwrite this pattern glob using ``pattern ``. +By default Testament looks for test files on `"./tests/*.nim"`. +You can overwrite this pattern glob using `pattern `. The default working directory path can be changed using -``--directory:"folder/subfolder/"``. +`--directory:"folder/subfolder/"`. -Testament uses the ``nim`` compiler on ``PATH``. -You can change that using ``--nim:"folder/subfolder/nim"``. -Running JavaScript tests with ``--targets:"js"`` requires a working NodeJS on -``PATH``. +Testament uses the `nim` compiler on `PATH`. +You can change that using `--nim:"folder/subfolder/nim"`. +Running JavaScript tests with `--targets:"js"` requires a working NodeJS on +`PATH`. Options ======= -* ``--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: 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. -* ``--skipFrom:file`` Read tests to skip from ``file`` - one test per line, # comments ignored +* `--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: 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. +* `--skipFrom:file` Read tests to skip from `file` - one test per line, # comments ignored Running a single test @@ -68,7 +70,7 @@ To search for tests deeper in a directory, use HTML Reports ============ -Generate HTML Reports ``testresults.html`` from unittests, +Generate HTML Reports `testresults.html` from unittests, you have to run at least 1 test *before* generating a report: .. code:: @@ -141,7 +143,7 @@ Example "template" **to edit** and write a Testament unittest: # Command the test should use to run. If left out or an empty string is # provided, the command is taken to be: - # "nim $target --hints:on -d:testing --nimblePath:tests/deps $options $file" + # "nim $target --hints:on -d:testing --nimblePath:build/deps/pkgs $options $file" # You can use the $target, $options, and $file placeholders in your own # command, too. cmd: "nim c -r $file" @@ -172,7 +174,7 @@ Example "template" **to edit** and write a Testament unittest: assert 42 == 42, "Assert error message" -* As you can see the "Spec" is just a ``discard """ """``. +* As you can see the "Spec" is just a `discard """ """`. * Spec has sane defaults, so you don't need to provide them all, any simple assert will work just fine. * `This is not the full spec of Testament, check the Testament Spec on GitHub, see parseSpec(). `_ * `Nim itself uses Testament, so there are plenty of test examples. `_ @@ -227,7 +229,7 @@ JavaScript tests: targets: "js" """ when defined(js): - import jsconsole + import std/jsconsole console.log("My Frontend Project") Compile-time tests: diff --git a/doc/tools.rst b/doc/tools.rst index f231cdc7d6..e0044e1ca9 100644 --- a/doc/tools.rst +++ b/doc/tools.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ======================== Tools available with Nim ======================== @@ -9,11 +11,11 @@ The standard distribution ships with the following tools: document explaining how it works. - | `Documentation generator `_ - | The builtin document generator ``nim doc`` generates HTML documentation - from ``.nim`` source files. + | The builtin document generator `nim doc` generates HTML documentation + from `.nim` source files. - | `Nimsuggest for IDE support `_ - | Through the ``nimsuggest`` tool, any IDE can query a ``.nim`` source file + | Through the `nimsuggest` tool, any IDE can query a `.nim` source file and obtain useful information like the definition of symbols or suggestions for completion. @@ -27,11 +29,11 @@ The standard distribution ships with the following tools: | Nim search and replace utility. - | nimpretty - | ``nimpretty`` is a Nim source code beautifier, + | `nimpretty` is a Nim source code beautifier, to format code according to the official style guide. - | `testament `_ - | ``testament`` is an advanced automatic *unittests runner* for Nim tests, + | `testament` is an advanced automatic *unittests runner* for Nim tests, is used for the development of Nim itself, offers process isolation for your tests, it can generate statistics about test cases, supports multiple targets (C, JS, etc), `simulated Dry-Runs `_, diff --git a/doc/tut1.rst b/doc/tut1.rst index 3977823303..d2d6f8fe7d 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ===================== Nim Tutorial (Part I) ===================== @@ -17,9 +19,14 @@ Introduction 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. +like variables, types, or statements. +If you would like to have a gentle introduction of those concepts, we recommend +`Nim Basics tutorial `_. +On the other hand, 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 `_. @@ -41,7 +48,7 @@ Save this code to the file "greetings.nim". Now compile and run it:: nim compile --run greetings.nim -With the ``--run`` `switch `_ Nim +With the `--run` `switch `_ Nim executes the file automatically after compilation. You can give your program command-line arguments by appending them after the filename:: @@ -56,7 +63,7 @@ To compile a release version use:: nim c -d:release greetings.nim By default, the Nim compiler generates a large number of runtime checks -aiming for your debugging pleasure. With ``-d:release`` some checks are +aiming for your debugging pleasure. With `-d:release` some checks are `turned off and optimizations are turned on `_. @@ -65,8 +72,8 @@ syntax: statements which are not indented are executed when the program starts. Indentation is Nim's way of grouping statements. Indentation is done with spaces only, tabulators are not allowed. -String literals are enclosed in double-quotes. The ``var`` statement declares -a new variable named ``name`` of type ``string`` with the value that is +String literals are enclosed in double-quotes. The `var` statement declares +a new variable named `name` of type `string` with the value that is returned by the `readLine `_ procedure. Since the compiler knows that `readLine `_ returns a string, you can leave out the type in the declaration (this is called `local type @@ -80,7 +87,7 @@ Note that this is basically the only form of type inference that exists in Nim: it is a good compromise between brevity and readability. The "hello world" program contains several identifiers that are already known -to the compiler: ``echo``, `readLine `_, etc. +to the compiler: `echo`, `readLine `_, etc. These built-ins are declared in the system_ module which is implicitly imported by any other module. @@ -97,7 +104,7 @@ String and character literals ----------------------------- String literals are enclosed in double-quotes; character literals in single -quotes. Special characters are escaped with ``\``: ``\n`` means newline, ``\t`` +quotes. Special characters are escaped with ``\\``: ``\n`` means newline, ``\t`` means tabulator, etc. There are also *raw* string literals: .. code-block:: Nim @@ -106,8 +113,8 @@ means tabulator, etc. There are also *raw* string literals: In raw literals, the backslash is not an escape character. The third and last way to write string literals is *long-string literals*. -They are written with three quotes: ``""" ... """``; they can span over -multiple lines and the ``\`` is not an escape character either. They are very +They are written with three quotes: `""" ... """`; they can span over +multiple lines and the ``\\`` is not an escape character either. They are very useful for embedding HTML code templates for example. @@ -115,7 +122,7 @@ Comments -------- Comments start anywhere outside a string or character literal with the -hash character ``#``. Documentation comments start with ``##``: +hash character `#`. Documentation comments start with `##`: .. code-block:: nim :test: "nim c $1" @@ -128,7 +135,7 @@ Documentation comments are tokens; they are only allowed at certain places in the input file as they belong to the syntax tree! This feature enables simpler documentation generators. -Multiline comments are started with ``#[`` and terminated with ``]#``. Multiline +Multiline comments are started with `#[` and terminated with `]#`. Multiline comments can also be nested. .. code-block:: nim @@ -147,10 +154,10 @@ Numbers ------- Numerical literals are written as in most other languages. As a special twist, -underscores are allowed for better readability: ``1_000_000`` (one million). +underscores are allowed for better readability: `1_000_000` (one million). A number that contains a dot (or 'e' or 'E') is a floating-point literal: -``1.0e9`` (one billion). Hexadecimal literals are prefixed with ``0x``, -binary literals with ``0b`` and octal literals with ``0o``. A leading zero +`1.0e9` (one billion). Hexadecimal literals are prefixed with `0x`, +binary literals with `0b` and octal literals with `0o`. A leading zero alone does not produce an octal. @@ -159,9 +166,9 @@ The var statement The var statement declares a new local or global variable: .. code-block:: - var x, y: int # declares x and y to have the type ``int`` + var x, y: int # declares x and y to have the type `int` -Indentation can be used after the ``var`` keyword to list a whole section of +Indentation can be used after the `var` keyword to list a whole section of variables: .. code-block:: @@ -182,7 +189,7 @@ to a storage location: var x = "abc" # introduces a new variable `x` and assigns a value to it x = "xyz" # assigns a new value to `x` -``=`` is the *assignment operator*. The assignment operator can be +`=` is the *assignment operator*. The assignment operator can be overloaded. You can declare multiple variables with a single assignment statement and all the variables will have the same value: @@ -214,7 +221,7 @@ constant declaration at compile time: :test: "nim c $1" const x = "abc" # the constant x contains the string "abc" -Indentation can be used after the ``const`` keyword to list a whole section of +Indentation can be used after the `const` keyword to list a whole section of constants: .. code-block:: @@ -228,7 +235,7 @@ constants: The let statement ================= -The ``let`` statement works like the ``var`` statement but the declared +The `let` statement works like the `var` statement but the declared symbols are *single assignment* variables: After the initialization their value cannot change: @@ -236,8 +243,8 @@ value cannot change: let x = "abc" # introduces a new variable `x` and binds a value to it x = "xyz" # Illegal: assignment to `x` -The difference between ``let`` and ``const`` is: ``let`` introduces a variable -that can not be re-assigned, ``const`` means "enforce compile time evaluation +The difference between `let` and `const` is: `let` introduces a variable +that can not be re-assigned, `const` means "enforce compile time evaluation and put it into a data section": .. code-block:: @@ -271,9 +278,9 @@ The if statement is one way to branch the control flow: else: echo "Hi, ", name, "!" -There can be zero or more ``elif`` parts, and the ``else`` part is optional. -The keyword ``elif`` is short for ``else if``, and is useful to avoid -excessive indentation. (The ``""`` is the empty string. It contains no +There can be zero or more `elif` parts, and the `else` part is optional. +The keyword `elif` is short for `else if`, and is useful to avoid +excessive indentation. (The `""` is the empty string. It contains no characters.) @@ -296,7 +303,7 @@ a multi-branch: else: echo "Hi, ", name, "!" -As it can be seen, for an ``of`` branch a comma-separated list of values is also +As it can be seen, for an `of` branch a comma-separated list of values is also allowed. The case statement can deal with integers, other ordinal types, and strings. @@ -305,7 +312,7 @@ For integers or other ordinal types value ranges are also possible: .. code-block:: nim # this statement will be explained later: - from strutils import parseInt + from std/strutils import parseInt echo "A number please: " let n = parseInt(readLine(stdin)) @@ -314,8 +321,8 @@ For integers or other ordinal types value ranges are also possible: of 3, 8: echo "The number is 3 or 8" However, the above code does not compile: the reason is that you have to cover -every value that ``n`` may contain, but the code only handles the values -``0..8``. Since it is not very practical to list every other possible integer +every value that `n` may contain, but the code only handles the values +`0..8`. Since it is not very practical to list every other possible integer (though it is possible thanks to the range notation), we fix this by telling the compiler that for every other value nothing should be done: @@ -329,7 +336,7 @@ the compiler that for every other value nothing should be done: The empty `discard statement <#procedures-discard-statement>`_ is a *do nothing* statement. The compiler knows that a case statement with an else part cannot fail and thus the error disappears. Note that it is impossible to cover -all possible string values: that is why string cases always need an ``else`` +all possible string values: that is why string cases always need an `else` branch. In general, the case statement is used for subrange types or enumerations where @@ -350,7 +357,7 @@ The while statement is a simple looping construct: while name == "": echo "Please tell me your name: " name = readLine(stdin) - # no ``var``, because we do not declare a new variable here + # no `var`, because we do not declare a new variable here The example uses a while loop to keep asking the users for their name, as long as the user types in nothing (only presses RETURN). @@ -359,7 +366,7 @@ as the user types in nothing (only presses RETURN). For statement ------------- -The ``for`` statement is a construct to loop over any element an *iterator* +The `for` statement is a construct to loop over any element an *iterator* provides. The example uses the built-in `countup `_ iterator: @@ -370,10 +377,10 @@ provides. The example uses the built-in `countup echo i # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines -The variable ``i`` is implicitly declared by the -``for`` loop and has the type ``int``, because that is what `countup -`_ returns. ``i`` runs through the values -1, 2, .., 10. Each value is ``echo``-ed. This code does the same: +The variable `i` is implicitly declared by the +`for` loop and has the type `int`, because that is what `countup +`_ returns. `i` runs through the values +1, 2, .., 10. Each value is `echo`-ed. This code does the same: .. code-block:: nim echo "Counting to 10: " @@ -398,7 +405,7 @@ Since counting up occurs so often in programs, Nim also has a `.. for i in 1 .. 10: ... -Zero-indexed counting has two shortcuts ``..<`` and ``.. ^1`` +Zero-indexed counting has two shortcuts `..<` and `.. ^1` (`backward index operator `_) to simplify counting to one less than the higher index: @@ -421,8 +428,8 @@ or ... Other useful iterators for collections (like arrays and sequences) are -* ``items`` and ``mitems``, which provides immutable and mutable elements respectively, and -* ``pairs`` and ``mpairs`` which provides the element and an index number (immutable and mutable respectively) +* `items` and `mitems`, which provides immutable and mutable elements respectively, and +* `pairs` and `mpairs` which provides the element and an index number (immutable and mutable respectively) .. code-block:: nim :test: "nim c $1" @@ -434,7 +441,7 @@ Other useful iterators for collections (like arrays and sequences) are Scopes and the block statement ------------------------------ Control flow statements have a feature not covered yet: they open a -new scope. This means that in the following example, ``x`` is not accessible +new scope. This means that in the following example, `x` is not accessible outside the loop: .. code-block:: nim @@ -445,7 +452,7 @@ outside the loop: echo x # does not work A while (for) statement introduces an implicit block. Identifiers -are only visible within the block they have been declared. The ``block`` +are only visible within the block they have been declared. The `block` statement can be used to open a new block explicitly: .. code-block:: nim @@ -455,13 +462,13 @@ statement can be used to open a new block explicitly: var x = "hi" echo x # does not work either -The block's *label* (``myblock`` in the example) is optional. +The block's *label* (`myblock` in the example) is optional. Break statement --------------- -A block can be left prematurely with a ``break`` statement. The break statement -can leave a ``while``, ``for``, or a ``block`` statement. It leaves the +A block can be left prematurely with a `break` statement. The break statement +can leave a `while`, `for`, or a `block` statement. It leaves the innermost construct, unless a label of a block is given: .. code-block:: nim @@ -485,7 +492,7 @@ innermost construct, unless a label of a block is given: Continue statement ------------------ -Like in many other programming languages, a ``continue`` statement starts +Like in many other programming languages, a `continue` statement starts the next iteration immediately: .. code-block:: nim @@ -513,17 +520,17 @@ Example: else: echo "unknown operating system" -The ``when`` statement is almost identical to the ``if`` statement, but with these +The `when` statement is almost identical to the `if` statement, but with these differences: * Each condition must be a constant expression since it is evaluated by the compiler. * The statements within a branch do not open a new scope. * The compiler checks the semantics and produces code *only* for the statements - that belong to the first condition that evaluates to ``true``. + that belong to the first condition that evaluates to `true`. -The ``when`` statement is useful for writing platform-specific code, similar to -the ``#ifdef`` construct in the C programming language. +The `when` statement is useful for writing platform-specific code, similar to +the `#ifdef` construct in the C programming language. Statements and indentation @@ -534,8 +541,8 @@ indentation rules. In Nim, there is a distinction between *simple statements* and *complex statements*. *Simple statements* cannot contain other statements: -Assignment, procedure calls, or the ``return`` statement are all simple -statements. *Complex statements* like ``if``, ``when``, ``for``, ``while`` can +Assignment, procedure calls, or the `return` statement are all simple +statements. *Complex statements* like `if`, `when`, `for`, `while` can contain other statements. To avoid ambiguities, complex statements must always be indented, but single simple statements do not: @@ -570,7 +577,7 @@ contain indentation at certain places for better readability: As a rule of thumb, indentation within expressions is allowed after operators, an open parenthesis and after commas. -With parenthesis and semicolons ``(;)`` you can use statements where only +With parenthesis and semicolons `(;)` you can use statements where only an expression is allowed: .. code-block:: nim @@ -585,7 +592,7 @@ Procedures To define new commands like `echo `_ and `readLine `_ in the examples, the concept of a `procedure` is needed. (Some languages call them *methods* or *functions*.) -In Nim new procedures are defined with the ``proc`` keyword: +In Nim new procedures are defined with the `proc` keyword: .. code-block:: nim :test: "nim c $1" @@ -602,26 +609,26 @@ In Nim new procedures are defined with the ``proc`` keyword: else: echo "I think you know what the problem is just as well as I do." -This example shows a procedure named ``yes`` that asks the user a ``question`` +This example shows a procedure named `yes` that asks the user a `question` and returns true if they answered "yes" (or something similar) and returns -false if they answered "no" (or something similar). A ``return`` statement +false if they answered "no" (or something similar). A `return` statement leaves the procedure (and therefore the while loop) immediately. The -``(question: string): bool`` syntax describes that the procedure expects a -parameter named ``question`` of type ``string`` and returns a value of type -``bool``. The ``bool`` type is built-in: the only valid values for ``bool`` are -``true`` and ``false``. -The conditions in if or while statements must be of type ``bool``. +`(question: string): bool` syntax describes that the procedure expects a +parameter named `question` of type `string` and returns a value of type +`bool`. The `bool` type is built-in: the only valid values for `bool` are +`true` and `false`. +The conditions in if or while statements must be of type `bool`. -Some terminology: in the example ``question`` is called a (formal) *parameter*, -``"Should I..."`` is called an *argument* that is passed to this parameter. +Some terminology: in the example `question` is called a (formal) *parameter*, +`"Should I..."` is called an *argument* that is passed to this parameter. Result variable --------------- -A procedure that returns a value has an implicit ``result`` variable declared -that represents the return value. A ``return`` statement with no expression is -shorthand for ``return result``. The ``result`` value is always returned -automatically at the end of a procedure if there is no ``return`` statement at +A procedure that returns a value has an implicit `result` variable declared +that represents the return value. A `return` statement with no expression is +shorthand for `return result`. The `result` value is always returned +automatically at the end of a procedure if there is no `return` statement at the exit. .. code-block:: nim @@ -636,15 +643,15 @@ the exit. echo sumTillNegative(3, 4, 5) # echos 12 echo sumTillNegative(3, 4 , -1 , 6) # echos 7 -The ``result`` variable is already implicitly declared at the start of the +The `result` variable is already implicitly declared at the start of the function, so declaring it again with 'var result', for example, would shadow it with a normal variable of the same name. The result variable is also already initialized with the type's default value. Note that referential data types will -be ``nil`` at the start of the procedure, and thus may require manual +be `nil` at the start of the procedure, and thus may require manual initialization. -A procedure that does not have any ``return`` statement and does not use the -special ``result`` variable returns the value of its last expression. For example, +A procedure that does not have any `return` statement and does not use the +special `result` variable returns the value of its last expression. For example, this procedure .. code-block:: nim @@ -659,7 +666,7 @@ Parameters Parameters are immutable in the procedure body. By default, their value cannot be changed because this allows the compiler to implement parameter passing in the most efficient way. If a mutable variable is needed inside the procedure, it has -to be declared with ``var`` in the procedure body. Shadowing the parameter name +to be declared with `var` in the procedure body. Shadowing the parameter name is possible, and actually an idiom: .. code-block:: nim @@ -670,7 +677,7 @@ is possible, and actually an idiom: echo s[i] If the procedure needs to modify the argument for the -caller, a ``var`` parameter can be used: +caller, a `var` parameter can be used: .. code-block:: nim :test: "nim c $1" @@ -684,7 +691,7 @@ caller, a ``var`` parameter can be used: echo x echo y -In the example, ``res`` and ``remainder`` are `var parameters`. +In the example, `res` and `remainder` are `var parameters`. Var parameters can be modified by the procedure and the changes are visible to the caller. Note that the above example would better make use of a tuple as a return value instead of using var parameters. @@ -693,7 +700,7 @@ a tuple as a return value instead of using var parameters. Discard statement ----------------- To call a procedure that returns a value just for its side effects and ignoring -its return value, a ``discard`` statement **must** be used. Nim does not +its return value, a `discard` statement **must** be used. Nim does not allow silently throwing away a return value: .. code-block:: nim @@ -701,7 +708,7 @@ allow silently throwing away a return value: The return value can be ignored implicitly if the called proc/iterator has -been declared with the ``discardable`` pragma: +been declared with the `discardable` pragma: .. code-block:: nim :test: "nim c $1" @@ -727,7 +734,7 @@ that it is clear which argument belongs to which parameter: var w = createWindow(show = true, title = "My Application", x = 0, y = 0, height = 600, width = 800) -Now that we use named arguments to call ``createWindow`` the argument order +Now that we use named arguments to call `createWindow` the argument order does not matter anymore. Mixing named arguments with ordered arguments is also possible, but not very readable: @@ -740,7 +747,7 @@ The compiler checks that each parameter receives exactly one argument. Default values -------------- -To make the ``createWindow`` proc easier to use it should provide `default +To make the `createWindow` proc easier to use it should provide `default values`; these are values that are used as arguments if the caller does not specify them: @@ -752,11 +759,11 @@ specify them: var w = createWindow(title = "My Application", height = 600, width = 800) -Now the call to ``createWindow`` only needs to set the values that differ +Now the call to `createWindow` only needs to set the values that differ from the defaults. Note that type inference works for parameters with default values; there is -no need to write ``title: string = "unknown"``, for example. +no need to write `title: string = "unknown"`, for example. Overloaded procedures @@ -778,8 +785,8 @@ Nim provides the ability to overload procedures similar to C++: assert toString(13) == "positive" # calls the toString(x: int) proc assert toString(true) == "yep" # calls the toString(x: bool) proc -(Note that ``toString`` is usually the `$ `_ operator in -Nim.) The compiler chooses the most appropriate proc for the ``toString`` +(Note that `toString` is usually the `$ `_ operator in +Nim.) The compiler chooses the most appropriate proc for the `toString` calls. How this overloading resolution algorithm works exactly is not discussed here (it will be specified in the manual soon). However, it does not lead to nasty surprises and is based on a quite simple unification @@ -789,31 +796,31 @@ algorithm. Ambiguous calls are reported as errors. Operators --------- The Nim library makes heavy use of overloading - one reason for this is that -each operator like ``+`` is just an overloaded proc. The parser lets you -use operators in `infix notation` (``a + b``) or `prefix notation` (``+ a``). +each operator like `+` is just an overloaded proc. The parser lets you +use operators in `infix notation` (`a + b`) or `prefix notation` (`+ a`). An infix operator always receives two arguments, a prefix operator always one. (Postfix operators are not possible, because this would be ambiguous: does -``a @ @ b`` mean ``(a) @ (@b)`` or ``(a@) @ (b)``? It always means -``(a) @ (@b)``, because there are no postfix operators in Nim.) +`a @ @ b` mean `(a) @ (@b)` or `(a@) @ (b)`? It always means +`(a) @ (@b)`, because there are no postfix operators in Nim.) -Apart from a few built-in keyword operators such as ``and``, ``or``, ``not``, +Apart from a few built-in keyword operators such as `and`, `or`, `not`, operators always consist of these characters: ``+ - * \ / < > = @ $ ~ & % ! ? ^ . |`` User-defined operators are allowed. Nothing stops you from defining your own -``@!?+~`` operator, but doing so may reduce readability. +`@!?+~` operator, but doing so may reduce readability. The operator's precedence is determined by its first character. The details can be found in the manual. -To define a new operator enclose the operator in backticks "``": +To define a new operator enclose the operator in backticks "`": .. code-block:: nim proc `$` (x: myDataType): string = ... # now the $ operator also works with myDataType, overloading resolution # ensures that $ works for built-in types just like before -The "``" notation can also be used to call an operator just like any other +The "`" notation can also be used to call an operator just like any other procedure: .. code-block:: nim @@ -846,10 +853,10 @@ However, this cannot be done for mutually recursive procedures: else: n == 0 or odd(n-1) -Here ``odd`` depends on ``even`` and vice versa. Thus ``even`` needs to be +Here `odd` depends on `even` and vice versa. Thus `even` needs to be introduced to the compiler before it is completely defined. The syntax for -such a forward declaration is simple: just omit the ``=`` and the -procedure's body. The ``assert`` just adds border conditions, and will be +such a forward declaration is simple: just omit the `=` and the +procedure's body. The `assert` just adds border conditions, and will be covered later in `Modules`_ section. Later versions of the language will weaken the requirements for forward @@ -881,9 +888,9 @@ supports this loop? Lets try: inc(res) However, this does not work. The problem is that the procedure should not -only ``return``, but return and **continue** after an iteration has +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`` +the only thing left to do is to replace the `proc` keyword by `iterator` and here it is - our first iterator: .. code-block:: nim @@ -898,19 +905,19 @@ Iterators look very similar to procedures, but there are several important differences: * Iterators can only be called from for loops. -* Iterators cannot contain a ``return`` statement (and procs cannot contain a - ``yield`` statement). -* Iterators have no implicit ``result`` variable. +* Iterators cannot contain a `return` statement (and procs cannot contain a + `yield` statement). +* Iterators have no implicit `result` variable. * Iterators do not support recursion. * Iterators cannot be forward declared, because the compiler must be able to inline an iterator. (This restriction will be gone in a future version of the compiler.) -However, you can also use a ``closure`` iterator to get a different set of +However, you can also use a `closure` iterator to get a different set of restrictions. See `first-class iterators `_ for details. Iterators can have the same name and parameters as a proc since essentially they have their own namespaces. Therefore it is common practice to wrap iterators in procs of the same name which accumulate the result of the -iterator and return it as a sequence, like ``split`` from the `strutils module +iterator and return it as a sequence, like `split` from the `strutils module `_. @@ -923,12 +930,12 @@ that are available for them in detail. Booleans -------- -Nim's boolean type is called ``bool`` and consists of the two -pre-defined values ``true`` and ``false``. Conditions in while, +Nim's boolean type is called `bool` and consists of the two +pre-defined values `true` and `false`. Conditions in while, if, elif, and when statements must be of type bool. -The operators ``not, and, or, xor, <, <=, >, >=, !=, ==`` are defined -for the bool type. The ``and`` and ``or`` operators perform short-circuit +The operators `not, and, or, xor, <, <=, >, >=, !=, ==` are defined +for the bool type. The `and` and `or` operators perform short-circuit evaluation. For example: .. code-block:: nim @@ -940,7 +947,7 @@ evaluation. For example: Characters ---------- -The `character type` is called ``char``. Its size is always one byte, so +The `character type` is called `char`. Its size is always one byte, so it cannot represent most UTF-8 characters, but it *can* represent one of the bytes that makes up a multi-byte UTF-8 character. The reason for this is efficiency: for the overwhelming majority of use-cases, @@ -948,57 +955,57 @@ the resulting programs will still handle UTF-8 properly as UTF-8 was especially designed for this. Character literals are enclosed in single quotes. -Chars can be compared with the ``==``, ``<``, ``<=``, ``>``, ``>=`` operators. -The ``$`` operator converts a ``char`` to a ``string``. Chars cannot be mixed -with integers; to get the ordinal value of a ``char`` use the ``ord`` proc. -Converting from an integer to a ``char`` is done with the ``chr`` proc. +Chars can be compared with the `==`, `<`, `<=`, `>`, `>=` operators. +The `$` operator converts a `char` to a `string`. Chars cannot be mixed +with integers; to get the ordinal value of a `char` use the `ord` proc. +Converting from an integer to a `char` is done with the `chr` proc. Strings ------- String variables are **mutable**, so appending to a string is possible, and quite efficient. Strings in Nim are both zero-terminated and have a -length field. A string's length can be retrieved with the builtin ``len`` +length field. A string's length can be retrieved with the builtin `len` procedure; the length never counts the terminating zero. Accessing the terminating zero is an error, it only exists so that a Nim string can be converted -to a ``cstring`` without doing a copy. +to a `cstring` without doing a copy. -The assignment operator for strings copies the string. You can use the ``&`` -operator to concatenate strings and ``add`` to append to a string. +The assignment operator for strings copies the string. You can use the `&` +operator to concatenate strings and `add` to append to a string. Strings are compared using their lexicographical order. All the comparison operators are supported. By convention, all strings are UTF-8 encoded, but this is not enforced. For example, when reading strings from binary files, they are merely -a sequence of bytes. The index operation ``s[i]`` means the i-th *char* of -``s``, not the i-th *unichar*. +a sequence of bytes. The index operation `s[i]` means the i-th *char* of +`s`, not the i-th *unichar*. -A string variable is initialized with the empty string ``""``. +A string variable is initialized with the empty string `""`. Integers -------- Nim has these integer types built-in: -``int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64``. +`int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64`. -The default integer type is ``int``. Integer literals can have a *type suffix* +The default integer type is `int`. Integer literals can have a *type suffix* to specify a non-default integer type: .. code-block:: nim :test: "nim c $1" let - x = 0 # x is of type ``int`` - y = 0'i8 # y is of type ``int8`` - z = 0'i64 # z is of type ``int64`` - u = 0'u # u is of type ``uint`` + x = 0 # x is of type `int` + y = 0'i8 # y is of type `int8` + z = 0'i64 # z is of type `int64` + u = 0'u # u is of type `uint` Most often integers are used for counting objects that reside in memory, so -``int`` has the same size as a pointer. +`int` has the same size as a pointer. -The common operators ``+ - * div mod < <= == != > >=`` are defined for -integers. The ``and or xor not`` operators are also defined for integers and -provide *bitwise* operations. Left bit shifting is done with the ``shl``, right -shifting with the ``shr`` operator. Bit shifting operators always treat their +The common operators `+ - * div mod < <= == != > >=` are defined for +integers. The `and or xor not` operators are also defined for integers and +provide *bitwise* operations. Left bit shifting is done with the `shl`, right +shifting with the `shr` operator. Bit shifting operators always treat their arguments as *unsigned*. For `arithmetic bit shifts`:idx: ordinary multiplication or division can be used. @@ -1013,10 +1020,10 @@ cannot be detected at compile time). Floats ------ -Nim has these floating-point types built-in: ``float float32 float64``. +Nim has these floating-point types built-in: `float float32 float64`. -The default float type is ``float``. In the current implementation, -``float`` is always 64-bits. +The default float type is `float`. In the current implementation, +`float` is always 64-bits. Float literals can have a *type suffix* to specify a non-default float type: @@ -1024,11 +1031,11 @@ type: .. code-block:: nim :test: "nim c $1" var - x = 0.0 # x is of type ``float`` - y = 0.0'f32 # y is of type ``float32`` - z = 0.0'f64 # z is of type ``float64`` + x = 0.0 # x is of type `float` + y = 0.0'f32 # y is of type `float32` + z = 0.0'f64 # z is of type `float64` -The common operators ``+ - * / < <= == != > >=`` are defined for +The common operators `+ - * / < <= == != > >=` are defined for floats and follow the IEEE-754 standard. Automatic type conversion in expressions with different kinds of floating-point types is performed: the smaller type is converted to the larger. Integer @@ -1056,13 +1063,13 @@ Internal type representation As mentioned earlier, the built-in `$ `_ (stringify) operator turns any basic type into a string, which you can then print to the console -using the ``echo`` proc. However, advanced types, and your own custom types, -won't work with the ``$`` operator until you define it for them. +using the `echo` proc. However, advanced types, and your own custom types, +won't work with the `$` operator until you define it for them. Sometimes you just want to debug the current value of a complex type without -having to write its ``$`` operator. You can use then the `repr +having to write its `$` operator. You can use then the `repr `_ proc which works with any type and even complex data graphs with cycles. The following example shows that even for basic types -there is a difference between the ``$`` and ``repr`` outputs: +there is a difference between the `$` and `repr` outputs: .. code-block:: nim :test: "nim c $1" @@ -1087,7 +1094,7 @@ there is a difference between the ``$`` and ``repr`` outputs: Advanced types ============== -In Nim new types can be defined within a ``type`` statement: +In Nim new types can be defined within a `type` statement: .. code-block:: nim :test: "nim c $1" @@ -1096,7 +1103,7 @@ In Nim new types can be defined within a ``type`` statement: biggestFloat = float64 # biggest float type that is available Enumeration and object types may only be defined within a -``type`` statement. +`type` statement. Enumerations @@ -1119,9 +1126,9 @@ at runtime by 0, the second by 1, and so on. For example: All the comparison operators can be used with enumeration types. An enumeration's symbol can be qualified to avoid ambiguities: -``Direction.south``. +`Direction.south`. -The ``$`` operator can convert any enumeration value to its name, and the ``ord`` +The `$` operator can convert any enumeration value to its name, and the `ord` proc can convert it to its underlying integer value. For better interfacing to other programming languages, the symbols of enum @@ -1131,7 +1138,7 @@ must be in ascending order. Ordinal types ------------- -Enumerations, integer types, ``char`` and ``bool`` (and +Enumerations, integer types, `char` and `bool` (and subranges) are called ordinal types. Ordinal types have quite a few special operations: @@ -1139,16 +1146,16 @@ a few special operations: ----------------- -------------------------------------------------------- Operation Comment ----------------- -------------------------------------------------------- -``ord(x)`` returns the integer value that is used to +`ord(x)` returns the integer value that is used to represent `x`'s value -``inc(x)`` increments `x` by one -``inc(x, n)`` increments `x` by `n`; `n` is an integer -``dec(x)`` decrements `x` by one -``dec(x, n)`` decrements `x` by `n`; `n` is an integer -``succ(x)`` returns the successor of `x` -``succ(x, n)`` returns the `n`'th successor of `x` -``pred(x)`` returns the predecessor of `x` -``pred(x, n)`` returns the `n`'th predecessor of `x` +`inc(x)` increments `x` by one +`inc(x, n)` increments `x` by `n`; `n` is an integer +`dec(x)` decrements `x` by one +`dec(x, n)` decrements `x` by `n`; `n` is an integer +`succ(x)` returns the successor of `x` +`succ(x, n)` returns the `n`'th successor of `x` +`pred(x)` returns the predecessor of `x` +`pred(x, n)` returns the `n`'th predecessor of `x` ----------------- -------------------------------------------------------- @@ -1169,17 +1176,17 @@ A subrange type is a range of values from an integer or enumeration type MySubrange = range[0..5] -``MySubrange`` is a subrange of ``int`` which can only hold the values 0 -to 5. Assigning any other value to a variable of type ``MySubrange`` is a +`MySubrange` is a subrange of `int` which can only hold the values 0 +to 5. Assigning any other value to a variable of type `MySubrange` is a compile-time or runtime error. Assignments from the base type to one of its subrange types (and vice versa) are allowed. -The ``system`` module defines the important `Natural `_ -type as ``range[0..high(int)]`` (`high `_ returns +The `system` module defines the important `Natural `_ +type as `range[0..high(int)]` (`high `_ returns the maximal value). Other programming languages may suggest the use of unsigned integers for natural numbers. This is often **unwise**: you don't want unsigned arithmetic (which wraps around) just because the numbers cannot be negative. -Nim's ``Natural`` type helps to avoid this common programming error. +Nim's `Natural` type helps to avoid this common programming error. Sets @@ -1192,7 +1199,7 @@ Arrays An array is a simple fixed-length container. Each element in an array has the same type. The array's index type can be any ordinal type. -Arrays can be constructed using ``[]``: +Arrays can be constructed using `[]`: .. code-block:: nim :test: "nim c $1" @@ -1205,10 +1212,10 @@ Arrays can be constructed using ``[]``: for i in low(x)..high(x): echo x[i] -The notation ``x[i]`` is used to access the i-th element of ``x``. +The notation `x[i]` is used to access the i-th element of `x`. Array access is always bounds checked (at compile-time or at runtime). These checks can be disabled via pragmas or invoking the compiler with the -``--bound_checks:off`` command line switch. +`--bound_checks:off` command line switch. Arrays are value types, like any other Nim type. The assignment operator copies the whole array contents. @@ -1258,9 +1265,9 @@ subdivided into height levels accessed through their integer index: #tower[north][east] = on #tower[0][1] = on -Note how the built-in ``len`` proc returns only the array's first dimension -length. Another way of defining the ``LightTower`` to better illustrate its -nested nature would be to omit the previous definition of the ``LevelSetting`` +Note how the built-in `len` proc returns only the array's first dimension +length. Another way of defining the `LightTower` to better illustrate its +nested nature would be to omit the previous definition of the `LevelSetting` type and instead write it embedded directly as the type of the first dimension: .. code-block:: nim @@ -1290,13 +1297,13 @@ Sequences are similar to arrays but of dynamic length which may change during runtime (like strings). Since sequences are resizable they are always allocated on the heap and garbage collected. -Sequences are always indexed with an ``int`` starting at position 0. The `len +Sequences are always indexed with an `int` starting at position 0. The `len `_, `low `_ and `high `_ operations are available for sequences too. -The notation ``x[i]`` can be used to access the i-th element of ``x``. +The notation `x[i]` can be used to access the i-th element of `x`. -Sequences can be constructed by the array constructor ``[]`` in conjunction -with the array to sequence operator ``@``. Another way to allocate space for +Sequences can be constructed by the array constructor `[]` in conjunction +with the array to sequence operator `@`. Another way to allocate space for a sequence is to call the built-in `newSeq `_ procedure. A sequence may be passed to an openarray parameter. @@ -1310,15 +1317,15 @@ Example: x: seq[int] # a reference to a sequence of integers x = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence allocated on the heap -Sequence variables are initialized with ``@[]``. +Sequence variables are initialized with `@[]`. -The ``for`` statement can be used with one or two variables when used with a +The `for` statement can be used with one or two variables when used with a sequence. When you use the one variable form, the variable will hold the value -provided by the sequence. The ``for`` statement is looping over the results +provided by the sequence. The `for` statement is looping over the results from the `items() `_ iterator from the `system `_ module. But if you use the two-variable form, the first variable will hold the index position and the second variable will hold the -value. Here the ``for`` statement is looping over the results from the +value. Here the `for` statement is looping over the results from the `pairs() `_ iterator from the `system `_ module. Examples: @@ -1343,7 +1350,7 @@ Open arrays Often fixed-size arrays turn out to be too inflexible; procedures should be able to deal with arrays of different sizes. The `openarray`:idx: type allows -this. Openarrays are always indexed with an ``int`` starting at position 0. +this. Openarrays are always indexed with an `int` starting at position 0. The `len `_, `low `_ and `high `_ operations are available for open arrays too. Any array with a compatible base type can be passed to an @@ -1372,7 +1379,7 @@ supported because this is seldom needed and cannot be done efficiently. Varargs ------- -A ``varargs`` parameter is like an openarray parameter. However, it is +A `varargs` parameter is like an openarray parameter. However, it is also a means to implement passing a variable number of arguments to a procedure. The compiler converts the list of arguments to an array automatically: @@ -1404,7 +1411,7 @@ type conversions in this context: myWriteln(stdout, [$123, $"abc", $4.0]) In this example `$ `_ is applied to any argument that is passed -to the parameter ``a``. Note that `$ `_ applied to strings is a +to the parameter `a`. Note that `$ `_ applied to strings is a nop. @@ -1436,7 +1443,7 @@ To understand some of the different ways of specifying the indices of strings, arrays, sequences, etc., it must be remembered that Nim uses zero-based indices. -So the string ``b`` is of length 19, and two different ways of specifying the +So the string `b` is of length 19, and two different ways of specifying the indices are .. code-block:: nim @@ -1446,22 +1453,22 @@ indices are 0 11 17 using indices ^19 ^8 ^2 using ^ syntax -where ``b[0 .. ^1]`` is equivalent to ``b[0 .. b.len-1]`` and ``b[0 ..< b.len]``, and it -can be seen that the ``^1`` provides a short-hand way of specifying the ``b.len-1``. See +where `b[0 .. ^1]` is equivalent to `b[0 .. b.len-1]` and `b[0 ..< b.len]`, and it +can be seen that the `^1` provides a short-hand way of specifying the `b.len-1`. See the `backwards index operator `_. In the above example, because the string ends in a period, to get the portion of the string that is "useless" and replace it with "useful". -``b[11 .. ^2]`` is the portion "useless", and ``b[11 .. ^2] = "useful"`` replaces the +`b[11 .. ^2]` is the portion "useless", and `b[11 .. ^2] = "useful"` replaces the "useless" portion with "useful", giving the result "Slices are useful." -Note 1: alternate ways of writing this are ``b[^8 .. ^2] = "useful"`` or -as ``b[11 .. b.len-2] = "useful"`` or as ``b[11 ..< b.len-1] = "useful"``. +Note 1: alternate ways of writing this are `b[^8 .. ^2] = "useful"` or +as `b[11 .. b.len-2] = "useful"` or as `b[11 ..< b.len-1] = "useful"`. -Note 2: As the ``^`` template returns a `distinct int `_ -of type ``BackwardsIndex``, we can have a ``lastIndex`` constant defined as ``const lastIndex = ^1``, -and later used as ``b[0 .. lastIndex]``. +Note 2: As the `^` template returns a `distinct int `_ +of type `BackwardsIndex`, we can have a `lastIndex` constant defined as `const lastIndex = ^1`, +and later used as `b[0 .. lastIndex]`. Objects ------- @@ -1471,7 +1478,7 @@ structure with a name is the object type. An object is a value type, which means that when an object is assigned to a new variable all its components are copied as well. -Each object type ``Foo`` has a constructor ``Foo(field: value, ...)`` +Each object type `Foo` has a constructor `Foo(field: value, ...)` where all of its fields can be initialized. Unspecified fields will get their default value. @@ -1505,7 +1512,7 @@ get their default value. Object fields that should be visible from outside the defining module have to -be marked with ``*``. +be marked with `*`. .. code-block:: nim :test: "nim c $1" @@ -1524,15 +1531,15 @@ Unlike object types though, tuple types are structurally typed, meaning different tuple-types are *equivalent* if they specify fields of the same type and of the same name in the same order. -The constructor ``()`` can be used to construct tuples. The order of the +The constructor `()` can be used to construct tuples. The order of the fields in the constructor must match the order in the tuple's definition. But unlike objects, a name for the tuple type may not be used here. -Like the object type the notation ``t.field`` is used to access a +Like the object type the notation `t.field` is used to access a tuple's field. Another notation that is not available for objects is -``t[i]`` to access the ``i``'th field. Here ``i`` must be a constant +`t[i]` to access the `i`'th field. Here `i` must be a constant integer. .. code-block:: nim @@ -1602,7 +1609,7 @@ variables! For example: .. code-block:: nim :test: "nim c $1" - import os + import std/os let path = "usr/local/nimc.html" @@ -1636,9 +1643,9 @@ untraced references are *unsafe*. However, for certain low-level operations Traced references are declared with the **ref** keyword; untraced references are declared with the **ptr** keyword. -The empty ``[]`` subscript notation can be used to *de-refer* a reference, -meaning to retrieve the item the reference points to. The ``.`` (access a -tuple/object field operator) and ``[]`` (array/string/sequence index operator) +The empty `[]` subscript notation can be used to *de-refer* a reference, +meaning to retrieve the item the reference points to. The `.` (access a +tuple/object field operator) and `[]` (array/string/sequence index operator) operators perform implicit dereferencing operations for reference types: .. code-block:: nim @@ -1654,18 +1661,18 @@ operators perform implicit dereferencing operations for reference types: n.data = 9 # no need to write n[].data; in fact n[].data is highly discouraged! -To allocate a new traced object, the built-in procedure ``new`` must be used. -To deal with untraced memory, the procedures ``alloc``, ``dealloc`` and -``realloc`` can be used. The `system `_ +To allocate a new traced object, the built-in procedure `new` must be used. +To deal with untraced memory, the procedures `alloc`, `dealloc` and +`realloc` can be used. The `system `_ module's documentation contains further details. -If a reference points to *nothing*, it has the value ``nil``. +If a reference points to *nothing*, it has the value `nil`. Procedural type --------------- A procedural type is a (somewhat abstract) pointer to a procedure. -``nil`` is an allowed value for a variable of a procedural type. +`nil` is an allowed value for a variable of a procedural type. Nim uses procedural types to achieve `functional`:idx: programming techniques. @@ -1703,7 +1710,7 @@ Nim supports splitting a program into pieces with a module concept. Each module is in its own file. Modules enable `information hiding`:idx: and `separate compilation`:idx:. A module may gain access to the symbols of another module by using the `import`:idx: statement. Only top-level symbols that are marked -with an asterisk (``*``) are exported: +with an asterisk (`*`) are exported: .. code-block:: nim # Module A @@ -1717,19 +1724,19 @@ with an asterisk (``*``) are exported: for i in 0..len(a)-1: result[i] = a[i] * b[i] when isMainModule: - # test the new ``*`` operator for sequences: + # test the new `*` operator for sequences: assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9]) -The above module exports ``x`` and ``*``, but not ``y``. +The above module exports `x` and `*`, but not `y`. A module's top-level statements are executed at the start of the program. This can be used to initialize complex data structures for example. -Each module has a special magic constant ``isMainModule`` that is true if the +Each module has a special magic constant `isMainModule` that is true if the module is compiled as the main file. This is very useful to embed tests within the module as shown by the above example. -A symbol of a module *can* be *qualified* with the ``module.symbol`` syntax. And if +A symbol of a module *can* be *qualified* with the `module.symbol` syntax. And if a symbol is ambiguous, it *must* be qualified. A symbol is ambiguous if it is defined in two (or more) different modules and both modules are imported by a third one: @@ -1776,9 +1783,9 @@ rules apply: Excluding symbols ----------------- -The normal ``import`` statement will bring in all exported symbols. +The normal `import` statement will bring in all exported symbols. These can be limited by naming symbols that should be excluded using -the ``except`` qualifier. +the `except` qualifier. .. code-block:: nim import mymodule except y @@ -1787,14 +1794,14 @@ the ``except`` qualifier. From statement -------------- -We have already seen the simple ``import`` statement that just imports all +We have already seen the simple `import` statement that just imports all exported symbols. An alternative that only imports listed symbols is the -``from import`` statement: +`from import` statement: .. code-block:: nim from mymodule import x, y, z -The ``from`` statement can also force namespace qualification on +The `from` statement can also force namespace qualification on symbols, thereby making symbols available, but needing to be qualified in order to be used. @@ -1821,8 +1828,8 @@ define a shorter alias to use when qualifying symbols. Include statement ----------------- -The ``include`` statement does something fundamentally different than -importing a module: it merely includes the contents of a file. The ``include`` +The `include` statement does something fundamentally different than +importing a module: it merely includes the contents of a file. The `include` statement is useful to split up a large module into several files: .. code-block:: nim diff --git a/doc/tut2.rst b/doc/tut2.rst index e3b00555d3..3aef6bb0f2 100644 --- a/doc/tut2.rst +++ b/doc/tut2.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ====================== Nim Tutorial (Part II) ====================== @@ -24,7 +26,7 @@ Pragmas Pragmas are Nim's method to give the compiler additional information/ commands without introducing a massive number of new keywords. Pragmas are -enclosed in the special ``{.`` and ``.}`` curly dot brackets. This tutorial +enclosed in the special `{.` and `.}` curly dot brackets. This tutorial does not cover pragmas. See the `manual `_ or `user guide `_ for a description of the available pragmas. @@ -45,11 +47,11 @@ Inheritance Inheritance in Nim is entirely optional. To enable inheritance with runtime type information the object needs to inherit from -``RootObj``. This can be done directly, or indirectly by -inheriting from an object that inherits from ``RootObj``. Usually -types with inheritance are also marked as ``ref`` types even though +`RootObj`. This can be done directly, or indirectly by +inheriting from an object that inherits from `RootObj`. Usually +types with inheritance are also marked as `ref` types even though this isn't strictly enforced. To check at runtime if an object is of a certain -type, the ``of`` operator can be used. +type, the `of` operator can be used. .. code-block:: nim :test: "nim c $1" @@ -69,16 +71,16 @@ type, the ``of`` operator can be used. student = Student(name: "Anton", age: 5, id: 2) echo student[] -Inheritance is done with the ``object of`` syntax. Multiple inheritance is -currently not supported. If an object type has no suitable ancestor, ``RootObj`` +Inheritance is done with the `object of` syntax. Multiple inheritance is +currently not supported. If an object type has no suitable ancestor, `RootObj` can be used as its ancestor, but this is only a convention. Objects that have -no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma -to introduce new object roots apart from ``system.RootObj``. (This is used +no ancestor are implicitly `final`. You can use the `inheritable` pragma +to introduce new object roots apart from `system.RootObj`. (This is used in the GTK wrapper for instance.) Ref objects should be used whenever inheritance is used. It isn't strictly -necessary, but with non-ref objects assignments such as ``let person: Person = -Student(id: 123)`` will truncate subclass fields. +necessary, but with non-ref objects assignments such as `let person: Person = +Student(id: 123)` will truncate subclass fields. **Note**: Composition (*has-a* relation) is often preferable to inheritance (*is-a* relation) for simple code reuse. Since objects are value types in @@ -111,7 +113,7 @@ Example: Type conversions ---------------- Nim distinguishes between `type casts`:idx: and `type conversions`:idx:. -Casts are done with the ``cast`` operator and force the compiler to +Casts are done with the `cast` operator and force the compiler to interpret a bit pattern to be of another type. Type conversions are a much more polite way to convert a type into another: @@ -119,15 +121,15 @@ They preserve the abstract *value*, not necessarily the *bit-pattern*. If a type conversion is not possible, the compiler complains or an exception is raised. -The syntax for type conversions is ``destination_type(expression_to_convert)`` +The syntax for type conversions is `destination_type(expression_to_convert)` (like an ordinary call): .. code-block:: nim proc getID(x: Person): int = Student(x).id -The ``InvalidObjectConversionDefect`` exception is raised if ``x`` is not a -``Student``. +The `InvalidObjectConversionDefect` exception is raised if `x` is not a +`Student`. Object variants @@ -150,7 +152,7 @@ An example: nkSub, # a subtraction nkIf # an if statement Node = ref object - case kind: NodeKind # the ``kind`` field is the discriminator + case kind: NodeKind # the `kind` field is the discriminator of nkInt: intVal: int of nkFloat: floatVal: float of nkString: strVal: string @@ -173,16 +175,16 @@ Method call syntax ------------------ There is a syntactic sugar for calling routines: -The syntax ``obj.method(args)`` can be used instead of ``method(obj, args)``. +The syntax `obj.method(args)` can be used instead of `method(obj, args)`. If there are no remaining arguments, the parentheses can be omitted: -``obj.len`` (instead of ``len(obj)``). +`obj.len` (instead of `len(obj)`). This method call syntax is not restricted to objects, it can be used for any type: .. code-block:: nim :test: "nim c $1" - import strutils + import std/strutils echo "abc".len # is the same as echo len("abc") echo "abc".toUpperAscii() @@ -196,7 +198,7 @@ So "pure object oriented" code is easy to write: .. code-block:: nim :test: "nim c $1" - import strutils, sequtils + import std/[strutils, sequtils] stdout.writeLine("Give a list of numbers (separated by spaces): ") stdout.write(stdin.readLine.splitWhitespace.map(parseInt).max.`$`) @@ -229,10 +231,10 @@ is needed: new s s.host = 34 # same as `host=`(s, 34) -(The example also shows ``inline`` procedures.) +(The example also shows `inline` procedures.) -The ``[]`` array access operator can be overloaded to provide +The `[]` array access operator can be overloaded to provide `array properties`:idx:\ : .. code-block:: nim @@ -258,14 +260,14 @@ The ``[]`` array access operator can be overloaded to provide else: assert(false) The example is silly, since a vector is better modelled by a tuple which -already provides ``v[]`` access. +already provides `v[]` access. Dynamic dispatch ---------------- Procedures always use static dispatch. For dynamic dispatch replace the -``proc`` keyword by ``method``: +`proc` keyword by `method`: .. code-block:: nim :test: "nim c $1" @@ -289,12 +291,12 @@ Procedures always use static dispatch. For dynamic dispatch replace the echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) -Note that in the example the constructors ``newLit`` and ``newPlus`` are procs -because it makes more sense for them to use static binding, but ``eval`` is a +Note that in the example the constructors `newLit` and `newPlus` are procs +because it makes more sense for them to use static binding, but `eval` is a method because it requires dynamic binding. **Note:** Starting from Nim 0.20, to use multi-methods one must explicitly pass -``--multimethods:on`` when compiling. +`--multimethods:on` when compiling. In a multi-method all parameters that have an object type are used for the dispatching: @@ -324,7 +326,7 @@ dispatching: As the example demonstrates, invocation of a multi-method cannot be ambiguous: Collide 2 is preferred over collide 1 because the resolution works from left to -right. Thus ``Unit, Thing`` is preferred over ``Thing, Unit``. +right. Thus `Unit, Thing` is preferred over `Thing, Unit`. **Performance note**: Nim does not produce a virtual method table, but generates dispatch trees. This avoids the expensive indirect branch for method @@ -338,19 +340,19 @@ Exceptions In Nim exceptions are objects. By convention, exception types are suffixed with 'Error'. The `system `_ module defines an exception hierarchy that you might want to stick to. Exceptions derive from -``system.Exception``, which provides the common interface. +`system.Exception`, which provides the common interface. Exceptions have to be allocated on the heap because their lifetime is unknown. The compiler will prevent you from raising an exception created on the stack. All raised exceptions should at least specify the reason for being raised in -the ``msg`` field. +the `msg` field. A convention is that exceptions should be raised in *exceptional* cases, they should not be used as an alternative method of control flow. Raise statement --------------- -Raising an exception is done with the ``raise`` statement: +Raising an exception is done with the `raise` statement: .. code-block:: nim :test: "nim c $1" @@ -360,9 +362,9 @@ Raising an exception is done with the ``raise`` statement: e.msg = "the request to the OS failed" raise e -If the ``raise`` keyword is not followed by an expression, the last exception +If the `raise` keyword is not followed by an expression, the last exception is *re-raised*. For the purpose of avoiding repeating this common code pattern, -the template ``newException`` in the ``system`` module can be used: +the template `newException` in the `system` module can be used: .. code-block:: nim raise newException(OSError, "the request to the OS failed") @@ -371,11 +373,11 @@ the template ``newException`` in the ``system`` module can be used: Try statement ------------- -The ``try`` statement handles exceptions: +The `try` statement handles exceptions: .. code-block:: nim :test: "nim c $1" - from strutils import parseInt + from std/strutils import parseInt # read the first two lines of a text file that should contain numbers # and tries to add them @@ -399,23 +401,23 @@ The ``try`` statement handles exceptions: finally: close(f) -The statements after the ``try`` are executed unless an exception is -raised. Then the appropriate ``except`` part is executed. +The statements after the `try` are executed unless an exception is +raised. Then the appropriate `except` part is executed. -The empty ``except`` part is executed if there is an exception that is -not explicitly listed. It is similar to an ``else`` part in ``if`` +The empty `except` part is executed if there is an exception that is +not explicitly listed. It is similar to an `else` part in `if` statements. -If there is a ``finally`` part, it is always executed after the +If there is a `finally` part, it is always executed after the exception handlers. -The exception is *consumed* in an ``except`` part. If an exception is not +The exception is *consumed* in an `except` part. If an exception is not handled, it is propagated through the call stack. This means that often -the rest of the procedure - that is not within a ``finally`` clause - +the rest of the procedure - that is not within a `finally` clause - is not executed (if an exception occurs). If you need to *access* the actual exception object or message inside an -``except`` branch you can use the `getCurrentException() +`except` branch you can use the `getCurrentException() `_ and `getCurrentExceptionMsg() `_ procs from the `system `_ module. Example: @@ -433,10 +435,10 @@ module. Example: Annotating procs with raised exceptions --------------------------------------- -Through the use of the optional ``{.raises.}`` pragma you can specify that a +Through the use of the optional `{.raises.}` pragma you can specify that a proc is meant to raise a specific set of exceptions, or none at all. If the -``{.raises.}`` pragma is used, the compiler will verify that this is true. For -instance, if you specify that a proc raises ``IOError``, and at some point it +`{.raises.}` pragma is used, the compiler will verify that this is true. For +instance, if you specify that a proc raises `IOError`, and at some point it (or one of the procs it calls) starts raising a new exception the compiler will prevent that proc from compiling. Usage example: @@ -453,11 +455,11 @@ stopped validating the pragma and the raised exception not being caught, along with the file and line where the uncaught exception is being raised, which may help you locate the offending code which has changed. -If you want to add the ``{.raises.}`` pragma to existing code, the compiler can -also help you. You can add the ``{.effects.}`` pragma statement to your proc and +If you want to add the `{.raises.}` pragma to existing code, the compiler can +also help you. You can add the `{.effects.}` pragma statement to your proc and the compiler will output all inferred effects up to that point (exception tracking is part of Nim's effect system). Another more roundabout way to -find out the list of exceptions raised by a proc is to use the Nim ``doc`` +find out the list of exceptions raised by a proc is to use the Nim `doc` command which generates documentation for a whole module and decorates all procs with the list of raised exceptions. You can read more about Nim's `effect system and related pragmas in the manual `_. @@ -468,14 +470,14 @@ Generics Generics are Nim's means to parametrize procs, iterators or types with `type parameters`:idx:. Generic parameters are written within square -brackets, for example ``Foo[T]``. They are most useful for efficient type safe +brackets, for example `Foo[T]`. They are most useful for efficient type safe containers: .. code-block:: nim :test: "nim c $1" type BinaryTree*[T] = ref object # BinaryTree is a generic type with - # generic param ``T`` + # generic param `T` le, ri: BinaryTree[T] # left and right subtrees; may be nil data: T # the data stored in a node @@ -491,8 +493,8 @@ containers: else: var it = root while it != nil: - # compare the data items; uses the generic ``cmp`` proc - # that works for any type that has a ``==`` and ``<`` operator + # compare the data items; uses the generic `cmp` proc + # that works for any type that has a `==` and `<` operator var c = cmp(it.data, n.data) if c < 0: if it.le == nil: @@ -522,19 +524,19 @@ containers: n = n.le # and follow the left pointer var - root: BinaryTree[string] # instantiate a BinaryTree with ``string`` - add(root, newNode("hello")) # instantiates ``newNode`` and ``add`` - add(root, "world") # instantiates the second ``add`` proc + root: BinaryTree[string] # instantiate a BinaryTree with `string` + add(root, newNode("hello")) # instantiates `newNode` and `add` + add(root, "world") # instantiates the second `add` proc for str in preorder(root): stdout.writeLine(str) The example shows a generic binary tree. Depending on context, the brackets are used either to introduce type parameters or to instantiate a generic proc, iterator or type. As the example shows, generics work with overloading: the -best match of ``add`` is used. The built-in ``add`` procedure for sequences -is not hidden and is used in the ``preorder`` iterator. +best match of `add` is used. The built-in `add` procedure for sequences +is not hidden and is used in the `preorder` iterator. -There is a special ``[:T]`` syntax when using generics with the method call syntax: +There is a special `[:T]` syntax when using generics with the method call syntax: .. code-block:: nim :test: "nim c $1" @@ -567,14 +569,14 @@ Example: assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6)) -The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact -templates: this has the benefit that if you overload the ``==`` operator, -the ``!=`` operator is available automatically and does the right thing. (Except +The `!=`, `>`, `>=`, `in`, `notin`, `isnot` operators are in fact +templates: this has the benefit that if you overload the `==` operator, +the `!=` operator is available automatically and does the right thing. (Except for IEEE floating point numbers - NaN breaks basic boolean logic.) -``a > b`` is transformed into ``b < a``. -``a in b`` is transformed into ``contains(b, a)``. -``notin`` and ``isnot`` have the obvious meanings. +`a > b` is transformed into `b < a`. +`a in b` is transformed into `contains(b, a)`. +`notin` and `isnot` have the obvious meanings. Templates are especially useful for lazy evaluation purposes. Consider a simple proc for logging: @@ -591,11 +593,11 @@ simple proc for logging: x = 4 log("x has the value: " & $x) -This code has a shortcoming: if ``debug`` is set to false someday, the quite -expensive ``$`` and ``&`` operations are still performed! (The argument +This code has a shortcoming: if `debug` is set to false someday, the quite +expensive `$` and `&` operations are still performed! (The argument evaluation for procedures is *eager*). -Turning the ``log`` proc into a template solves this problem: +Turning the `log` proc into a template solves this problem: .. code-block:: nim :test: "nim c $1" @@ -609,15 +611,15 @@ Turning the ``log`` proc into a template solves this problem: x = 4 log("x has the value: " & $x) -The parameters' types can be ordinary types or the meta types ``untyped``, -``typed``, or ``type``. ``type`` suggests that only a type symbol may be given -as an argument, and ``untyped`` means symbol lookups and type resolution is not +The parameters' types can be ordinary types or the meta types `untyped`, +`typed`, or `type`. `type` suggests that only a type symbol may be given +as an argument, and `untyped` means symbol lookups and type resolution is not performed before the expression is passed to the template. If the template has no explicit return type, -``void`` is used for consistency with procs and methods. +`void` is used for consistency with procs and methods. -To pass a block of statements to a template, use ``untyped`` for the last parameter: +To pass a block of statements to a template, use `untyped` for the last parameter: .. code-block:: nim :test: "nim c $1" @@ -638,10 +640,10 @@ To pass a block of statements to a template, use ``untyped`` for the last parame txt.writeLine("line 1") txt.writeLine("line 2") -In the example the two ``writeLine`` statements are bound to the ``body`` -parameter. The ``withFile`` template contains boilerplate code and helps to +In the example the two `writeLine` statements are bound to the `body` +parameter. The `withFile` template contains boilerplate code and helps to avoid a common bug: to forget to close the file. Note how the -``let fn = filename`` statement ensures that ``filename`` is evaluated only +`let fn = filename` statement ensures that `filename` is evaluated only once. Example: Lifting Procs @@ -649,11 +651,11 @@ Example: Lifting Procs .. code-block:: nim :test: "nim c $1" - import math + import std/math template liftScalarProc(fname) = ## Lift a proc taking one scalar parameter and returning a - ## scalar value (eg ``proc sssss[T](x: T): float``), + ## scalar value (eg `proc sssss[T](x: T): float`), ## to provide templated procs that can handle a single ## parameter of seq[T] or nested seq[seq[]] or the same type ## @@ -675,15 +677,15 @@ Compilation to JavaScript Nim code can be compiled to JavaScript. However in order to write JavaScript-compatible code you should remember the following: -- ``addr`` and ``ptr`` have slightly different semantic meaning in JavaScript. +- `addr` and `ptr` have slightly different semantic meaning in JavaScript. It is recommended to avoid those if you're not sure how they are translated to JavaScript. -- ``cast[T](x)`` in JavaScript is translated to ``(x)``, except for casting +- `cast[T](x)` in JavaScript is translated to `(x)`, except for casting between signed/unsigned ints, in which case it behaves as static cast in C language. -- ``cstring`` in JavaScript means JavaScript string. It is a good practice to - use ``cstring`` only when it is semantically appropriate. E.g. don't use - ``cstring`` as a binary data buffer. +- `cstring` in JavaScript means JavaScript string. It is a good practice to + use `cstring` only when it is semantically appropriate. E.g. don't use + `cstring` as a binary data buffer. Part 3 diff --git a/doc/tut3.rst b/doc/tut3.rst index a159f0d829..358a9b45e4 100644 --- a/doc/tut3.rst +++ b/doc/tut3.rst @@ -1,3 +1,5 @@ +.. default-role:: code + ======================= Nim Tutorial (Part III) ======================= @@ -20,15 +22,15 @@ a Nim syntax tree into a different tree. Examples of things that can be implemented in macros: * An assert macro that prints both sides of a comparison operator, if - the assertion fails. ``myAssert(a == b)`` is converted to - ``if a != b: quit($a " != " $b)`` + the assertion fails. `myAssert(a == b)` is converted to + `if a != b: quit($a " != " $b)` * A debug macro that prints the value and the name of the symbol. - ``myDebugEcho(a)`` is converted to ``echo "a: ", a`` + `myDebugEcho(a)` is converted to `echo "a: ", a` * Symbolic differentiation of an expression. - ``diff(a*pow(x,3) + b*pow(x,2) + c*x + d, x)`` is converted to - ``3*a*pow(x,2) + 2*b*x + c`` + `diff(a*pow(x,3) + b*pow(x,2) + c*x + d, x)` is converted to + `3*a*pow(x,2) + 2*b*x + c` Macro Arguments @@ -36,14 +38,14 @@ Macro Arguments The types of macro arguments have two faces. One face is used for the overload resolution and the other face is used within the macro -body. For example, if ``macro foo(arg: int)`` is called in an -expression ``foo(x)``, ``x`` has to be of a type compatible to int, but -*within* the macro's body ``arg`` has the type ``NimNode``, not ``int``! +body. For example, if `macro foo(arg: int)` is called in an +expression `foo(x)`, `x` has to be of a type compatible to int, but +*within* the macro's body `arg` has the type `NimNode`, not `int`! Why it is done this way will become obvious later, when we have seen concrete examples. There are two ways to pass arguments to a macro, an argument can be -either ``typed`` or ``untyped``. +either `typed` or `untyped`. Untyped Arguments @@ -58,11 +60,11 @@ result somehow. The result of a macro expansion is always checked by the compiler, so apart from weird error messages, nothing bad can happen. -The downside for an ``untyped`` argument is that these do not play +The downside for an `untyped` argument is that these do not play well with Nim's overloading resolution. The upside for untyped arguments is that the syntax tree is -quite predictable and less complex compared to its ``typed`` +quite predictable and less complex compared to its `typed` counterpart. @@ -74,8 +76,8 @@ does transformations on it, before it is passed to the macro. Here identifier nodes are resolved as symbols, implicit type conversions are visible in the tree as calls, templates are expanded, and probably most importantly, nodes have type information. -Typed arguments can have the type ``typed`` in the arguments list. -But all other types, such as ``int``, ``float`` or ``MyObjectType`` +Typed arguments can have the type `typed` in the arguments list. +But all other types, such as `int`, `float` or `MyObjectType` are typed arguments as well, and they are passed to the macro as a syntax tree. @@ -84,17 +86,17 @@ Static Arguments ---------------- Static arguments are a way to pass values as values and not as syntax -tree nodes to a macro. For example for ``macro foo(arg: static[int])`` -in the expression ``foo(x)``, ``x`` needs to be an integer constant, -but in the macro body ``arg`` is just like a normal parameter of type -``int``. +tree nodes to a macro. For example for `macro foo(arg: static[int])` +in the expression `foo(x)`, `x` needs to be an integer constant, +but in the macro body `arg` is just like a normal parameter of type +`int`. .. code-block:: nim - import macros + import std/macros macro myMacro(arg: static[int]): untyped = - echo arg # just an int (7), not ``NimNode`` + echo arg # just an int (7), not `NimNode` myMacro(1 + 2 * 3) @@ -104,7 +106,7 @@ Code Blocks as Arguments It is possible to pass the last argument of a call expression in a separate code block with indentation. For example, the following code -example is a valid (but not a recommended) way to call ``echo``: +example is a valid (but not a recommended) way to call `echo`: .. code-block:: nim @@ -125,10 +127,10 @@ code is represented as a syntax tree, and how such a tree needs to look like so that the Nim compiler will understand it. The nodes of the Nim syntax tree are documented in the `macros `_ module. But a more interactive way to explore the Nim -syntax tree is with ``macros.treeRepr``, it converts a syntax tree +syntax tree is with `macros.treeRepr`, it converts a syntax tree into a multi-line string for printing on the console. It can be used to explore how the argument expressions are represented in tree form -and for debug printing of generated syntax tree. ``dumpTree`` is a +and for debug printing of generated syntax tree. `dumpTree` is a predefined macro that just prints its argument in a tree representation, but does nothing else. Here is an example of such a tree representation: @@ -154,15 +156,15 @@ but does nothing else. Here is an example of such a tree representation: Custom Semantic Checking ------------------------ +------------------------ The first thing that a macro should do with its arguments is to check if the argument is in the correct form. Not every type of wrong input needs to be caught here, but anything that could cause a crash during macro evaluation should be caught and create a nice error message. -``macros.expectKind`` and ``macros.expectLen`` are a good start. If +`macros.expectKind` and `macros.expectLen` are a good start. If the checks need to be more complex, arbitrary error messages can -be created with the ``macros.error`` proc. +be created with the `macros.error` proc. .. code-block:: nim @@ -174,26 +176,44 @@ Generating Code --------------- There are two ways to generate the code. Either by creating the syntax -tree with expressions that contain a lot of calls to ``newTree`` and -``newLit``, or with ``quote do:`` expressions. The first option offers +tree with expressions that contain a lot of calls to `newTree` and +`newLit`, or with `quote do:` expressions. The first option offers the best low-level control for the syntax tree generation, but the second option is much less verbose. If you choose to create the syntax -tree with calls to ``newTree`` and ``newLit`` the macro -``macros.dumpAstGen`` can help you with the verbosity. ``quote do:`` -allows you to write the code that you want to generate literally, -backticks are used to insert code from ``NimNode`` symbols into the -generated expression. This means that you can't use backticks within -``quote do:`` for anything else than injecting symbols. Make sure to -inject only symbols of type ``NimNode`` into the generated syntax -tree. You can use ``newLit`` to convert arbitrary values into -expressions trees of type ``NimNode`` so that it is safe to inject +tree with calls to `newTree` and `newLit` the macro +`macros.dumpAstGen` can help you with the verbosity. + +`quote do:` allows you to write the code that you want to generate literally. +Backticks are used to insert code from `NimNode` symbols into the +generated expression. + +.. code-block:: nim + macro a(i) = quote do: let `i` = 0 + a b + +A custom prefix operator can be defined whenever backticks are needed. + +.. code-block:: nim + macro a(i) = quote("@") do: assert @i == 0 + let b = 0 + a b + +The injected symbol needs accent quoted when it resolves to a symbol. + +.. code-block:: nim + macro a(i) = quote("@") do: let `@i` == 0 + a b + +Make sure to inject only symbols of type `NimNode` into the generated syntax +tree. You can use `newLit` to convert arbitrary values into +expressions trees of type `NimNode` so that it is safe to inject them into the tree. .. code-block:: nim :test: "nim c $1" - import macros + import std/macros type MyType = object @@ -213,7 +233,7 @@ them into the tree. myMacro("Hallo") -The call to ``myMacro`` will generate the following code: +The call to `myMacro` will generate the following code: .. code-block:: nim echo "Hallo" @@ -224,7 +244,7 @@ Building Your First Macro ------------------------- To give a starting point to writing macros we will show now how to -implement the ``myDebug`` macro mentioned earlier. The first thing to +implement the `myDebug` macro mentioned earlier. The first thing to do is to build a simple example of the macro usage, and then just print the argument. This way it is possible to get an idea of what a correct argument should look like. @@ -232,7 +252,7 @@ correct argument should look like. .. code-block:: nim :test: "nim c $1" - import macros + import std/macros macro myAssert(arg: untyped): untyped = echo arg.treeRepr @@ -258,7 +278,7 @@ written. .. code-block:: nim :test: "nim c $1" - import macros + import std/macros macro myAssert(arg: untyped): untyped = # all node kind identifiers are prefixed with "nnk" @@ -281,7 +301,7 @@ written. This is the code that will be generated. To debug what the macro -actually generated, the statement ``echo result.repr`` can be used, in +actually generated, the statement `echo result.repr` can be used, in the last line of the macro. It is also the statement that has been used to get this output. @@ -324,14 +344,14 @@ possible with it. Strformat --------- -In the Nim standard library, the ``strformat`` library provides a +In the Nim standard library, the `strformat` library provides a macro that parses a string literal at compile time. Parsing a string in a macro like here is generally not recommended. The parsed AST cannot have type information, and parsing implemented on the VM is generally not very fast. Working on AST nodes is almost always the -recommended way. But still ``strformat`` is a good example for a +recommended way. But still `strformat` is a good example for a practical use case for a macro that is slightly more complex than the -``assert`` macro. +`assert` macro. `Strformat `_ diff --git a/drnim/drnim.nim b/drnim/drnim.nim index f2a20fa624..44eab86259 100644 --- a/drnim/drnim.nim +++ b/drnim/drnim.nim @@ -1271,7 +1271,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = mainCommand(graph) if conf.hasHint(hintGCStats): echo(GC_getStatistics()) -when compileOption("gc", "v2") or compileOption("gc", "refc"): +when compileOption("gc", "refc"): # the new correct mark&sweep collector is too slow :-/ GC_disableMarkAndSweep() diff --git a/examples/allany.nim b/examples/allany.nim deleted file mode 100644 index 8a5ab81f05..0000000000 --- a/examples/allany.nim +++ /dev/null @@ -1,24 +0,0 @@ -# All and any - -template all(container, cond: untyped): bool = - var result = true - for it in items(container): - if not cond(it): - result = false - break - result - -template any(container, cond: untyped): bool = - var result = false - for it in items(container): - if cond(it): - result = true - break - result - -if all("mystring", {'a'..'z'}.contains) and any("myohmy", 'y'.`==`): - echo "works" -else: - echo "does not work" - - diff --git a/examples/extract_keyval_pairs_pegs.nim b/examples/extract_keyval_pairs_pegs.nim deleted file mode 100644 index 2a56432768..0000000000 --- a/examples/extract_keyval_pairs_pegs.nim +++ /dev/null @@ -1,7 +0,0 @@ -# Filter key=value pairs from "myfile.txt" -import pegs - -for x in lines("myfile.txt"): - if x =~ peg"{\ident} \s* '=' \s* {.*}": - echo "Key: ", matches[0], - " Value: ", matches[1] diff --git a/examples/extract_keyval_pairs_re.nim b/examples/extract_keyval_pairs_re.nim deleted file mode 100644 index a594c0fa8c..0000000000 --- a/examples/extract_keyval_pairs_re.nim +++ /dev/null @@ -1,8 +0,0 @@ -# Filter key=value pairs from "myfile.txt" -import re - -for x in lines("myfile.txt"): - if x =~ re"(\w+)=(.*)": - echo "Key: ", matches[0], " Value: ", matches[1] - - diff --git a/examples/hallo.nim b/examples/hallo.nim deleted file mode 100644 index d94da8c1f0..0000000000 --- a/examples/hallo.nim +++ /dev/null @@ -1,3 +0,0 @@ -# Hello world program - -echo "Hello World" diff --git a/examples/maximum.nim b/examples/maximum.nim deleted file mode 100644 index 3c43a48c96..0000000000 --- a/examples/maximum.nim +++ /dev/null @@ -1,6 +0,0 @@ -# Shows how the method call syntax can be used to chain calls conveniently. - -import strutils, sequtils - -echo "Give a list of numbers (separated by spaces): " -stdin.readLine.split.map(parseInt).max.`$`.echo(" is the maximum!") diff --git a/examples/myfile.txt b/examples/myfile.txt deleted file mode 100644 index fb7cda984e..0000000000 --- a/examples/myfile.txt +++ /dev/null @@ -1,11 +0,0 @@ -kladsfa - -asdflksadlfasf - - -adsfljksadfl - - -key=/usr/bin/value -key2=/ha/ha - diff --git a/examples/readme.txt b/examples/readme.txt deleted file mode 100644 index 42446faead..0000000000 --- a/examples/readme.txt +++ /dev/null @@ -1,2 +0,0 @@ -In this directory you can find several examples for how to use the Nim -library. diff --git a/examples/statcsv.nim b/examples/statcsv.nim deleted file mode 100644 index 983cd555fb..0000000000 --- a/examples/statcsv.nim +++ /dev/null @@ -1,60 +0,0 @@ -# Example program to show the parsecsv module -# This program reads a CSV file and computes sum, mean, minimum, maximum and -# the standard deviation of its columns. -# The CSV file can have a header which is then used for the output. - -import os, streams, parsecsv, strutils, math, stats - -if paramCount() < 1: - quit("Usage: statcsv filename[.csv]") - -var filename = addFileExt(paramStr(1), "csv") -var s = newFileStream(filename, fmRead) -if s == nil: quit("cannot open the file " & filename) - -var - x: CsvParser - header: seq[string] - res: seq[RunningStat] -open(x, s, filename, separator=';', skipInitialSpace = true) -while readRow(x): - if processedRows(x) == 1: - newSeq(res, x.row.len) # allocate space for the result - if validIdentifier(x.row[0]): - # header line: - header = x.row - else: - newSeq(header, x.row.len) - for i in 0..x.row.len-1: header[i] = "Col " & $(i+1) - else: - # data line: - for i in 0..x.row.len-1: - push(res[i], parseFloat(x.row[i])) -x.close() - -# Write results: -for i in 0..header.len-1: - stdout.write("\t") - stdout.write(header[i]) -stdout.write("\nSum") -for i in 0..header.len-1: - stdout.write("\t") - stdout.write(res[i].sum) -stdout.write("\nMean") -for i in 0..header.len-1: - stdout.write("\t") - stdout.write(res[i].mean) -stdout.write("\nMin") -for i in 0..header.len-1: - stdout.write("\t") - stdout.write(res[i].min) -stdout.write("\nMax") -for i in 0..header.len-1: - stdout.write("\t") - stdout.write(res[i].max) -stdout.write("\nStdDev") -for i in 0..header.len-1: - stdout.write("\t") - stdout.write(res[i].standardDeviation) -stdout.write("\n") - diff --git a/examples/talk/dsl.nim b/examples/talk/dsl.nim deleted file mode 100644 index 2dde517903..0000000000 --- a/examples/talk/dsl.nim +++ /dev/null @@ -1,33 +0,0 @@ - -import strutils - -template html(name, matter: untyped) = - proc name(): string = - result = "" - matter - result.add("") - -template nestedTag(tag: untyped) = - template tag(matter: typed) = - result.add("<" & astToStr(tag) & ">") - matter - result.add("") - -template simpleTag(tag: untyped) = - template tag(matter: untyped) = - result.add("<$1>$2" % [astToStr(tag), matter]) - -nestedTag body -nestedTag head -nestedTag ul -simpleTag title -simpleTag li - -html mainPage: - head: - title "now look at this" - body: - ul: - li "Nim is quite capable" - -echo mainPage() diff --git a/examples/talk/formatoptimizer.nim b/examples/talk/formatoptimizer.nim deleted file mode 100644 index 6e3d0c2c39..0000000000 --- a/examples/talk/formatoptimizer.nim +++ /dev/null @@ -1,55 +0,0 @@ -## This is the example that optimizes a modified "hello world" - -import macros - -proc invalidFormatString() = - echo "invalidFormatString" - -template formatImpl(handleChar: untyped) = - var i = 0 - while i < f.len: - if f[i] == '$': - case f[i+1] - of '1'..'9': - var j = 0 - i += 1 - while f[i] in {'0'..'9'}: - j = j * 10 + ord(f[i]) - ord('0') - i += 1 - result.add(a[j-1]) - else: - invalidFormatString() - else: - result.add(handleChar(f[i])) - i += 1 - -proc `%`*(f: string, a: openArray[string]): string = - template identity(x: untyped): untyped = x - result = "" - formatImpl(identity) - -macro optFormat{`%`(f, a)}(f: string{lit}, a: openArray[string]): untyped = - result = newNimNode(nnkBracket) - #newCall("&") - let f = f.strVal - formatImpl(newLit) - result = nestList(newIdentNode("&"), result) - -template optAdd1{x = y; add(x, z)}(x, y, z: string) = - x = y & z - -#template optAdd2{x.add(y); x.add(z)}(x, y, z: string) = -# x.add(y & z) - -proc `/&` [T: object](x: T): string = - result = "(" - for name, value in fieldPairs(x): - result.add("$1: $2\n" % [name, $value]) - result.add(")") - -type - MyObject = object - a, b: int - s: string -let obj = MyObject(a: 3, b: 4, s: "abc") -echo(/&obj) diff --git a/examples/talk/hoisting.nim b/examples/talk/hoisting.nim deleted file mode 100644 index 54e00884f9..0000000000 --- a/examples/talk/hoisting.nim +++ /dev/null @@ -1,23 +0,0 @@ -type - Regex = distinct string - -const maxSubpatterns = 10 - -proc re(x: string): Regex = - result = Regex(x) - -proc match(s: string, pattern: Regex, captures: var openArray[string]): bool = - true - -template optRe{re(x)}(x: string{lit}): Regex = - var g {.global.} = re(x) - g - -template `=~`(s: string, pattern: Regex): bool = - when not declaredInScope(matches): - var matches {.inject.}: array[maxSubPatterns, string] - match(s, pattern, matches) - -for line in lines("input.txt"): - if line =~ re"(\w+)=(\w+)": - echo "key-value pair; key: ", matches[0], " value: ", matches[1] diff --git a/examples/talk/lazyeval.nim b/examples/talk/lazyeval.nim deleted file mode 100644 index 77d9638343..0000000000 --- a/examples/talk/lazyeval.nim +++ /dev/null @@ -1,12 +0,0 @@ - -const - debug = true - -template log(msg: string) = - if debug: - echo msg -var - x = 1 - y = 2 - -log("x: " & $x & ", y: " & $y) diff --git a/examples/talk/quasiquote.nim b/examples/talk/quasiquote.nim deleted file mode 100644 index b3c7bb9712..0000000000 --- a/examples/talk/quasiquote.nim +++ /dev/null @@ -1,11 +0,0 @@ - -import macros - -macro check(ex: untyped): typed = - var info = ex.lineinfo - var expString = ex.toStrLit - result = quote do: - if not `ex`: - echo `info`, ": Check failed: ", `expString` - -check 1 < 2 diff --git a/examples/talk/tags.nim b/examples/talk/tags.nim deleted file mode 100644 index 8bf3450c9e..0000000000 --- a/examples/talk/tags.nim +++ /dev/null @@ -1,9 +0,0 @@ - -template htmlTag(tag: untyped) = - proc tag(): string = "<" & astToStr(tag) & ">" - -htmlTag(br) -htmlTag(html) - -echo br() -echo html() \ No newline at end of file diff --git a/examples/tunit.nim b/examples/tunit.nim deleted file mode 100644 index e8ff8a9527..0000000000 --- a/examples/tunit.nim +++ /dev/null @@ -1,47 +0,0 @@ - -import - unittest, macros - -var - a = 1 - b = 22 - c = 1 - d = 3 - -suite "my suite": - setup: - echo "suite setup" - var testVar = "from setup" - - teardown: - echo "suite teardown" - - test "first suite test": - testVar = "modified" - echo "test var: " & testVar - check a > b - - test "second suite test": - echo "test var: " & testVar - -proc foo: bool = - echo "running foo" - return true - -proc err = - raise newException(ArithmeticDefect, "some exception") - -test "final test": - echo "inside suite-less test" - - check: - a == c - foo() - d > 10 - -test "arithmetic failure": - expect(ArithmeticDefect): - err() - - expect(ArithmeticDefect, CatchableError): - discard foo() diff --git a/koch.nim b/koch.nim index 5da2628847..bf7fb1e620 100644 --- a/koch.nim +++ b/koch.nim @@ -10,9 +10,10 @@ # const - NimbleStableCommit = "8f7af860c5ce9634af880a7081c6435e1f2a5148" # master - FusionStableCommit = "319aac4d43b04113831b529f8003e82f4af6a4a5" - + NimbleStableCommit = "d13f3b8ce288b4dc8c34c219a4e050aaeaf43fc9" # master + # examples of possible values: #head, #ea82b54, 1.2.3 + FusionStableHash = "#372ee4313827ef9f2ea388840f7d6b46c2b1b014" + HeadHash = "#head" when not defined(windows): const Z3StableCommit = "65de3f748a6812eecd7db7c478d5fc54424d368b" # the version of Z3 that DrNim uses @@ -66,7 +67,8 @@ Possible Commands: e.g. nimble) doesn't require network connectivity nimble builds the Nimble tool - fusion clone fusion into the working tree + fusion installs fusion via Nimble + Boot options: -d:release produce a release version of the compiler -d:nimUseLinenoise use the linenoise library for interactive mode @@ -180,14 +182,7 @@ proc bundleWinTools(args: string) = nimCompile(r"tools\downloader.nim", options = r"--cc:vcc --app:gui -d:ssl --noNimblePath --path:..\ui " & args) -proc bundleFusion(latest: bool) = - let commit = if latest: "HEAD" else: FusionStableCommit - cloneDependency(distDir, "https://github.com/nim-lang/fusion.git", commit, - allowBundled = true) - copyDir(distDir / "fusion" / "src" / "fusion", "lib" / "fusion") - proc zip(latest: bool; args: string) = - bundleFusion(latest) bundleNimbleExe(latest, args) bundleNimsuggest(args) bundleNimpretty(args) @@ -227,7 +222,6 @@ proc buildTools(args: string = "") = options = "-d:release " & args) proc nsis(latest: bool; args: string) = - bundleFusion(latest) bundleNimbleExe(latest, args) bundleNimsuggest(args) bundleWinTools(args) @@ -272,7 +266,7 @@ proc findStartNim: string = # If these fail, we try to build nim with the "build.(sh|bat)" script. let (nim, ok) = findNimImpl() if ok: return nim - when defined(Posix): + when defined(posix): const buildScript = "build.sh" if fileExists(buildScript): if tryExec("./" & buildScript): return "bin" / nim @@ -290,6 +284,13 @@ proc thVersion(i: int): string = template doUseCpp(): bool = getEnv("NIM_COMPILE_TO_CPP", "false") == "true" proc boot(args: string) = + ## bootstrapping is a process that involves 3 steps: + ## 1. use csources to produce nim1.exe. This nim1.exe is buggy but + ## rock solid for building a Nim compiler. It shouldn't be used for anything else. + ## 2. use nim1.exe to produce nim2.exe. nim2.exe is the one you really need. + ## 3. We use nim2.exe to build nim3.exe. nim3.exe is equal to nim2.exe except for timestamps. + ## This step ensures a minimum amount of quality. We know that nim2.exe can be used + ## for Nim compiler development. var output = "compiler" / "nim".exe var finalDest = "bin" / "nim".exe # default to use the 'c' command: @@ -464,7 +465,7 @@ proc temp(args: string) = if "doc" notin programArgs and "threads" notin programArgs and "js" notin programArgs and "rst2html" notin programArgs: - bootArgs.add " -d:leanCompiler" + bootArgs = " -d:leanCompiler" & bootArgs let nimexec = findNim().quoteShell() exec(nimexec & " c -d:debug --debugger:native -d:nimBetterRun " & bootArgs & " " & (d / "compiler" / "nim"), 125) copyExe(output, finalDest) @@ -525,18 +526,23 @@ proc runCI(cmd: string) = echo "runCI: ", cmd echo hostInfo() # boot without -d:nimHasLibFFI to make sure this still works - kochExecFold("Boot in release mode", "boot -d:release") + kochExecFold("Boot in release mode", "boot -d:release -d:nimStrictMode") ## build nimble early on to enable remainder to depend on it if needed kochExecFold("Build Nimble", "nimble") + let batchParam = "--batch:$1" % "NIM_TESTAMENT_BATCH".getEnv("_") if getEnv("NIM_TEST_PACKAGES", "0") == "1": - execFold("Test selected Nimble packages (1)", "nim c -r testament/testament cat nimble-packages-1") - elif getEnv("NIM_TEST_PACKAGES", "0") == "2": - execFold("Test selected Nimble packages (2)", "nim c -r testament/testament cat nimble-packages-2") + execFold("Test selected Nimble packages", "nim r testament/testament $# pcat nimble-packages" % batchParam) else: buildTools() + for a in "zip opengl sdl1 jester@#head".split: + let buildDeps = "build"/"deps" # xxx factor pending https://github.com/timotheecour/Nim/issues/616 + # if this gives `Additional info: "build/deps" [OSError]`, make sure nimble is >= v0.12.0, + # otherwise `absolutePath` is needed, refs https://github.com/nim-lang/nimble/issues/901 + execFold("", "nimble install -y --nimbleDir:$# $#" % [buildDeps.quoteShell, a]) + ## run tests execFold("Test nimscript", "nim e tests/test_nimscript.nims") when defined(windows): @@ -544,11 +550,9 @@ proc runCI(cmd: string) = execFold("Compile tester", "nim c -d:nimCoroutines --os:genode -d:posix --compileOnly testament/testament") # main bottleneck here - # xxx: even though this is the main bottlneck, we could use same code to batch the other tests - #[ - BUG: with initOptParser, `--batch:'' all` interprets `all` as the argument of --batch - ]# - execFold("Run tester", "nim c -r -d:nimCoroutines testament/testament --pedantic --batch:$1 all -d:nimCoroutines" % ["NIM_TESTAMENT_BATCH".getEnv("_")]) + # xxx: even though this is the main bottleneck, we could speedup the rest via batching with `--batch`. + # BUG: with initOptParser, `--batch:'' all` interprets `all` as the argument of --batch, pending bug #14343 + execFold("Run tester", "nim c -r -d:nimCoroutines --putenv:NIM_TESTAMENT_REMOTE_NETWORKING:1 -d:nimStrictMode testament/testament $# all -d:nimCoroutines" % batchParam) block CT_FFI: when defined(posix): # windows can be handled in future PR's @@ -694,12 +698,13 @@ when isMainModule: of "tools": buildTools(op.cmdLineRest) bundleNimbleExe(latest, op.cmdLineRest) - bundleFusion(latest) of "pushcsource", "pushcsources": pushCsources() of "valgrind": valgrind(op.cmdLineRest) of "c2nim": bundleC2nim(op.cmdLineRest) of "drnim": buildDrNim(op.cmdLineRest) - of "fusion": bundleFusion(latest) + of "fusion": + let suffix = if latest: HeadHash else: FusionStableHash + exec("nimble install -y fusion@$#" % suffix) else: showHelp() break of cmdEnd: break diff --git a/lib/core/macrocache.nim b/lib/core/macrocache.nim index 8fe1fa603f..e376ad87fe 100644 --- a/lib/core/macrocache.nim +++ b/lib/core/macrocache.nim @@ -7,38 +7,199 @@ # distribution, for details about the copyright. # -## This module provides an API for macros that need to collect compile -## time information across module boundaries in global variables. -## Starting with version 0.19 of Nim this is not directly supported anymore -## as it breaks incremental compilations. -## Instead the API here needs to be used. +## This module provides an API for macros to collect compile-time information +## across module boundaries. It should be used instead of global `{.compileTime.}` +## variables as those break incremental compilation. +## +## The main feature of this module is that if you create `CacheTable`s or +## any other `Cache` types with the same name in different modules, their +## content will be shared, meaning that you can fill a `CacheTable` in +## one module, and iterate over its contents in another. + +runnableExamples: + import std/macros + + const mcTable = CacheTable"myTable" + const mcSeq = CacheSeq"mySeq" + const mcCounter = CacheCounter"myCounter" + + static: + # add new key "val" with the value `myval` + let myval = newLit("hello ic") + mcTable["val"] = myval + assert mcTable["val"].kind == nnkStrLit + + # Can access the same cache from different static contexts + # All the information is retained + static: + # get value from `mcTable` and add it to `mcSeq` + mcSeq.add(mcTable["val"]) + assert mcSeq.len == 1 + + static: + assert mcSeq[0].strVal == "hello ic" + + # increase `mcCounter` by 3 + mcCounter.inc(3) + assert mcCounter.value == 3 + type CacheSeq* = distinct string + ## Compile-time sequence of `NimNode`s. CacheTable* = distinct string + ## Compile-time table of key-value pairs. + ## + ## Keys are `string`s and values are `NimNode`s. CacheCounter* = distinct string + ## Compile-time counter, uses `int` for storing the count. -proc value*(c: CacheCounter): int {.magic: "NccValue".} -proc inc*(c: CacheCounter; by = 1) {.magic: "NccInc".} +proc value*(c: CacheCounter): int {.magic: "NccValue".} = + ## Returns the value of a counter `c`. + runnableExamples: + static: + let counter = CacheCounter"valTest" + # default value is 0 + assert counter.value == 0 -proc add*(s: CacheSeq; value: NimNode) {.magic: "NcsAdd".} -proc incl*(s: CacheSeq; value: NimNode) {.magic: "NcsIncl".} -proc len*(s: CacheSeq): int {.magic: "NcsLen".} -proc `[]`*(s: CacheSeq; i: int): NimNode {.magic: "NcsAt".} + inc counter + assert counter.value == 1 + +proc inc*(c: CacheCounter; by = 1) {.magic: "NccInc".} = + ## Increments the counter `c` with the value `by`. + runnableExamples: + static: + let counter = CacheCounter"incTest" + inc counter + inc counter, 5 + + assert counter.value == 6 + +proc add*(s: CacheSeq; value: NimNode) {.magic: "NcsAdd".} = + ## Adds `value` to `s`. + runnableExamples: + import std/macros + const mySeq = CacheSeq"addTest" + + static: + mySeq.add(newLit(5)) + mySeq.add(newLit("hello ic")) + + assert mySeq.len == 2 + assert mySeq[1].strVal == "hello ic" + +proc incl*(s: CacheSeq; value: NimNode) {.magic: "NcsIncl".} = + ## Adds `value` to `s`. + ## + ## .. hint:: This doesn't do anything if `value` is already in `s`. + runnableExamples: + import std/macros + const mySeq = CacheSeq"inclTest" + + static: + mySeq.incl(newLit(5)) + mySeq.incl(newLit(5)) + + # still one element + assert mySeq.len == 1 + +proc len*(s: CacheSeq): int {.magic: "NcsLen".} = + ## Returns the length of `s`. + runnableExamples: + import std/macros + + const mySeq = CacheSeq"lenTest" + static: + let val = newLit("helper") + mySeq.add(val) + assert mySeq.len == 1 + + mySeq.add(val) + assert mySeq.len == 2 + +proc `[]`*(s: CacheSeq; i: int): NimNode {.magic: "NcsAt".} = + ## Returns the `i`th value from `s`. + runnableExamples: + import std/macros + + const mySeq = CacheSeq"subTest" + static: + mySeq.add(newLit(42)) + assert mySeq[0].intVal == 42 iterator items*(s: CacheSeq): NimNode = + ## Iterates over each item in `s`. + runnableExamples: + import std/macros + const myseq = CacheSeq"itemsTest" + + static: + myseq.add(newLit(5)) + myseq.add(newLit(42)) + + for val in myseq: + # check that all values in `myseq` are int literals + assert val.kind == nnkIntLit + for i in 0 ..< len(s): yield s[i] -proc `[]=`*(t: CacheTable; key: string, value: NimNode) {.magic: "NctPut".} - ## 'key' has to be unique! +proc `[]=`*(t: CacheTable; key: string, value: NimNode) {.magic: "NctPut".} = + ## Inserts a `(key, value)` pair into `t`. + ## + ## .. warning:: `key` has to be unique! Assigning `value` to a `key` that is already + ## in the table will result in a compiler error. + runnableExamples: + import std/macros -proc len*(t: CacheTable): int {.magic: "NctLen".} -proc `[]`*(t: CacheTable; key: string): NimNode {.magic: "NctGet".} + const mcTable = CacheTable"subTest" + static: + # assign newLit(5) to the key "value" + mcTable["value"] = newLit(5) + + # check that we can get the value back + assert mcTable["value"].kind == nnkIntLit + +proc len*(t: CacheTable): int {.magic: "NctLen".} = + ## Returns the number of elements in `t`. + runnableExamples: + import std/macros + + const dataTable = CacheTable"lenTest" + static: + dataTable["key"] = newLit(5) + assert dataTable.len == 1 + +proc `[]`*(t: CacheTable; key: string): NimNode {.magic: "NctGet".} = + ## Retrieves the `NimNode` value at `t[key]`. + runnableExamples: + import std/macros + + const mcTable = CacheTable"subTest" + static: + mcTable["toAdd"] = newStmtList() + + # get the NimNode back + assert mcTable["toAdd"].kind == nnkStmtList proc hasNext(t: CacheTable; iter: int): bool {.magic: "NctHasNext".} proc next(t: CacheTable; iter: int): (string, NimNode, int) {.magic: "NctNext".} iterator pairs*(t: CacheTable): (string, NimNode) = + ## Iterates over all `(key, value)` pairs in `t`. + runnableExamples: + import std/macros + const mytabl = CacheTable"values" + + static: + mytabl["intVal"] = newLit(5) + mytabl["otherVal"] = newLit(6) + for key, val in mytabl: + # make sure that we actually get the same keys + assert key in ["intVal", "otherVal"] + + # all vals are int literals + assert val.kind == nnkIntLit + var h = 0 while hasNext(t, h): let (a, b, h2) = next(t, h) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 97c3a46c55..491235d8b8 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -124,7 +124,7 @@ type NimIdent* {.deprecated.} = object of RootObj ## Represents a Nim identifier in the AST. **Note**: This is only ## rarely useful, for identifier construction from a string - ## use ``ident"abc"``. + ## use `ident"abc"`. NimSymObj = object # hidden NimSym* {.deprecated.} = ref NimSymObj @@ -175,7 +175,7 @@ proc `[]`*(n: NimNode, i: BackwardsIndex): NimNode = n[n.len - i.int] template `^^`(n: NimNode, i: untyped): untyped = (when i is BackwardsIndex: n.len - int(i) else: int(i)) -proc `[]`*[T, U](n: NimNode, x: HSlice[T, U]): seq[NimNode] = +proc `[]`*[T, U: Ordinal](n: NimNode, x: HSlice[T, U]): seq[NimNode] = ## Slice operation for NimNode. ## Returns a seq of child of `n` who inclusive range [n[x.a], n[x.b]]. let xa = n ^^ x.a @@ -193,8 +193,8 @@ proc `[]=`*(n: NimNode, i: BackwardsIndex, child: NimNode) = n[n.len - i.int] = child template `or`*(x, y: NimNode): NimNode = - ## Evaluate ``x`` and when it is not an empty node, return - ## it. Otherwise evaluate to ``y``. Can be used to chain several + ## Evaluate `x` and when it is not an empty node, return + ## it. Otherwise evaluate to `y`. Can be used to chain several ## expressions to get the first expression that is not empty. ## ## .. code-block:: nim @@ -229,7 +229,17 @@ proc intVal*(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect.} proc floatVal*(n: NimNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.} ## Returns a float from any floating point literal. -{.push warnings: off.} + +proc symKind*(symbol: NimNode): NimSymKind {.magic: "NSymKind", noSideEffect.} +proc getImpl*(symbol: NimNode): NimNode {.magic: "GetImpl", noSideEffect.} + ## Returns a copy of the declaration of a symbol or `nil`. +proc strVal*(n: NimNode): string {.magic: "NStrVal", noSideEffect.} + ## Returns the string value of an identifier, symbol, comment, or string literal. + ## + ## See also: + ## * `strVal= proc<#strVal=,NimNode,string>`_ for setting the string value. + +{.push warnings: off.} # silence `deprecated` proc ident*(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect, deprecated: "Deprecated since version 0.18.1; All functionality is defined on 'NimNode'.".} @@ -239,41 +249,13 @@ proc symbol*(n: NimNode): NimSym {.magic: "NSymbol", noSideEffect, deprecated: proc getImpl*(s: NimSym): NimNode {.magic: "GetImpl", noSideEffect, deprecated: "use `getImpl: NimNode -> NimNode` instead".} -when defined(nimSymKind): - proc symKind*(symbol: NimNode): NimSymKind {.magic: "NSymKind", noSideEffect.} - proc getImpl*(symbol: NimNode): NimNode {.magic: "GetImpl", noSideEffect.} - ## Returns a copy of the declaration of a symbol or `nil`. - proc strVal*(n: NimNode): string {.magic: "NStrVal", noSideEffect.} - ## Returns the string value of an identifier, symbol, comment, or string literal. - ## - ## See also: - ## * `strVal= proc<#strVal=,NimNode,string>`_ for setting the string value. +proc `$`*(i: NimIdent): string {.magic: "NStrVal", noSideEffect, deprecated: + "Deprecated since version 0.18.1; Use 'strVal' instead.".} + ## Converts a Nim identifier to a string. - proc `$`*(i: NimIdent): string {.magic: "NStrVal", noSideEffect, deprecated: - "Deprecated since version 0.18.1; Use 'strVal' instead.".} - ## Converts a Nim identifier to a string. - - proc `$`*(s: NimSym): string {.magic: "NStrVal", noSideEffect, deprecated: - "Deprecated since version 0.18.1; Use 'strVal' instead.".} - ## Converts a Nim symbol to a string. - -else: # bootstrapping substitute - proc getImpl*(symbol: NimNode): NimNode = - symbol.symbol.getImpl - - proc strValOld(n: NimNode): string {.magic: "NStrVal", noSideEffect.} - - proc `$`*(s: NimSym): string {.magic: "IdentToStr", noSideEffect.} - - proc `$`*(i: NimIdent): string {.magic: "IdentToStr", noSideEffect.} - - proc strVal*(n: NimNode): string = - if n.kind == nnkIdent: - $n.ident - elif n.kind == nnkSym: - $n.symbol - else: - n.strValOld +proc `$`*(s: NimSym): string {.magic: "NStrVal", noSideEffect, deprecated: + "Deprecated since version 0.18.1; Use 'strVal' instead.".} + ## Converts a Nim symbol to a string. {.pop.} @@ -284,23 +266,21 @@ when (NimMajor, NimMinor, NimPatch) >= (1, 3, 5) or defined(nimSymImplTransform) ## note that code transformations are implementation dependent and subject to change. ## See an example in `tests/macros/tmacros_various.nim`. -when defined(nimHasSymOwnerInMacro): - proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.} - ## Accepts a node of kind `nnkSym` and returns its owner's symbol. - ## The meaning of 'owner' depends on `sym`'s `NimSymKind` and declaration - ## context. For top level declarations this is an `nskModule` symbol, - ## for proc local variables an `nskProc` symbol, for enum/object fields an - ## `nskType` symbol, etc. For symbols without an owner, `nil` is returned. - ## - ## See also: - ## * `symKind proc<#symKind,NimNode>`_ to get the kind of a symbol - ## * `getImpl proc<#getImpl,NimNode>`_ to get the declaration of a symbol +proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.} + ## Accepts a node of kind `nnkSym` and returns its owner's symbol. + ## The meaning of 'owner' depends on `sym`'s `NimSymKind` and declaration + ## context. For top level declarations this is an `nskModule` symbol, + ## for proc local variables an `nskProc` symbol, for enum/object fields an + ## `nskType` symbol, etc. For symbols without an owner, `nil` is returned. + ## + ## See also: + ## * `symKind proc<#symKind,NimNode>`_ to get the kind of a symbol + ## * `getImpl proc<#getImpl,NimNode>`_ to get the declaration of a symbol -when defined(nimHasInstantiationOfInMacro): - proc isInstantiationOf*(instanceProcSym, genProcSym: NimNode): bool {.magic: "SymIsInstantiationOf", noSideEffect.} - ## Checks if a proc symbol is an instance of the generic proc symbol. - ## Useful to check proc symbols against generic symbols - ## returned by `bindSym`. +proc isInstantiationOf*(instanceProcSym, genProcSym: NimNode): bool {.magic: "SymIsInstantiationOf", noSideEffect.} + ## Checks if a proc symbol is an instance of the generic proc symbol. + ## Useful to check proc symbols against generic symbols + ## returned by `bindSym`. proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} ## With 'getType' you can access the node's `type`:idx:. A Nim type is @@ -311,11 +291,11 @@ proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} ## kind of type it is, call `typeKind` on getType's result. proc getType*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.} - ## Version of ``getType`` which takes a ``typedesc``. + ## Version of `getType` which takes a `typedesc`. proc typeKind*(n: NimNode): NimTypeKind {.magic: "NGetType", noSideEffect.} ## Returns the type kind of the node 'n' that should represent a type, that - ## means the node should have been obtained via ``getType``. + ## means the node should have been obtained via `getType`. proc getTypeInst*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} = ## Returns the `type`:idx: of a node in a form matching the way the @@ -336,12 +316,12 @@ proc getTypeInst*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} = doAssert(dumpTypeInst(c) == "Vec[4, float32]") proc getTypeInst*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.} - ## Version of ``getTypeInst`` which takes a ``typedesc``. + ## Version of `getTypeInst` which takes a `typedesc`. proc getTypeImpl*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} = ## Returns the `type`:idx: of a node in a form matching the implementation ## of the type. Any intermediate aliases are expanded to arrive at the final - ## type implementation. You can instead use ``getImpl`` on a symbol if you + ## type implementation. You can instead use `getImpl` on a symbol if you ## want to find the intermediate aliases. runnableExamples: type @@ -362,12 +342,11 @@ object doAssert(dumpTypeImpl(b) == t) doAssert(dumpTypeImpl(c) == t) -when defined(nimHasSignatureHashInMacro): - proc signatureHash*(n: NimNode): string {.magic: "NSigHash", noSideEffect.} - ## Returns a stable identifier derived from the signature of a symbol. - ## The signature combines many factors such as the type of the symbol, - ## the owning module of the symbol and others. The same identifier is - ## used in the back-end to produce the mangled symbol name. +proc signatureHash*(n: NimNode): string {.magic: "NSigHash", noSideEffect.} + ## Returns a stable identifier derived from the signature of a symbol. + ## The signature combines many factors such as the type of the symbol, + ## the owning module of the symbol and others. The same identifier is + ## used in the back-end to produce the mangled symbol name. proc symBodyHash*(s: NimNode): string {.noSideEffect.} = ## Returns a stable digest for symbols derived not only from type signature @@ -377,7 +356,7 @@ proc symBodyHash*(s: NimNode): string {.noSideEffect.} = discard proc getTypeImpl*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.} - ## Version of ``getTypeImpl`` which takes a ``typedesc``. + ## Version of `getTypeImpl` which takes a `typedesc`. proc `intVal=`*(n: NimNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.} proc `floatVal=`*(n: NimNode, val: BiggestFloat) {.magic: "NSetFloatVal", noSideEffect.} @@ -407,7 +386,7 @@ proc newNimNode*(kind: NimNodeKind, {.magic: "NNewNimNode", noSideEffect.} ## Creates a new AST node of the specified kind. ## - ## The ``lineInfoFrom`` parameter is used for line information when the + ## The `lineInfoFrom` parameter is used for line information when the ## produced code crashes. You should ensure that it is set to a node that ## you are transforming. @@ -415,7 +394,7 @@ proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.} proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.} proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign.} - ## Writes an error message at compile time. The optional ``n: NimNode`` + ## Writes an error message at compile time. The optional `n: NimNode` ## parameter is used as the source for file and line number information in ## the compilation error message. @@ -456,13 +435,13 @@ proc newIdentNode*(i: NimIdent): NimNode {.compileTime, deprecated.} = proc newIdentNode*(i: string): NimNode {.magic: "StrToIdent", noSideEffect.} ## Creates an identifier node from `i`. It is simply an alias for - ## ``ident(string)``. Use that, it's shorter. + ## `ident(string)`. Use that, it's shorter. proc ident*(name: string): NimNode {.magic: "StrToIdent", noSideEffect.} ## Create a new ident node from a string. type - BindSymRule* = enum ## specifies how ``bindSym`` behaves + BindSymRule* = enum ## specifies how `bindSym` behaves brClosed, ## only the symbols in current scope are bound brOpen, ## open wrt overloaded symbols, but may be a single ## symbol if not ambiguous (the rules match that of @@ -475,12 +454,12 @@ proc bindSym*(ident: string | NimNode, rule: BindSymRule = brClosed): NimNode {. magic: "NBindSym", noSideEffect.} ## Creates a node that binds `ident` to a symbol node. The bound symbol ## may be an overloaded symbol. - ## if `ident` is a NimNode, it must have ``nnkIdent`` kind. - ## If ``rule == brClosed`` either an ``nnkClosedSymChoice`` tree is - ## returned or ``nnkSym`` if the symbol is not ambiguous. - ## If ``rule == brOpen`` either an ``nnkOpenSymChoice`` tree is - ## returned or ``nnkSym`` if the symbol is not ambiguous. - ## If ``rule == brForceOpen`` always an ``nnkOpenSymChoice`` tree is + ## if `ident` is a NimNode, it must have `nnkIdent` kind. + ## If `rule == brClosed` either an `nnkClosedSymChoice` tree is + ## returned or `nnkSym` if the symbol is not ambiguous. + ## If `rule == brOpen` either an `nnkOpenSymChoice` tree is + ## returned or `nnkSym` if the symbol is not ambiguous. + ## If `rule == brForceOpen` always an `nnkOpenSymChoice` tree is ## returned even if the symbol is not ambiguous. ## ## Experimental feature: @@ -523,10 +502,10 @@ proc getColumn(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.} proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.} proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffect.} - ## Copy lineinfo from ``info``. + ## Copy lineinfo from `info`. proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} = - ## Returns ``LineInfo`` of ``n``, using absolute path for ``filename``. + ## Returns `LineInfo` of `n`, using absolute path for `filename`. result = LineInfo(filename: n.getFile, line: n.getLine, column: n.getColumn) proc lineInfo*(arg: NimNode): string {.compileTime.} = @@ -545,14 +524,14 @@ proc internalErrorFlag*(): string {.magic: "NError", noSideEffect.} proc parseExpr*(s: string): NimNode {.noSideEffect, compileTime.} = ## Compiles the passed string to its AST representation. - ## Expects a single expression. Raises ``ValueError`` for parsing errors. + ## Expects a single expression. Raises `ValueError` for parsing errors. result = internalParseExpr(s) let x = internalErrorFlag() if x.len > 0: raise newException(ValueError, x) proc parseStmt*(s: string): NimNode {.noSideEffect, compileTime.} = ## Compiles the passed string to its AST representation. - ## Expects one or more statements. Raises ``ValueError`` for parsing errors. + ## Expects one or more statements. Raises `ValueError` for parsing errors. result = internalParseStmt(s) let x = internalErrorFlag() if x.len > 0: raise newException(ValueError, x) @@ -566,34 +545,86 @@ proc getAst*(macroOrTemplate: untyped): NimNode {.magic: "ExpandToAst", noSideEf ## macro FooMacro() = ## var ast = getAst(BarTemplate()) -proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.} +proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.} = ## Quasi-quoting operator. ## Accepts an expression or a block and returns the AST that represents it. ## Within the quoted AST, you are able to interpolate NimNode expressions ## from the surrounding scope. If no operator is given, quoting is done using ## backticks. Otherwise, the given operator must be used as a prefix operator - ## for any interpolated expression. + ## for any interpolated expression. The original meaning of the interpolation + ## operator may be obtained by escaping it (by prefixing it with itself) when used + ## as a unary operator: + ## e.g. `@` is escaped as `@@`, `&%` is escaped as `&%&%` and so on; see examples. ## - ## Example: - ## - ## .. code-block:: nim - ## - ## macro check(ex: untyped) = - ## # this is a simplified version of the check macro from the - ## # unittest module. - ## - ## # If there is a failed check, we want to make it easy for - ## # the user to jump to the faulty line in the code, so we - ## # get the line info here: - ## var info = ex.lineinfo - ## - ## # We will also display the code string of the failed check: - ## var expString = ex.toStrLit - ## - ## # Finally we compose the code to implement the check: - ## result = quote do: - ## if not `ex`: - ## echo `info` & ": Check failed: " & `expString` + ## A custom operator interpolation needs accent quoted (``) whenever it resolves + ## to a symbol. + runnableExamples: + macro check(ex: untyped) = + # this is a simplified version of the check macro from the + # unittest module. + + # If there is a failed check, we want to make it easy for + # the user to jump to the faulty line in the code, so we + # get the line info here: + var info = ex.lineinfo + + # We will also display the code string of the failed check: + var expString = ex.toStrLit + + # Finally we compose the code to implement the check: + result = quote do: + if not `ex`: + echo `info` & ": Check failed: " & `expString` + check 1 + 1 == 2 + + runnableExamples: + # example showing how to define a symbol that requires backtick without + # quoting it. + 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 + + runnableExamples: + # custom `op` + var destroyCalled = 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]" + destroyCalled = true + block: + let a = Foo() + bar(someident) + doAssert destroyCalled + + 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() proc expectKind*(n: NimNode, k: NimNodeKind) {.compileTime.} = ## Checks that `n` is of kind `k`. If this is not the case, @@ -614,7 +645,7 @@ proc expectLen*(n: NimNode, len: int) {.compileTime.} = if n.len != len: error("Expected a node with " & $len & " children, got " & $n.len, n) proc expectLen*(n: NimNode, min, max: int) {.compileTime.} = - ## Checks that `n` has a number of children in the range ``min..max``. + ## Checks that `n` has a number of children in the range `min..max`. ## If this is not the case, compilation aborts with an error message. ## This is useful for writing macros that check its number of arguments. if n.len < min or n.len > max: @@ -629,7 +660,7 @@ proc newTree*(kind: NimNodeKind, proc newCall*(theProc: NimNode, args: varargs[NimNode]): NimNode {.compileTime.} = ## Produces a new call node. `theProc` is the proc that is called with - ## the arguments ``args[0..]``. + ## the arguments `args[0..]`. result = newNimNode(nnkCall) result.add(theProc) result.add(args) @@ -639,7 +670,7 @@ proc newCall*(theProc: NimNode, proc newCall*(theProc: NimIdent, args: varargs[NimNode]): NimNode {.compileTime, deprecated: "Deprecated since v0.18.1; use 'newCall(string, ...)' or 'newCall(NimNode, ...)' instead".} = ## Produces a new call node. `theProc` is the proc that is called with - ## the arguments ``args[0..]``. + ## the arguments `args[0..]`. result = newNimNode(nnkCall) result.add(newIdentNode(theProc)) result.add(args) @@ -649,7 +680,7 @@ proc newCall*(theProc: NimIdent, args: varargs[NimNode]): NimNode {.compileTime, proc newCall*(theProc: string, args: varargs[NimNode]): NimNode {.compileTime.} = ## Produces a new call node. `theProc` is the proc that is called with - ## the arguments ``args[0..]``. + ## the arguments `args[0..]`. result = newNimNode(nnkCall) result.add(newIdentNode(theProc)) result.add(args) @@ -743,7 +774,7 @@ when declared(float128): proc newLit*(arg: enum): NimNode {.compileTime.} = result = newCall( - arg.type.getTypeInst[1], + arg.typeof.getTypeInst[1], newLit(int(arg)) ) @@ -753,13 +784,13 @@ proc newLit*[T](s: set[T]): NimNode {.compileTime.} proc newLit*[T: tuple](arg: T): NimNode {.compileTime.} proc newLit*(arg: object): NimNode {.compileTime.} = - result = nnkObjConstr.newTree(arg.type.getTypeInst[1]) + result = nnkObjConstr.newTree(arg.typeof.getTypeInst[1]) for a, b in arg.fieldPairs: result.add nnkExprColonExpr.newTree( newIdentNode(a), newLit(b) ) proc newLit*(arg: ref object): NimNode {.compileTime.} = ## produces a new ref type literal node. - result = nnkObjConstr.newTree(arg.type.getTypeInst[1]) + result = nnkObjConstr.newTree(arg.typeof.getTypeInst[1]) for a, b in fieldPairs(arg[]): result.add nnkExprColonExpr.newTree(newIdentNode(a), newLit(b)) @@ -806,7 +837,7 @@ proc newLit*[T: tuple](arg: T): NimNode {.compileTime.} = proc nestList*(op: NimNode; pack: NimNode): NimNode {.compileTime.} = ## Nests the list `pack` into a tree of call expressions: - ## ``[a, b, c]`` is transformed into ``op(a, op(c, d))``. + ## `[a, b, c]` is transformed into `op(a, op(c, d))`. ## This is also known as fold expression. if pack.len < 1: error("`nestList` expects a node with at least 1 child") @@ -816,7 +847,7 @@ proc nestList*(op: NimNode; pack: NimNode): NimNode {.compileTime.} = proc nestList*(op: NimNode; pack: NimNode; init: NimNode): NimNode {.compileTime.} = ## Nests the list `pack` into a tree of call expressions: - ## ``[a, b, c]`` is transformed into ``op(a, op(c, d))``. + ## `[a, b, c]` is transformed into `op(a, op(c, d))`. ## This is also known as fold expression. result = init for i in countdown(pack.len - 1, 0): @@ -864,16 +895,16 @@ proc treeRepr*(n: NimNode): string {.compileTime, benign.} = n.treeTraverse(result, isLisp = false, indented = true) proc lispRepr*(n: NimNode; indented = false): string {.compileTime, benign.} = - ## Convert the AST ``n`` to a human-readable lisp-like string. + ## Convert the AST `n` to a human-readable lisp-like string. ## - ## See also ``repr``, ``treeRepr``, and ``astGenRepr``. + ## See also `repr`, `treeRepr`, and `astGenRepr`. result = "" n.treeTraverse(result, isLisp = true, indented = indented) proc astGenRepr*(n: NimNode): string {.compileTime, benign.} = - ## Convert the AST ``n`` to the code required to generate that AST. + ## Convert the AST `n` to the code required to generate that AST. ## - ## See also ``repr``, ``treeRepr``, and ``lispRepr``. + ## See also `repr`, `treeRepr`, and `lispRepr`. const NodeKinds = {nnkEmpty, nnkIdent, nnkSym, nnkNone, nnkCommentStmt} @@ -918,7 +949,7 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} = macro dumpTree*(s: untyped): untyped = echo s.treeRepr ## Accepts a block of nim code and prints the parsed abstract syntax - ## tree using the ``treeRepr`` proc. Printing is done *at compile time*. + ## tree using the `treeRepr` proc. Printing is done *at compile time*. ## ## You can use this as a tool to explore the Nim's abstract syntax ## tree and to discover what kind of nodes must be created to represent @@ -938,11 +969,11 @@ macro dumpTree*(s: untyped): untyped = echo s.treeRepr ## Ident "echo" ## StrLit "Hello, World!" ## - ## Also see ``dumpAstGen`` and ``dumpLisp``. + ## Also see `dumpAstGen` and `dumpLisp`. macro dumpLisp*(s: untyped): untyped = echo s.lispRepr(indented = true) ## Accepts a block of nim code and prints the parsed abstract syntax - ## tree using the ``lispRepr`` proc. Printing is done *at compile time*. + ## tree using the `lispRepr` proc. Printing is done *at compile time*. ## ## You can use this as a tool to explore the Nim's abstract syntax ## tree and to discover what kind of nodes must be created to represent @@ -962,11 +993,11 @@ macro dumpLisp*(s: untyped): untyped = echo s.lispRepr(indented = true) ## (Ident "echo") ## (StrLit "Hello, World!"))) ## - ## Also see ``dumpAstGen`` and ``dumpTree``. + ## Also see `dumpAstGen` and `dumpTree`. macro dumpAstGen*(s: untyped): untyped = echo s.astGenRepr ## Accepts a block of nim code and prints the parsed abstract syntax - ## tree using the ``astGenRepr`` proc. Printing is done *at compile time*. + ## tree using the `astGenRepr` proc. Printing is done *at compile time*. ## ## You can use this as a tool to write macros quicker by writing example ## outputs and then copying the snippets into the macro for modification. @@ -987,7 +1018,7 @@ macro dumpAstGen*(s: untyped): untyped = echo s.astGenRepr ## ) ## ) ## - ## Also see ``dumpTree`` and ``dumpLisp``. + ## Also see `dumpTree` and `dumpLisp`. proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} = ## Create a new empty node. @@ -1039,15 +1070,15 @@ proc newColonExpr*(a, b: NimNode): NimNode {.compileTime.} = proc newIdentDefs*(name, kind: NimNode; default = newEmptyNode()): NimNode {.compileTime.} = - ## Creates a new ``nnkIdentDefs`` node of a specific kind and value. + ## Creates a new `nnkIdentDefs` node of a specific kind and value. ## - ## ``nnkIdentDefs`` need to have at least three children, but they can have + ## `nnkIdentDefs` need to have at least three children, but they can have ## more: first comes a list of identifiers followed by a type and value ## nodes. This helper proc creates a three node subtree, the first subnode - ## being a single identifier name. Both the ``kind`` node and ``default`` - ## (value) nodes may be empty depending on where the ``nnkIdentDefs`` - ## appears: tuple or object definitions will have an empty ``default`` node, - ## ``let`` or ``var`` blocks may have an empty ``kind`` node if the + ## being a single identifier name. Both the `kind` node and `default` + ## (value) nodes may be empty depending on where the `nnkIdentDefs` + ## appears: tuple or object definitions will have an empty `default` node, + ## `let` or `var` blocks may have an empty `kind` node if the ## identifier is being assigned a value. Example: ## ## .. code-block:: nim @@ -1060,7 +1091,7 @@ proc newIdentDefs*(name, kind: NimNode; ## # b = 3 ## ## If you need to create multiple identifiers you need to use the lower level - ## ``newNimNode``: + ## `newNimNode`: ## ## .. code-block:: nim ## @@ -1097,7 +1128,7 @@ proc newProc*(name = newEmptyNode(); pragmas: NimNode = newEmptyNode()): NimNode {.compileTime.} = ## Shortcut for creating a new proc. ## - ## The ``params`` array must start with the return type of the proc, + ## The `params` array must start with the return type of the proc, ## followed by a list of IdentDefs which specify the params. if procType notin RoutineNodes: error("Expected one of " & $RoutineNodes & ", got " & $procType) @@ -1113,7 +1144,7 @@ proc newProc*(name = newEmptyNode(); proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]): NimNode {.compileTime.} = - ## Constructor for ``if`` statements. + ## Constructor for `if` statements. ## ## .. code-block:: nim ## @@ -1273,17 +1304,17 @@ proc `$`*(node: NimNode): string {.compileTime.} = badNodeKind node, "$" iterator items*(n: NimNode): NimNode {.inline.} = - ## Iterates over the children of the NimNode ``n``. + ## Iterates over the children of the NimNode `n`. for i in 0 ..< n.len: yield n[i] iterator pairs*(n: NimNode): (int, NimNode) {.inline.} = - ## Iterates over the children of the NimNode ``n`` and its indices. + ## Iterates over the children of the NimNode `n` and its indices. for i in 0 ..< n.len: yield (i, n[i]) iterator children*(n: NimNode): NimNode {.inline.} = - ## Iterates over the children of the NimNode ``n``. + ## Iterates over the children of the NimNode `n`. for i in 0 ..< n.len: yield n[i] @@ -1302,7 +1333,7 @@ template findChild*(n: NimNode; cond: untyped): NimNode {.dirty.} = res proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} = - ## Insert node ``b`` into node ``a`` at ``pos``. + ## Insert node `b` into node `a` at `pos`. if len(a)-1 < pos: # add some empty nodes first for i in len(a)-1..pos-2: @@ -1366,73 +1397,36 @@ proc copy*(node: NimNode): NimNode {.compileTime.} = ## An alias for `copyNimTree<#copyNimTree,NimNode>`_. return node.copyNimTree() -when defined(nimVmEqIdent): - proc eqIdent*(a: string; b: string): bool {.magic: "EqIdent", noSideEffect.} - ## Style insensitive comparison. +proc eqIdent*(a: string; b: string): bool {.magic: "EqIdent", noSideEffect.} + ## Style insensitive comparison. - proc eqIdent*(a: NimNode; b: string): bool {.magic: "EqIdent", noSideEffect.} - ## Style insensitive comparison. ``a`` can be an identifier or a - ## symbol. ``a`` may be wrapped in an export marker - ## (``nnkPostfix``) or quoted with backticks (``nnkAccQuoted``), - ## these nodes will be unwrapped. +proc eqIdent*(a: NimNode; b: string): bool {.magic: "EqIdent", noSideEffect.} + ## Style insensitive comparison. `a` can be an identifier or a + ## symbol. `a` may be wrapped in an export marker + ## (`nnkPostfix`) or quoted with backticks (`nnkAccQuoted`), + ## these nodes will be unwrapped. - proc eqIdent*(a: string; b: NimNode): bool {.magic: "EqIdent", noSideEffect.} - ## Style insensitive comparison. ``b`` can be an identifier or a - ## symbol. ``b`` may be wrapped in an export marker - ## (``nnkPostfix``) or quoted with backticks (``nnkAccQuoted``), - ## these nodes will be unwrapped. +proc eqIdent*(a: string; b: NimNode): bool {.magic: "EqIdent", noSideEffect.} + ## Style insensitive comparison. `b` can be an identifier or a + ## symbol. `b` may be wrapped in an export marker + ## (`nnkPostfix`) or quoted with backticks (`nnkAccQuoted`), + ## these nodes will be unwrapped. - proc eqIdent*(a: NimNode; b: NimNode): bool {.magic: "EqIdent", noSideEffect.} - ## Style insensitive comparison. ``a`` and ``b`` can be an - ## identifier or a symbol. Both may be wrapped in an export marker - ## (``nnkPostfix``) or quoted with backticks (``nnkAccQuoted``), - ## these nodes will be unwrapped. - -else: - # this procedure is optimized for native code, it should not be compiled to nimVM bytecode. - proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} = - proc toLower(c: char): char {.inline.} = - if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A'))) - else: result = c - var i = 0 - var j = 0 - # first char is case sensitive - if a[0] != b[0]: return 1 - while true: - while a[i] == '_': inc(i) - while b[j] == '_': inc(j) # BUGFIX: typo - var aa = toLower(a[i]) - var bb = toLower(b[j]) - result = ord(aa) - ord(bb) - if result != 0 or aa == '\0': break - inc(i) - inc(j) - - - proc eqIdent*(a, b: string): bool = cmpIgnoreStyle(a, b) == 0 - ## Check if two idents are equal. - - proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} = - ## Check if node is some identifier node (``nnkIdent``, ``nnkSym``, etc.) - ## is the same as ``s``. Note that this is the preferred way to check! Most - ## other ways like ``node.ident`` are much more error-prone, unfortunately. - case node.kind - of nnkSym, nnkIdent: - result = eqIdent(node.strVal, s) - of nnkOpenSymChoice, nnkClosedSymChoice: - result = eqIdent($node[0], s) - else: - result = false +proc eqIdent*(a: NimNode; b: NimNode): bool {.magic: "EqIdent", noSideEffect.} + ## Style insensitive comparison. `a` and `b` can be an + ## identifier or a symbol. Both may be wrapped in an export marker + ## (`nnkPostfix`) or quoted with backticks (`nnkAccQuoted`), + ## these nodes will be unwrapped. proc expectIdent*(n: NimNode, name: string) {.compileTime, since: (1,1).} = - ## Check that ``eqIdent(n,name)`` holds true. If this is not the + ## Check that `eqIdent(n,name)` holds true. If this is not the ## case, compilation aborts with an error message. This is useful ## for writing macros that check the AST that is passed to them. if not eqIdent(n, name): error("Expected identifier to be `" & name & "` here", n) proc hasArgOfName*(params: NimNode; name: string): bool {.compileTime.}= - ## Search ``nnkFormalParams`` for an argument. + ## Search `nnkFormalParams` for an argument. expectKind(params, nnkFormalParams) for i in 1..`_ module for an example of ## what this module allows you to do. ## -## Note that even though ``Any`` and its operations hide the nasty low level +## Note that even though `Any` and its operations hide the nasty low level ## details from its clients, it remains inherently unsafe! Also, Nim's ## runtime type information will evolve and may eventually be deprecated. ## As an alternative approach to programmatically understanding and @@ -28,10 +28,10 @@ include "system/hti.nim" {.pop.} type - AnyKind* = enum ## what kind of ``any`` it is + AnyKind* = enum ## what kind of `any` it is akNone = 0, ## invalid any - akBool = 1, ## any represents a ``bool`` - akChar = 2, ## any represents a ``char`` + akBool = 1, ## any represents a `bool` + akChar = 2, ## any represents a `char` akEnum = 14, ## any represents an enum akArray = 16, ## any represents an array akObject = 17, ## any represents an object @@ -63,7 +63,7 @@ type Any* = object ## can represent any nim value; NOTE: the wrapped ## value can be modified with its wrapper! This means - ## that ``Any`` keeps a non-traced pointer to its + ## that `Any` keeps a non-traced pointer to its ## wrapped value and **must not** live longer than ## its wrapped value. value: pointer @@ -91,6 +91,8 @@ when not defined(gcDestructors): else: include system/seqs_v2_reimpl +from std/private/strimpl import cmpNimIdentifier + when not defined(js): template rawType(x: Any): PNimType = cast[PNimType](x.rawTypePtr) @@ -132,7 +134,7 @@ proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode = if discr <% 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) + # n.sons[n.len] contains the `else` part (but may be nil) else: result = n.sons[n.len] @@ -142,17 +144,17 @@ proc newAny(value: pointer, rawType: PNimType): Any {.inline.} = when declared(system.VarSlot): proc toAny*(x: VarSlot): Any {.inline.} = - ## Constructs a ``Any`` object from a variable slot ``x``. + ## Constructs a `Any` object from a variable slot `x`. ## This captures `x`'s address, so `x` can be modified with its - ## ``Any`` wrapper! The client needs to ensure that the wrapper + ## `Any` wrapper! The client needs to ensure that the wrapper ## **does not** live longer than `x`! ## This is provided for easier reflection capabilities of a debugger. result.value = x.address result.rawType = x.typ proc toAny*[T](x: var T): Any {.inline.} = - ## Constructs a ``Any`` object from `x`. This captures `x`'s address, so - ## `x` can be modified with its ``Any`` wrapper! The client needs to ensure + ## Constructs a `Any` object from `x`. This captures `x`'s address, so + ## `x` can be modified with its `Any` wrapper! The client needs to ensure ## that the wrapper **does not** live longer than `x`! newAny(addr(x), cast[PNimType](getTypeInfo(x))) @@ -165,7 +167,7 @@ proc size*(x: Any): int {.inline.} = result = x.rawType.size proc baseTypeKind*(x: Any): AnyKind {.inline.} = - ## Gets the base type's kind; ``akNone`` is returned if `x` has no base type. + ## Gets the base type's kind; `akNone` is returned if `x` has no base type. if x.rawType.base != nil: result = AnyKind(ord(x.rawType.base.kind)) @@ -175,7 +177,7 @@ proc baseTypeSize*(x: Any): int {.inline.} = result = x.rawType.base.size proc invokeNew*(x: Any) = - ## Performs ``new(x)``. `x` needs to represent a ``ref``. + ## Performs `new(x)`. `x` needs to represent a `ref`. assert x.rawType.kind == tyRef when defined(gcDestructors): cast[ppointer](x.value)[] = nimNewObj(x.rawType.base.size, x.rawType.base.align) @@ -184,7 +186,7 @@ proc invokeNew*(x: Any) = genericAssign(x.value, addr(z), x.rawType) proc invokeNewSeq*(x: Any, len: int) = - ## Performs ``newSeq(x, len)``. `x` needs to represent a ``seq``. + ## Performs `newSeq(x, len)`. `x` needs to represent a `seq`. assert x.rawType.kind == tySequence when defined(gcDestructors): var s = cast[ptr NimSeqV2Reimpl](x.value) @@ -196,7 +198,7 @@ proc invokeNewSeq*(x: Any, len: int) = genericShallowAssign(x.value, addr(z), x.rawType) proc extendSeq*(x: Any) = - ## Performs ``setLen(x, x.len+1)``. `x` needs to represent a ``seq``. + ## Performs `setLen(x, x.len+1)`. `x` needs to represent a `seq`. assert x.rawType.kind == tySequence when defined(gcDestructors): var s = cast[ptr NimSeqV2Reimpl](x.value) @@ -316,16 +318,16 @@ const tySequence, tyProc} proc getPointer*(x: Any): pointer = - ## Retrieves the pointer value out of `x`. ``x`` needs to be of kind - ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, - ## ``akPointer``, ``akSequence``. + ## Retrieves the pointer value out of `x`. `x` needs to be of kind + ## `akString`, `akCString`, `akProc`, `akRef`, `akPtr`, + ## `akPointer`, `akSequence`. assert x.rawType.kind in pointerLike result = cast[ppointer](x.value)[] proc setPointer*(x: Any, y: pointer) = - ## Sets the pointer value of `x`. ``x`` needs to be of kind - ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, - ## ``akPointer``, ``akSequence``. + ## Sets the pointer value of `x`. `x` needs to be of kind + ## `akString`, `akCString`, `akProc`, `akRef`, `akPtr`, + ## `akPointer`, `akSequence`. assert x.rawType.kind in pointerLike if y != nil and x.rawType.kind != tyPointer: genericAssign(x.value, y, x.rawType) @@ -366,36 +368,19 @@ iterator fields*(x: Any): tuple[name: string, any: Any] = for name, any in items(ret): yield ($name, any) -proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} = - proc toLower(c: char): char {.inline.} = - if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A'))) - else: result = c - var i = 0 - var j = 0 - if a[0] != b[0]: return 1 - while true: - while a[i] == '_': inc(i) - while b[j] == '_': inc(j) # BUGFIX: typo - var aa = toLower(a[i]) - var bb = toLower(b[j]) - result = ord(aa) - ord(bb) - if result != 0 or aa == '\0': break - inc(i) - inc(j) - proc getFieldNode(p: pointer, n: ptr TNimNode, name: cstring): ptr TNimNode = case n.kind of nkNone: assert(false) of nkSlot: - if cmpIgnoreStyle(n.name, name) == 0: + if cmpNimIdentifier(n.name, name) == 0: result = n of nkList: for i in 0..n.len-1: result = getFieldNode(p, n.sons[i], name) if result != nil: break of nkCase: - if cmpIgnoreStyle(n.name, name) == 0: + if cmpNimIdentifier(n.name, name) == 0: result = n else: var m = selectBranch(p, n) @@ -471,7 +456,7 @@ proc getInt64*(x: Any): int64 = proc getBiggestInt*(x: Any): BiggestInt = ## Retrieves the integer value out of `x`. `x` needs to represent ## some integer, a bool, a char, an enum or a small enough bit set. - ## The value might be sign-extended to ``BiggestInt``. + ## The value might be sign-extended to `BiggestInt`. var t = skipRange(x.rawType) case t.kind of tyInt: result = BiggestInt(cast[ptr int](x.value)[]) @@ -593,13 +578,13 @@ proc skipRange*(x: Any): Any = proc getEnumOrdinal*(x: Any, name: string): int = ## Gets the enum field ordinal from `name`. `x` needs to represent an enum ## but is only used to access the type information. In case of an error - ## ``low(int)`` is returned. + ## `low(int)` is returned. var typ = skipRange(x.rawType) assert typ.kind == tyEnum var n = typ.node var s = n.sons for i in 0 .. n.len-1: - if cmpIgnoreStyle($s[i].name, name) == 0: + if cmpNimIdentifier($s[i].name, name) == 0: if ntfEnumHole notin typ.flags: return i else: @@ -645,7 +630,7 @@ proc getFloat64*(x: Any): float64 = proc getBiggestFloat*(x: Any): BiggestFloat = ## Retrieves the float value out of `x`. `x` needs to represent - ## some float. The value is extended to ``BiggestFloat``. + ## some float. The value is extended to `BiggestFloat`. case skipRange(x.rawType).kind of tyFloat: result = BiggestFloat(cast[ptr float](x.value)[]) of tyFloat32: result = BiggestFloat(cast[ptr float32](x.value)[]) @@ -681,7 +666,7 @@ proc getCString*(x: Any): cstring = result = cast[ptr cstring](x.value)[] proc assign*(x, y: Any) = - ## Copies the value of `y` to `x`. The assignment operator for ``Any`` + ## Copies the value of `y` to `x`. The assignment operator for `Any` ## does NOT do this; it performs a shallow copy instead! assert y.rawType == x.rawType genericAssign(x.value, y.value, y.rawType) diff --git a/lib/deprecated/pure/events.nim b/lib/deprecated/pure/events.nim index d2a8dd085b..218cb45d57 100644 --- a/lib/deprecated/pure/events.nim +++ b/lib/deprecated/pure/events.nim @@ -12,7 +12,7 @@ ## Unstable API. ## ## This module implements an event system that is not dependent on external -## graphical toolkits. It was originally called ``NimEE`` because +## graphical toolkits. It was originally called `NimEE` because ## it was inspired by Python's PyEE module. There are two ways you can use ## events: one is a python-inspired way; the other is more of a C-style way. ## diff --git a/lib/deprecated/pure/ospaths.nim b/lib/deprecated/pure/ospaths.nim index 34d452fd2b..6c7fe4fb30 100644 --- a/lib/deprecated/pure/ospaths.nim +++ b/lib/deprecated/pure/ospaths.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -## This module is deprecated, ``import os`` instead. +## This module is deprecated, `import os` instead. {.deprecated: "import os.nim instead".} import os diff --git a/lib/deprecated/pure/parseopt2.nim b/lib/deprecated/pure/parseopt2.nim index e57b7e2c90..a6d5de06df 100644 --- a/lib/deprecated/pure/parseopt2.nim +++ b/lib/deprecated/pure/parseopt2.nim @@ -13,8 +13,8 @@ ## ## Supported syntax: ## -## 1. short options - ``-abcd``, where a, b, c, d are names -## 2. long option - ``--foo:bar``, ``--foo=bar`` or ``--foo`` +## 1. short options - `-abcd`, where a, b, c, d are names +## 2. long option - `--foo:bar`, `--foo=bar` or `--foo` ## 3. argument - everything else {.deprecated: "Use the 'parseopt' module instead".} @@ -29,16 +29,16 @@ type CmdLineKind* = enum ## the detected command line token cmdEnd, ## end of command line reached cmdArgument, ## argument detected - cmdLongOption, ## a long option ``--option`` detected - cmdShortOption ## a short option ``-c`` detected + cmdLongOption, ## a long option `--option` detected + cmdShortOption ## a short option `-c` detected OptParser* = object of RootObj ## this object implements the command line parser cmd: seq[string] pos: int remainingShortOptions: string kind*: CmdLineKind ## the detected command line token - key*, val*: TaintedString ## key and value pair; ``key`` is the option - ## or the argument, ``value`` is not "" if + key*, val*: string ## key and value pair; `key` is the option + ## or the argument, `value` is not "" if ## the option was given a value proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} = @@ -80,7 +80,7 @@ proc nextOption(p: var OptParser, token: string, allowEmpty: bool) = proc next(p: var OptParser) = if p.remainingShortOptions.len != 0: p.kind = cmdShortOption - p.key = TaintedString(p.remainingShortOptions[0..0]) + p.key = p.remainingShortOptions[0..0] p.val = "" p.remainingShortOptions = p.remainingShortOptions[1..p.remainingShortOptions.len-1] return @@ -103,13 +103,13 @@ proc next(p: var OptParser) = p.key = token p.val = "" -proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo2$1".} = +proc cmdLineRest*(p: OptParser): string {.rtl, extern: "npo2$1".} = ## Returns the part of command line string that has not been parsed yet, ## properly quoted. return p.cmd[p.pos..p.cmd.len-1].quoteShellCommand type - GetoptResult* = tuple[kind: CmdLineKind, key, val: TaintedString] + GetoptResult* = tuple[kind: CmdLineKind, key, val: string] iterator getopt*(p: var OptParser): GetoptResult = ## This is an convenience iterator for iterating over the given OptParser object. diff --git a/lib/deprecated/pure/securehash.nim b/lib/deprecated/pure/securehash.nim index c6cde599aa..2f4530d889 100644 --- a/lib/deprecated/pure/securehash.nim +++ b/lib/deprecated/pure/securehash.nim @@ -1,6 +1,6 @@ -## This module is a deprecated alias for the ``sha1`` module. +## This module is a deprecated alias for the `sha1` module. {.deprecated.} include "../std/sha1" diff --git a/lib/experimental/diff.nim b/lib/experimental/diff.nim index 9a92aba726..1db8914409 100644 --- a/lib/experimental/diff.nim +++ b/lib/experimental/diff.nim @@ -10,14 +10,14 @@ ## This module implements an algorithm to compute the ## `diff`:idx: between two sequences of lines. ## -## A basic example of ``diffInt`` on 2 arrays of integers: +## A basic example of `diffInt` on 2 arrays of integers: ## ## .. code::nim ## ## import experimental/diff ## echo diffInt([0, 1, 2, 3, 4, 5, 6, 7, 8], [-1, 1, 2, 3, 4, 5, 666, 7, 42]) ## -## Another short example of ``diffText`` to diff strings: +## Another short example of `diffText` to diff strings: ## ## .. code::nim ## @@ -59,7 +59,7 @@ type Smsrd = object x, y: int -# template to avoid a seq copy. Required until ``sink`` parameters are ready. +# template to avoid a seq copy. Required until `sink` parameters are ready. template newDiffData(initData: seq[int]; L: int): DiffData = DiffData( data: initData, @@ -71,9 +71,9 @@ proc len(d: DiffData): int {.inline.} = d.data.len proc diffCodes(aText: string; h: var Table[string, int]): DiffData = ## This function converts all textlines of the text into unique numbers for every unique textline ## so further work can work only with simple numbers. - ## ``aText`` the input text - ## ``h`` This extern initialized hashtable is used for storing all ever used textlines. - ## ``trimSpace`` ignore leading and trailing space characters + ## `aText` the input text + ## `h` This extern initialized hashtable is used for storing all ever used textlines. + ## `trimSpace` ignore leading and trailing space characters ## Returns a array of integers. var lastUsedCode = h.len result.data = newSeq[int]() @@ -108,14 +108,14 @@ proc optimize(data: var DiffData) = proc sms(dataA: var DiffData; lowerA, upperA: int; dataB: DiffData; lowerB, upperB: int; downVector, upVector: var openArray[int]): Smsrd = ## This is the algorithm to find the Shortest Middle Snake (sms). - ## ``dataA`` sequence A - ## ``lowerA`` lower bound of the actual range in dataA - ## ``upperA`` upper bound of the actual range in dataA (exclusive) - ## ``dataB`` sequence B - ## ``lowerB`` lower bound of the actual range in dataB - ## ``upperB`` upper bound of the actual range in dataB (exclusive) - ## ``downVector`` a vector for the (0,0) to (x,y) search. Passed as a parameter for speed reasons. - ## ``upVector`` a vector for the (u,v) to (N,M) search. Passed as a parameter for speed reasons. + ## `dataA` sequence A + ## `lowerA` lower bound of the actual range in dataA + ## `upperA` upper bound of the actual range in dataA (exclusive) + ## `dataB` sequence B + ## `lowerB` lower bound of the actual range in dataB + ## `upperB` upper bound of the actual range in dataB (exclusive) + ## `downVector` a vector for the (0,0) to (x,y) search. Passed as a parameter for speed reasons. + ## `upVector` a vector for the (u,v) to (N,M) search. Passed as a parameter for speed reasons. ## Returns a MiddleSnakeData record containing x,y and u,v. let max = dataA.len + dataB.len + 1 @@ -195,14 +195,14 @@ proc lcs(dataA: var DiffData; lowerA, upperA: int; dataB: var DiffData; lowerB, ## algorithm. ## The published algorithm passes recursively parts of the A and B sequences. ## To avoid copying these arrays the lower and upper bounds are passed while the sequences stay constant. - ## ``dataA`` sequence A - ## ``lowerA`` lower bound of the actual range in dataA - ## ``upperA`` upper bound of the actual range in dataA (exclusive) - ## ``dataB`` sequence B - ## ``lowerB`` lower bound of the actual range in dataB - ## ``upperB`` upper bound of the actual range in dataB (exclusive) - ## ``downVector`` a vector for the (0,0) to (x,y) search. Passed as a parameter for speed reasons. - ## ``upVector`` a vector for the (u,v) to (N,M) search. Passed as a parameter for speed reasons. + ## `dataA` sequence A + ## `lowerA` lower bound of the actual range in dataA + ## `upperA` upper bound of the actual range in dataA (exclusive) + ## `dataB` sequence B + ## `lowerB` lower bound of the actual range in dataB + ## `upperB` upper bound of the actual range in dataB (exclusive) + ## `downVector` a vector for the (0,0) to (x,y) search. Passed as a parameter for speed reasons. + ## `upVector` a vector for the (u,v) to (N,M) search. Passed as a parameter for speed reasons. # make mutable copy: var lowerA = lowerA @@ -275,9 +275,9 @@ proc createDiffs(dataA, dataB: DiffData): seq[Item] = proc diffInt*(arrayA, arrayB: openArray[int]): seq[Item] = ## Find the difference in 2 arrays of integers. ## - ## ``arrayA`` A-version of the numbers (usually the old one) + ## `arrayA` A-version of the numbers (usually the old one) ## - ## ``arrayB`` B-version of the numbers (usually the new one) + ## `arrayB` B-version of the numbers (usually the new one) ## ## Returns a sequence of Items that describe the differences. @@ -304,9 +304,9 @@ proc diffText*(textA, textB: string): seq[Item] = ## textlines into a common hashtable so i can find duplicates in there, and generating a ## new number each time a new textline is inserted. ## - ## ``textA`` A-version of the text (usually the old one) + ## `textA` A-version of the text (usually the old one) ## - ## ``textB`` B-version of the text (usually the new one) + ## `textB` B-version of the text (usually the new one) ## ## Returns a seq of Items that describe the differences. diff --git a/lib/genode/env.nim b/lib/genode/env.nim index 2b180d1b3b..ef4a258830 100644 --- a/lib/genode/env.nim +++ b/lib/genode/env.nim @@ -11,7 +11,7 @@ # This file contains the minimum required definitions # for interacting with the initial Genode environment. # It is reserved for use only within the standard -# library. See ``componentConstructHook`` in the system +# library. See `componentConstructHook` in the system # module for accessing the Genode environment after the # standard library has finished initializating. # diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index f0d9d8540c..242ea1b0d8 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -16,8 +16,8 @@ ## Parameter substitution ## ====================== ## -## All ``db_*`` modules support the same form of parameter substitution. -## That is, using the ``?`` (question mark) to signify the place where a +## All `db_*` modules support the same form of parameter substitution. +## That is, using the `?` (question mark) to signify the place where a ## value should be placed. For example: ## ## .. code-block:: Nim @@ -31,7 +31,7 @@ ## ---------------------------------- ## ## .. code-block:: Nim -## import db_mysql +## import std/db_mysql ## let db = open("localhost", "user", "password", "dbname") ## db.close() ## @@ -56,7 +56,7 @@ ## ## .. code-block:: Nim ## -## import db_mysql, math +## import std/[db_mysql, math] ## ## let theDb = open("localhost", "nim", "nim", "test") ## @@ -179,7 +179,7 @@ iterator fastRows*(db: DbConn, query: SqlQuery, ## if you require **ALL** the rows. ## ## Breaking the fastRows() iterator during a loop will cause the next - ## database query to raise an [EDb] exception ``Commands out of sync``. + ## database query to raise an [EDb] exception `Commands out of sync`. rawExec(db, query, args) var sqlres = mysql.useResult(PMySQL db) if sqlres != nil: diff --git a/lib/impure/db_odbc.nim b/lib/impure/db_odbc.nim index 3568cf1cc3..1e4032b348 100644 --- a/lib/impure/db_odbc.nim +++ b/lib/impure/db_odbc.nim @@ -22,8 +22,8 @@ ## Parameter substitution ## ====================== ## -## All ``db_*`` modules support the same form of parameter substitution. -## That is, using the ``?`` (question mark) to signify the place where a +## All `db_*` modules support the same form of parameter substitution. +## That is, using the `?` (question mark) to signify the place where a ## value should be placed. For example: ## ## .. code-block:: Nim @@ -37,7 +37,7 @@ ## ---------------------------------- ## ## .. code-block:: Nim -## import db_odbc +## import std/db_odbc ## var db = open("localhost", "user", "password", "dbname") ## db.close() ## @@ -62,7 +62,7 @@ ## ## .. code-block:: Nim ## -## import db_odbc, math +## import std/[db_odbc, math] ## ## var theDb = open("localhost", "nim", "nim", "test") ## @@ -168,7 +168,7 @@ proc dbError*(db: var DbConn) {. raise e proc sqlCheck(db: var DbConn, resVal: TSqlSmallInt) {.raises: [DbError]} = - ## Wrapper that raises [EDb] if ``resVal`` is neither SQL_SUCCESS or SQL_NO_DATA + ## Wrapper that raises [EDb] if `resVal` is neither SQL_SUCCESS or SQL_NO_DATA if resVal notIn [SQL_SUCCESS, SQL_NO_DATA]: dbError(db) proc sqlGetDBMS(db: var DbConn): string {. @@ -195,7 +195,7 @@ proc dbQuote*(s: string): string {.noSideEffect.} = proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string {. noSideEffect.} = - ## Replace any ``?`` placeholders with `args`, + ## Replace any `?` placeholders with `args`, ## and quotes the arguments result = "" var a = 0 @@ -498,7 +498,7 @@ proc open*(connection, user, password, database: string): DbConn {. ## Raises `EDb` if the connection could not be established. ## ## Currently the database parameter is ignored, - ## but included to match ``open()`` in the other db_xxxxx library modules. + ## but included to match `open()` in the other db_xxxxx library modules. var val = SQL_OV_ODBC3 resLen = 0 diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim index f9f584663d..034a948526 100644 --- a/lib/impure/db_postgres.nim +++ b/lib/impure/db_postgres.nim @@ -16,8 +16,8 @@ ## Parameter substitution ## ====================== ## -## All ``db_*`` modules support the same form of parameter substitution. -## That is, using the ``?`` (question mark) to signify the place where a +## All `db_*` modules support the same form of parameter substitution. +## That is, using the `?` (question mark) to signify the place where a ## value should be placed. For example: ## ## .. code-block:: Nim @@ -26,9 +26,9 @@ ## **Note**: There are two approaches to parameter substitution support by ## this module. ## -## 1. ``SqlQuery`` using ``?, ?, ?, ...`` (same as all the ``db_*`` modules) +## 1. `SqlQuery` using `?, ?, ?, ...` (same as all the `db_*` modules) ## -## 2. ``SqlPrepared`` using ``$1, $2, $3, ...`` +## 2. `SqlPrepared` using `$1, $2, $3, ...` ## ## .. code-block:: Nim ## prepare(db, "myExampleInsert", @@ -47,7 +47,7 @@ ## To use Unix sockets with `db_postgres`, change the server address to the socket file path: ## ## .. code-block:: Nim -## import db_postgres ## Change "localhost" or "127.0.0.1" to the socket file path +## import std/db_postgres ## Change "localhost" or "127.0.0.1" to the socket file path ## let db = db_postgres.open("/run/postgresql", "user", "password", "database") ## echo db.getAllRows(sql"SELECT version();") ## db.close() @@ -64,7 +64,7 @@ ## ---------------------------------- ## ## .. code-block:: Nim -## import db_postgres +## import std/db_postgres ## let db = open("localhost", "user", "password", "dbname") ## db.close() ## @@ -184,8 +184,8 @@ proc setupQuery(db: DbConn, stmtName: SqlPrepared, proc prepare*(db: DbConn; stmtName: string, query: SqlQuery; nParams: int): SqlPrepared = - ## Creates a new ``SqlPrepared`` statement. Parameter substitution is done - ## via ``$1``, ``$2``, ``$3``, etc. + ## Creates a new `SqlPrepared` statement. Parameter substitution is done + ## via `$1`, `$2`, `$3`, etc. if nParams > 0 and not string(query).contains("$1"): dbError("parameter substitution expects \"$1\"") var res = pqprepare(db, stmtName, query.string, int32(nParams), nil) @@ -488,8 +488,8 @@ proc tryInsertID*(db: DbConn, query: SqlQuery, tags: [WriteDbEffect].}= ## executes the query (typically "INSERT") and returns the ## generated ID for the row or -1 in case of an error. For Postgre this adds - ## ``RETURNING id`` to the query, so it only works if your primary key is - ## named ``id``. + ## `RETURNING id` to the query, so it only works if your primary key is + ## named `id`. var x = pqgetvalue(setupQuery(db, SqlQuery(string(query) & " RETURNING id"), args), 0, 0) if not isNil(x): @@ -502,8 +502,8 @@ proc insertID*(db: DbConn, query: SqlQuery, tags: [WriteDbEffect].} = ## executes the query (typically "INSERT") and returns the ## generated ID for the row. For Postgre this adds - ## ``RETURNING id`` to the query, so it only works if your primary key is - ## named ``id``. + ## `RETURNING id` to the query, so it only works if your primary key is + ## named `id`. result = tryInsertID(db, query, args) if result < 0: dbError(db) diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index 5c79b8c2a9..8324079602 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -22,8 +22,8 @@ ## Parameter substitution ## ---------------------- ## -## All ``db_*`` modules support the same form of parameter substitution. -## That is, using the ``?`` (question mark) to signify the place where a +## All `db_*` modules support the same form of parameter substitution. +## That is, using the `?` (question mark) to signify the place where a ## value should be placed. For example: ## ## .. code-block:: Nim @@ -35,7 +35,7 @@ ## ## .. code-block:: Nim ## -## import db_sqlite +## import std/db_sqlite ## ## # user, password, database name can be empty. ## # These params are not used on db_sqlite module. @@ -66,7 +66,7 @@ ## ## .. code-block:: nim ## -## import db_sqlite, math +## import std/[db_sqlite, math] ## ## let db = open("mytest.db", "", "", "") ## @@ -99,7 +99,7 @@ ## ## .. code-block:: nim ## -## import random +## import std/random ## ## ## Generate random float datas ## var orig = newSeq[float64](150) @@ -149,12 +149,12 @@ ## Note ## ==== ## This module does not implement any ORM features such as mapping the types from the schema. -## Instead, a ``seq[string]`` is returned for each row. +## Instead, a `seq[string]` is returned for each row. ## ## The reasoning is as follows: ## 1. it's close to what many DBs offer natively (char**) ## 2. it hides the number of types that the DB supports -## (int? int64? decimal up to 10 places? geo coords?) +## (int? int64? decimal up to 10 places? geo coords?) ## 3. it's convenient when all you do is to forward the data to somewhere else (echo, log, put the data into a new query) ## ## See also @@ -221,7 +221,7 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string = add(result, c) proc prepare*(db: DbConn; q: string): SqlPrepared {.since: (1, 3).} = - ## Creates a new ``SqlPrepared`` statement. + ## Creates a new `SqlPrepared` statement. if prepare_v2(db, q, q.len.cint,result.PStmt, nil) != SQLITE_OK: discard finalize(result.PStmt) dbError(db) @@ -310,8 +310,8 @@ iterator fastRows*(db: DbConn, query: SqlQuery, ## if you require **ALL** the rows. ## ## **Note:** Breaking the `fastRows()` iterator during a loop will cause the - ## next database query to raise a `DbError` exception ``unable to close due - ## to ...``. + ## next database query to raise a `DbError` exception `unable to close due + ## to ...`. ## ## **Examples:** ## @@ -674,8 +674,8 @@ proc insertID*(db: DbConn, query: SqlQuery, ## generated ID for the row. ## ## Raises a `DbError` exception when failed to insert row. - ## For Postgre this adds ``RETURNING id`` to the query, so it only works - ## if your primary key is named ``id``. + ## For Postgre this adds `RETURNING id` to the query, so it only works + ## if your primary key is named `id`. ## ## **Examples:** ## @@ -755,7 +755,7 @@ proc open*(connection, user, password, database: string): DbConn {. ## Opens a database connection. Raises a `DbError` exception if the connection ## could not be established. ## - ## **Note:** Only the ``connection`` parameter is used for ``sqlite``. + ## **Note:** Only the `connection` parameter is used for `sqlite`. ## ## **Examples:** ## diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index bd17c713eb..7b2d7d3ee1 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -20,13 +20,13 @@ when defined(js): ## search the internet for a wide variety of third-party documentation and ## tools. ## -## **Note**: If you love ``sequtils.toSeq`` we have bad news for you. This +## **Note**: If you love `sequtils.toSeq` we have bad news for you. This ## library doesn't work with it due to documented compiler limitations. As ## a workaround, use this: ## ## .. code-block:: nim ## -## import nre except toSeq +## import std/nre except toSeq ## ## ## Licencing @@ -76,19 +76,19 @@ export options type Regex* = ref object ## Represents the pattern that things are matched against, constructed with - ## ``re(string)``. Examples: ``re"foo"``, ``re(r"(*ANYCRLF)(?x)foo # - ## comment".`` + ## `re(string)`. Examples: `re"foo"`, `re(r"(*ANYCRLF)(?x)foo # + ## comment".` ## - ## ``pattern: string`` + ## `pattern: string` ## the string that was used to create the pattern. For details on how ## to write a pattern, please see `the official PCRE pattern ## documentation. ## `_ ## - ## ``captureCount: int`` + ## `captureCount: int` ## the number of captures that the pattern has. ## - ## ``captureNameId: Table[string, int]`` + ## `captureNameId: Table[string, int]` ## a table from the capture names to their numeric id. ## ## @@ -98,30 +98,30 @@ type ## The following options may appear anywhere in the pattern, and they affect ## the rest of it. ## - ## - ``(?i)`` - case insensitive - ## - ``(?m)`` - multi-line: ``^`` and ``$`` match the beginning and end of + ## - `(?i)` - case insensitive + ## - `(?m)` - multi-line: `^` and `$` match the beginning and end of ## lines, not of the subject string - ## - ``(?s)`` - ``.`` also matches newline (*dotall*) - ## - ``(?U)`` - expressions are not greedy by default. ``?`` can be added + ## - `(?s)` - `.` also matches newline (*dotall*) + ## - `(?U)` - expressions are not greedy by default. `?` can be added ## to a qualifier to make it greedy - ## - ``(?x)`` - whitespace and comments (``#``) are ignored (*extended*) - ## - ``(?X)`` - character escapes without special meaning (``\w`` vs. - ## ``\a``) are errors (*extra*) + ## - `(?x)` - whitespace and comments (`#`) are ignored (*extended*) + ## - `(?X)` - character escapes without special meaning (`\w` vs. + ## `\a`) are errors (*extra*) ## ## One or a combination of these options may appear only at the beginning ## of the pattern: ## - ## - ``(*UTF8)`` - treat both the pattern and subject as UTF-8 - ## - ``(*UCP)`` - Unicode character properties; ``\w`` matches ``я`` - ## - ``(*U)`` - a combination of the two options above - ## - ``(*FIRSTLINE*)`` - fails if there is not a match on the first line - ## - ``(*NO_AUTO_CAPTURE)`` - turn off auto-capture for groups; - ## ``(?...)`` can be used to capture - ## - ``(*CR)`` - newlines are separated by ``\r`` - ## - ``(*LF)`` - newlines are separated by ``\n`` (UNIX default) - ## - ``(*CRLF)`` - newlines are separated by ``\r\n`` (Windows default) - ## - ``(*ANYCRLF)`` - newlines are separated by any of the above - ## - ``(*ANY)`` - newlines are separated by any of the above and Unicode + ## - `(*UTF8)` - treat both the pattern and subject as UTF-8 + ## - `(*UCP)` - Unicode character properties; `\w` matches `я` + ## - `(*U)` - a combination of the two options above + ## - `(*FIRSTLINE*)` - fails if there is not a match on the first line + ## - `(*NO_AUTO_CAPTURE)` - turn off auto-capture for groups; + ## `(?...)` can be used to capture + ## - `(*CR)` - newlines are separated by `\r` + ## - `(*LF)` - newlines are separated by `\n` (UNIX default) + ## - `(*CRLF)` - newlines are separated by `\r\n` (Windows default) + ## - `(*ANYCRLF)` - newlines are separated by any of the above + ## - `(*ANY)` - newlines are separated by any of the above and Unicode ## newlines: ## ## single characters VT (vertical tab, U+000B), FF (form feed, U+000C), @@ -130,8 +130,8 @@ type ## are recognized only in UTF-8 mode. ## — man pcre ## - ## - ``(*JAVASCRIPT_COMPAT)`` - JavaScript compatibility - ## - ``(*NO_STUDY)`` - turn off studying; study is enabled by default + ## - `(*JAVASCRIPT_COMPAT)` - JavaScript compatibility + ## - `(*NO_STUDY)` - turn off studying; study is enabled by default ## ## For more details on the leading option groups, see the `Option ## Setting `_ @@ -141,9 +141,9 @@ type ## manual `_. ## ## Some of these options are not part of PCRE and are converted by nre - ## into PCRE flags. These include ``NEVER_UTF``, ``ANCHORED``, - ## ``DOLLAR_ENDONLY``, ``FIRSTLINE``, ``NO_AUTO_CAPTURE``, - ## ``JAVASCRIPT_COMPAT``, ``U``, ``NO_STUDY``. In other PCRE wrappers, you + ## into PCRE flags. These include `NEVER_UTF`, `ANCHORED`, + ## `DOLLAR_ENDONLY`, `FIRSTLINE`, `NO_AUTO_CAPTURE`, + ## `JAVASCRIPT_COMPAT`, `U`, `NO_STUDY`. In other PCRE wrappers, you ## will need to pass these as separate flags to PCRE. pattern*: string ## not nil pcreObj: ptr pcre.Pcre ## not nil @@ -155,46 +155,46 @@ type ## Usually seen as Option[RegexMatch], it represents the result of an ## execution. On failure, it is none, on success, it is some. ## - ## ``pattern: Regex`` + ## `pattern: Regex` ## the pattern that is being matched ## - ## ``str: string`` + ## `str: string` ## the string that was matched against ## - ## ``captures[]: string`` + ## `captures[]: string` ## the string value of whatever was captured at that id. If the value - ## is invalid, then behavior is undefined. If the id is ``-1``, then + ## is invalid, then behavior is undefined. If the id is `-1`, then ## the whole match is returned. If the given capture was not matched, - ## ``nil`` is returned. + ## `nil` is returned. ## - ## - ``"abc".match(re"(\w)").get.captures[0] == "a"`` - ## - ``"abc".match(re"(?\w)").get.captures["letter"] == "a"`` - ## - ``"abc".match(re"(\w)\w").get.captures[-1] == "ab"`` + ## - `"abc".match(re"(\w)").get.captures[0] == "a"` + ## - `"abc".match(re"(?\w)").get.captures["letter"] == "a"` + ## - `"abc".match(re"(\w)\w").get.captures[-1] == "ab"` ## - ## ``captureBounds[]: HSlice[int, int]`` + ## `captureBounds[]: HSlice[int, int]` ## gets the bounds of the given capture according to the same rules as - ## the above. If the capture is not filled, then ``None`` is returned. + ## the above. If the capture is not filled, then `None` is returned. ## The bounds are both inclusive. ## - ## - ``"abc".match(re"(\w)").get.captureBounds[0] == 0 .. 0`` - ## - ``0 in "abc".match(re"(\w)").get.captureBounds == true`` - ## - ``"abc".match(re"").get.captureBounds[-1] == 0 .. -1`` - ## - ``"abc".match(re"abc").get.captureBounds[-1] == 0 .. 2`` + ## - `"abc".match(re"(\w)").get.captureBounds[0] == 0 .. 0` + ## - `0 in "abc".match(re"(\w)").get.captureBounds == true` + ## - `"abc".match(re"").get.captureBounds[-1] == 0 .. -1` + ## - `"abc".match(re"abc").get.captureBounds[-1] == 0 .. 2` ## - ## ``match: string`` + ## `match: string` ## the full text of the match. ## - ## ``matchBounds: HSlice[int, int]`` - ## the bounds of the match, as in ``captureBounds[]`` + ## `matchBounds: HSlice[int, int]` + ## the bounds of the match, as in `captureBounds[]` ## - ## ``(captureBounds|captures).toTable`` + ## `(captureBounds|captures).toTable` ## returns a table with each named capture as a key. ## - ## ``(captureBounds|captures).toSeq`` + ## `(captureBounds|captures).toSeq` ## returns all the captures by their number. ## - ## ``$: string`` - ## same as ``match`` + ## `$: string` + ## same as `match` pattern*: Regex ## The regex doing the matching. ## Not nil. str*: string ## The string that was matched against. @@ -549,14 +549,14 @@ proc match*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[R iterator findIter*(str: string, pattern: Regex, start = 0, endpos = int.high): RegexMatch = ## Works the same as `find(...)<#find,string,Regex,int>`_, but finds every - ## non-overlapping match. ``"2222".find(re"22")`` is ``"22", "22"``, not - ## ``"22", "22", "22"``. + ## non-overlapping match. `"2222".find(re"22")` is `"22", "22"`, not + ## `"22", "22", "22"`. ## ## Arguments are the same as `find(...)<#find,string,Regex,int>`_ ## ## Variants: ## - ## - ``proc findAll(...)`` returns a ``seq[string]`` + ## - `proc findAll(...)` returns a `seq[string]` # see pcredemo for explanation let matchesCrLf = pattern.matchesCrLf() let unicode = uint32(getinfo[culong](pattern, pcre.INFO_OPTIONS) and @@ -601,12 +601,12 @@ proc find*(str: string, pattern: Regex, start = 0, endpos = int.high): Option[Re ## Finds the given pattern in the string between the end and start ## positions. ## - ## ``start`` - ## The start point at which to start matching. ``|abc`` is ``0``; - ## ``a|bc`` is ``1`` + ## `start` + ## The start point at which to start matching. `|abc` is `0`; + ## `a|bc` is `1` ## - ## ``endpos`` - ## The maximum index for a match; ``int.high`` means the end of the + ## `endpos` + ## The maximum index for a match; `int.high` means the end of the ## string, otherwise it’s an inclusive upper bound. return str.matchImpl(pattern, start, endpos, 0) @@ -618,7 +618,7 @@ proc findAll*(str: string, pattern: Regex, start = 0, endpos = int.high): seq[st proc contains*(str: string, pattern: Regex, start = 0, endpos = int.high): bool = ## Determine if the string contains the given pattern between the end and ## start positions: - ## This function is equivalent to ``isSome(str.find(pattern, start, endpos))``. + ## This function is equivalent to `isSome(str.find(pattern, start, endpos))`. ## runnableExamples: doAssert "abc".contains(re"bc") @@ -631,7 +631,7 @@ proc split*(str: string, pattern: Regex, maxSplit = -1, start = 0): seq[string] ## Splits the string with the given regex. This works according to the ## rules that Perl and Javascript use. ## - ## ``start`` behaves the same as in `find(...)<#find,string,Regex,int>`_. + ## `start` behaves the same as in `find(...)<#find,string,Regex,int>`_. ## runnableExamples: # - If the match is zero-width, then the string is still split: @@ -641,8 +641,8 @@ proc split*(str: string, pattern: Regex, maxSplit = -1, start = 0): seq[string] # split: doAssert "12".split(re"(\d)") == @["", "1", "", "2", ""] - # - If ``maxsplit != -1``, then the string will only be split - # ``maxsplit - 1`` times. This means that there will be ``maxsplit`` + # - If `maxsplit != -1`, then the string will only be split + # `maxsplit - 1` times. This means that there will be `maxsplit` # strings in the output seq. doAssert "1.2.3".split(re"\.", maxsplit = 2) == @["1", "2.3"] @@ -708,28 +708,28 @@ template replaceImpl(str: string, pattern: Regex, proc replace*(str: string, pattern: Regex, subproc: proc (match: RegexMatch): string): string = - ## Replaces each match of Regex in the string with ``subproc``, which should - ## never be or return ``nil``. + ## Replaces each match of Regex in the string with `subproc`, which should + ## never be or return `nil`. ## - ## If ``subproc`` is a ``proc (RegexMatch): string``, then it is executed with + ## If `subproc` is a `proc (RegexMatch): string`, then it is executed with ## each match and the return value is the replacement value. ## - ## If ``subproc`` is a ``proc (string): string``, then it is executed with the + ## If `subproc` is a `proc (string): string`, then it is executed with the ## full text of the match and and the return value is the replacement ## value. ## - ## If ``subproc`` is a string, the syntax is as follows: + ## If `subproc` is a string, the syntax is as follows: ## - ## - ``$$`` - literal ``$`` - ## - ``$123`` - capture number ``123`` - ## - ``$foo`` - named capture ``foo`` - ## - ``${foo}`` - same as above - ## - ``$1$#`` - first and second captures - ## - ``$#`` - first capture - ## - ``$0`` - full match + ## - `$$` - literal `$` + ## - `$123` - capture number `123` + ## - `$foo` - named capture `foo` + ## - `${foo}` - same as above + ## - `$1$#` - first and second captures + ## - `$#` - first capture + ## - `$0` - full match ## - ## If a given capture is missing, ``IndexDefect`` thrown for un-named captures - ## and ``KeyError`` for named captures. + ## If a given capture is missing, `IndexDefect` thrown for un-named captures + ## and `KeyError` for named captures. replaceImpl(str, pattern, subproc(match)) proc replace*(str: string, pattern: Regex, @@ -743,7 +743,7 @@ proc replace*(str: string, pattern: Regex, sub: string): string = proc escapeRe*(str: string): string {.gcsafe.} = ## Escapes the string so it doesn't match any special characters. - ## Incompatible with the Extra flag (``X``). + ## Incompatible with the Extra flag (`X`). ## ## Escaped char: `\ + * ? [ ^ ] $ ( ) { } = ! < > | : -` runnableExamples: diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index 9dbbd97aef..c580b89d1f 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -9,66 +9,67 @@ ## This module contains code for reading from `stdin`:idx:. On UNIX the ## linenoise library is wrapped and set up to provide default key bindings -## (e.g. you can navigate with the arrow keys). On Windows ``system.readLine`` +## (e.g. you can navigate with the arrow keys). On Windows `system.readLine` ## is used. This suffices because Windows' console already provides the ## wanted functionality. -## -## **Examples:** -## -## .. code-block:: nim -## echo readLineFromStdin("Is Nim awesome? (Y/n):") -## var userResponse: string -## doAssert readLineFromStdin("How are you?:", line = userResponse) -## echo userResponse -when defined(Windows): - proc readLineFromStdin*(prompt: string): TaintedString {. +runnableExamples("-r:off"): + echo readLineFromStdin("Is Nim awesome? (Y/n): ") + var line: string + while true: + let ok = readLineFromStdin("How are you? ", line) + if not ok: break # ctrl-C or ctrl-D will cause a break + if line.len > 0: echo line + echo "exiting" + +when defined(windows): + proc readLineFromStdin*(prompt: string): string {. tags: [ReadIOEffect, WriteIOEffect].} = ## Reads a line from stdin. stdout.write(prompt) result = readLine(stdin) - proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {. + proc readLineFromStdin*(prompt: string, line: var string): bool {. tags: [ReadIOEffect, WriteIOEffect].} = ## Reads a `line` from stdin. `line` must not be - ## ``nil``! May throw an IO exception. - ## A line of text may be delimited by ``CR``, ``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. + ## `nil`! May throw an IO exception. + ## A line of text may be delimited by `CR`, `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. stdout.write(prompt) result = readLine(stdin, line) elif defined(genode): - proc readLineFromStdin*(prompt: string): TaintedString {. + proc readLineFromStdin*(prompt: string): string {. tags: [ReadIOEffect, WriteIOEffect].} = stdin.readLine() - proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {. + proc readLineFromStdin*(prompt: string, line: var string): bool {. tags: [ReadIOEffect, WriteIOEffect].} = stdin.readLine(line) else: import linenoise - proc readLineFromStdin*(prompt: string): TaintedString {. + proc readLineFromStdin*(prompt: string): string {. tags: [ReadIOEffect, WriteIOEffect].} = var buffer = linenoise.readLine(prompt) if isNil(buffer): raise newException(IOError, "Linenoise returned nil") - result = TaintedString($buffer) - if result.string.len > 0: + result = $buffer + if result.len > 0: historyAdd(buffer) linenoise.free(buffer) - proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {. + proc readLineFromStdin*(prompt: string, line: var string): bool {. tags: [ReadIOEffect, WriteIOEffect].} = var buffer = linenoise.readLine(prompt) if isNil(buffer): - line.string.setLen(0) + line.setLen(0) return false - line = TaintedString($buffer) - if line.string.len > 0: + line = $buffer + if line.len > 0: historyAdd(buffer) linenoise.free(buffer) result = true diff --git a/lib/impure/re.nim b/lib/impure/re.nim index fe3ea96ff1..0c96876b91 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -37,14 +37,14 @@ import const MaxSubpatterns* = 20 ## defines the maximum number of subpatterns that can be captured. - ## This limit still exists for ``replacef`` and ``parallelReplace``. + ## This limit still exists for `replacef` and `parallelReplace`. type RegexFlag* = enum ## options for regular expressions reIgnoreCase = 0, ## do caseless matching - reMultiLine = 1, ## ``^`` and ``$`` match newlines within data - reDotAll = 2, ## ``.`` matches anything including NL - reExtended = 3, ## ignore whitespace and ``#`` comments + reMultiLine = 1, ## `^` and `$` match newlines within data + reDotAll = 2, ## `.` matches anything including NL + reExtended = 3, ## ignore whitespace and `#` comments reStudy = 4 ## study the expression (may be omitted if the ## expression will be used only once) @@ -79,7 +79,7 @@ proc rawCompile(pattern: string, flags: cint): ptr Pcre = proc finalizeRegEx(x: Regex) = # XXX This is a hack, but PCRE does not export its "free" function properly. - # Sigh. The hack relies on PCRE's implementation (see ``pcre_get.c``). + # Sigh. The hack relies on PCRE's implementation (see `pcre_get.c`). # Fortunately the implementation is unlikely to change. pcre.free_substring(cast[cstring](x.h)) if not isNil(x.e): @@ -89,8 +89,8 @@ proc re*(s: string, flags = {reStudy}): Regex = ## Constructor of regular expressions. ## ## Note that Nim's - ## extended raw string literals support the syntax ``re"[abc]"`` as - ## a short form for ``re(r"[abc]")``. Also note that since this + ## extended raw string literals support the syntax `re"[abc]"` as + ## a short form for `re(r"[abc]")`. Also note that since this ## compiles the regular expression, which is expensive, you should ## avoid putting it directly in the arguments of the functions like ## the examples show below if you plan to use it a lot of times, as @@ -143,11 +143,11 @@ proc matchOrFind(buf: cstring, pattern: Regex, matches: var openArray[string], proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string], start = 0, bufSize: int): tuple[first, last: int] = - ## returns the starting position and end position of ``pattern`` in ``buf`` - ## (where ``buf`` has length ``bufSize`` and is not necessarily ``'\0'`` terminated), + ## returns the starting position and end position of `pattern` in `buf` + ## (where `buf` has length `bufSize` and is not necessarily `'\0'` terminated), ## and the captured - ## substrings in the array ``matches``. If it does not match, nothing - ## is written into ``matches`` and ``(-1,0)`` is returned. + ## substrings in the array `matches`. If it does not match, nothing + ## is written into `matches` and `(-1,0)` is returned. var rtarray = initRtArray[cint]((matches.len+1)*3) rawMatches = rtarray.getRawData @@ -163,20 +163,20 @@ proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string], proc findBounds*(s: string, pattern: Regex, matches: var openArray[string], start = 0): tuple[first, last: int] {.inline.} = - ## returns the starting position and end position of ``pattern`` in ``s`` - ## and the captured substrings in the array ``matches``. + ## 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 - ## is written into ``matches`` and ``(-1,0)`` is returned. + ## is written into `matches` and `(-1,0)` is returned. result = findBounds(cstring(s), pattern, matches, start, s.len) proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[tuple[first, last: int]], start = 0, bufSize = 0): tuple[first, last: int] = - ## returns the starting position and end position of ``pattern`` in ``buf`` - ## (where ``buf`` has length ``bufSize`` and is not necessarily ``'\0'`` terminated), - ## and the captured substrings in the array ``matches``. - ## If it does not match, nothing is written into ``matches`` and - ## ``(-1,0)`` is returned. + ## returns the starting position and end position of `pattern` in `buf` + ## (where `buf` has length `bufSize` and is not necessarily `'\0'` terminated), + ## and the captured substrings in the array `matches`. + ## If it does not match, nothing is written into `matches` and + ## `(-1,0)` is returned. var rtarray = initRtArray[cint]((matches.len+1)*3) rawMatches = rtarray.getRawData @@ -193,17 +193,17 @@ proc findBounds*(buf: cstring, pattern: Regex, proc findBounds*(s: string, pattern: Regex, matches: var openArray[tuple[first, last: int]], start = 0): tuple[first, last: int] {.inline.} = - ## 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 is written into ``matches`` and - ## ``(-1,0)`` is returned. + ## 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 is written into `matches` and + ## `(-1,0)` is returned. result = findBounds(cstring(s), pattern, matches, start, s.len) proc findBounds*(buf: cstring, pattern: Regex, start = 0, bufSize: int): tuple[first, last: int] = - ## returns the ``first`` and ``last`` position of ``pattern`` in ``buf``, - ## where ``buf`` has length ``bufSize`` (not necessarily ``'\0'`` terminated). - ## If it does not match, ``(-1,0)`` is returned. + ## returns the `first` and `last` position of `pattern` in `buf`, + ## where `buf` has length `bufSize` (not necessarily `'\0'` terminated). + ## If it does not match, `(-1,0)` is returned. var rtarray = initRtArray[cint](3) rawMatches = rtarray.getRawData @@ -214,8 +214,8 @@ proc findBounds*(buf: cstring, pattern: Regex, proc findBounds*(s: string, pattern: Regex, start = 0): tuple[first, last: int] {.inline.} = - ## returns the ``first`` and ``last`` position of ``pattern`` in ``s``. - ## If it does not match, ``(-1,0)`` is returned. + ## returns the `first` and `last` position of `pattern` in `s`. + ## If it does not match, `(-1,0)` is returned. ## ## Note: there is a speed improvement if the matches do not need to be captured. runnableExamples: @@ -233,21 +233,21 @@ proc matchOrFind(buf: cstring, pattern: Regex, start, bufSize: int, flags: cint) proc matchLen*(s: string, pattern: Regex, matches: var openArray[string], start = 0): int {.inline.} = - ## 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 + ## 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. result = matchOrFind(cstring(s), pattern, matches, start.cint, s.len.cint, pcre.ANCHORED) proc matchLen*(buf: cstring, pattern: Regex, matches: var openArray[string], start = 0, bufSize: int): int {.inline.} = - ## 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 + ## 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. return matchOrFind(buf, pattern, matches, start.cint, bufSize.cint, pcre.ANCHORED) proc matchLen*(s: string, pattern: Regex, start = 0): int {.inline.} = - ## 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 + ## 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. ## runnableExamples: @@ -257,24 +257,24 @@ proc matchLen*(s: string, pattern: Regex, start = 0): int {.inline.} = result = matchOrFind(cstring(s), pattern, start.cint, s.len.cint, pcre.ANCHORED) proc matchLen*(buf: cstring, pattern: Regex, start = 0, bufSize: int): int {.inline.} = - ## 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 + ## 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. result = matchOrFind(buf, pattern, start.cint, bufSize, pcre.ANCHORED) proc match*(s: string, pattern: Regex, start = 0): bool {.inline.} = - ## returns ``true`` if ``s[start..]`` matches the ``pattern``. + ## returns `true` if `s[start..]` matches the `pattern`. result = matchLen(cstring(s), pattern, start, s.len) != -1 proc match*(s: string, pattern: Regex, matches: var openArray[string], start = 0): bool {.inline.} = - ## 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 + ## 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. ## runnableExamples: - import sequtils + import std/sequtils var matches: array[2, string] if match("abcdefg", re"c(d)ef(g)", matches, 2): doAssert toSeq(matches) == @["d", "g"] @@ -282,19 +282,19 @@ proc match*(s: string, pattern: Regex, matches: var openArray[string], proc match*(buf: cstring, pattern: Regex, matches: var openArray[string], start = 0, bufSize: int): bool {.inline.} = - ## returns ``true`` if ``buf[start..= 0`` + ## same as `find(s, pattern, start) >= 0` return find(s, pattern, start) >= 0 proc contains*(s: string, pattern: Regex, matches: var openArray[string], start = 0): bool {.inline.} = - ## same as ``find(s, pattern, matches, start) >= 0`` + ## same as `find(s, pattern, matches, start) >= 0` return find(s, pattern, matches, start) >= 0 proc startsWith*(s: string, prefix: Regex): bool {.inline.} = @@ -429,8 +426,8 @@ proc endsWith*(s: string, suffix: Regex): bool {.inline.} = if matchLen(s, suffix, i) == s.len - i: return true proc replace*(s: string, sub: Regex, by = ""): string = - ## Replaces ``sub`` in ``s`` by the string ``by``. Captures cannot be - ## accessed in ``by``. + ## Replaces `sub` in `s` by the string `by`. Captures cannot be + ## accessed in `by`. runnableExamples: doAssert "var1=key; var2=key2".replace(re"(\w+)=(\w+)") == "; " doAssert "var1=key; var2=key2".replace(re"(\w+)=(\w+)", "?") == "?; ?" @@ -446,8 +443,8 @@ proc replace*(s: string, sub: Regex, by = ""): string = add(result, substr(s, prev)) proc replacef*(s: string, sub: Regex, by: string): string = - ## Replaces ``sub`` in ``s`` by the string ``by``. Captures can be accessed in ``by`` - ## with the notation ``$i`` and ``$#`` (see strutils.\`%\`). + ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by` + ## with the notation `$i` and `$#` (see strutils.\`%\`). runnableExamples: doAssert "var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2") == "var1<-keykey; var2<-key2key2" @@ -465,7 +462,7 @@ proc replacef*(s: string, sub: Regex, by: string): string = proc multiReplace*(s: string, subs: openArray[ tuple[pattern: Regex, repl: string]]): string = - ## Returns a modified copy of ``s`` with the substitutions in ``subs`` + ## Returns a modified copy of `s` with the substitutions in `subs` ## applied in parallel. result = "" var i = 0 @@ -485,19 +482,19 @@ proc multiReplace*(s: string, subs: openArray[ proc transformFile*(infile, outfile: string, subs: openArray[tuple[pattern: Regex, repl: string]]) = - ## reads in the file ``infile``, performs a parallel replacement (calls - ## ``parallelReplace``) and writes back to ``outfile``. Raises ``IOError`` if an + ## reads in the file `infile`, performs a parallel replacement (calls + ## `parallelReplace`) and writes back to `outfile`. Raises `IOError` if an ## error occurs. This is supposed to be used for quick scripting. - var x = readFile(infile).string + var x = readFile(infile) writeFile(outfile, x.multiReplace(subs)) iterator split*(s: string, sep: Regex; maxsplit = -1): string = - ## Splits the string ``s`` into substrings. + ## Splits the string `s` into substrings. ## - ## Substrings are separated by the regular expression ``sep`` - ## (and the portion matched by ``sep`` is not returned). + ## Substrings are separated by the regular expression `sep` + ## (and the portion matched by `sep` is not returned). runnableExamples: - import sequtils + import std/sequtils doAssert toSeq(split("00232this02939is39an22example111", re"\d+")) == @["", "this", "is", "an", "example", ""] var last = 0 @@ -522,14 +519,14 @@ iterator split*(s: string, sep: Regex; maxsplit = -1): string = inc(last, sepLen) proc split*(s: string, sep: Regex, maxsplit = -1): seq[string] {.inline.} = - ## Splits the string ``s`` into a seq of substrings. + ## Splits the string `s` into a seq of substrings. ## - ## The portion matched by ``sep`` is not returned. + ## The portion matched by `sep` is not returned. result = @[] for x in split(s, sep, maxsplit): result.add x proc escapeRe*(s: string): string = - ## escapes ``s`` so that it is matched verbatim when used as a regular + ## escapes `s` so that it is matched verbatim when used as a regular ## expression. result = "" for c in items(s): diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim index 219b1bed55..c62ac633fa 100644 --- a/lib/js/asyncjs.nim +++ b/lib/js/asyncjs.nim @@ -11,11 +11,11 @@ ## and libraries, writing async procedures in Nim and converting callback-based code ## to promises. ## -## A Nim procedure is asynchronous when it includes the ``{.async.}`` pragma. It -## should always have a ``Future[T]`` return type or not have a return type at all. -## A ``Future[void]`` return type is assumed by default. +## A Nim procedure is asynchronous when it includes the `{.async.}` pragma. It +## should always have a `Future[T]` return type or not have a return type at all. +## A `Future[void]` return type is assumed by default. ## -## This is roughly equivalent to the ``async`` keyword in JavaScript code. +## This is roughly equivalent to the `async` keyword in JavaScript code. ## ## .. code-block:: nim ## proc loadGame(name: string): Future[Game] {.async.} = @@ -28,14 +28,14 @@ ## // code ## } ## -## A call to an asynchronous procedure usually needs ``await`` to wait for -## the completion of the ``Future``. +## A call to an asynchronous procedure usually needs `await` to wait for +## the completion of the `Future`. ## ## .. code-block:: nim ## var game = await loadGame(name) ## ## Often, you might work with callback-based API-s. You can wrap them with -## asynchronous procedures using promises and ``newPromise``: +## asynchronous procedures using promises and `newPromise`: ## ## .. code-block:: nim ## proc loadGame(name: string): Future[Game] = @@ -44,7 +44,7 @@ ## resolve(game) ## return promise ## -## Forward definitions work properly, you just need to always add the ``{.async.}`` pragma: +## Forward definitions work properly, you just need to always add the `{.async.}` pragma: ## ## .. code-block:: nim ## proc loadGame(name: string): Future[Game] {.async.} @@ -57,19 +57,21 @@ ## If you need to use this module with older versions of JavaScript, you can ## use a tool that backports the resulting JavaScript code, as babel. -import jsffi -import macros +# xxx code-block:: javascript above gives `LanguageXNotSupported` warning. -when not defined(js) and not defined(nimdoc) and not defined(nimsuggest): +when not defined(js) and not defined(nimsuggest): {.fatal: "Module asyncjs is designed to be used with the JavaScript backend.".} +import std/jsffi +import std/macros + type Future*[T] = ref object future*: T ## Wraps the return type of an asynchronous procedure. - PromiseJs* {.importcpp: "Promise".} = ref object - ## A JavaScript Promise + PromiseJs* {.importjs: "Promise".} = ref object + ## A JavaScript Promise. proc replaceReturn(node: var NimNode) = @@ -111,16 +113,17 @@ proc generateJsasync(arg: NimNode): NimNode = if len(code) > 0: var awaitFunction = quote: - proc await[T](f: Future[T]): T {.importcpp: "(await #)", used.} + proc await[T](f: Future[T]): T {.importjs: "(await #)", used.} result.body.add(awaitFunction) var resolve: NimNode if isVoid: resolve = quote: - var `jsResolve` {.importcpp: "undefined".}: Future[void] + var `jsResolve` {.importjs: "undefined".}: Future[void] else: resolve = quote: - proc jsResolve[T](a: T): Future[T] {.importcpp: "#", used.} + proc jsResolve[T](a: T): Future[T] {.importjs: "#", used.} + proc jsResolve[T](a: Future[T]): Future[T] {.importjs: "#", used.} result.body.add(resolve) else: result.body = newEmptyNode() @@ -139,7 +142,7 @@ proc generateJsasync(arg: NimNode): NimNode = macro async*(arg: untyped): untyped = ## Macro which converts normal procedures into - ## javascript-compatible async procedures + ## javascript-compatible async procedures. if arg.kind == nnkStmtList: result = newStmtList() for oneProc in arg: @@ -147,10 +150,108 @@ macro async*(arg: untyped): untyped = else: result = generateJsasync(arg) -proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importcpp: "(new Promise(#))".} +proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importjs: "(new Promise(#))".} ## A helper for wrapping callback-based functions - ## into promises and async procedures + ## into promises and async procedures. -proc newPromise*(handler: proc(resolve: proc())): Future[void] {.importcpp: "(new Promise(#))".} +proc newPromise*(handler: proc(resolve: proc())): Future[void] {.importjs: "(new Promise(#))".} ## A helper for wrapping callback-based functions - ## into promises and async procedures + ## into promises and async procedures. + +template typeOrVoid[T](a: T): type = + # xxx this is useful, make it public in std/typetraits in future work + T + +template maybeFuture(T): untyped = + # avoids `Future[Future[T]]` + when T is Future: T + else: Future[T] + +when defined(nimExperimentalAsyncjsThen): + import std/private/since + since (1, 5, 1): + #[ + TODO: + * map `Promise.all()` + * proc toString*(a: Error): cstring {.importjs: "#.toString()".} + + Note: + We probably can't have a `waitFor` in js in browser (single threaded), but maybe it would be possible + in in nodejs, see https://nodejs.org/api/child_process.html#child_process_child_process_execsync_command_options + and https://stackoverflow.com/questions/61377358/javascript-wait-for-async-call-to-finish-before-returning-from-function-witho + ]# + + type Error* {.importjs: "Error".} = ref object of JsRoot + ## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error + message*: cstring + name*: cstring + + type OnReject* = proc(reason: Error) + + proc then*[T](future: Future[T], onSuccess: proc, onReject: OnReject = nil): auto = + ## See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then + ## Returns a `Future` from the return type of `onSuccess(T.default)`. + runnableExamples("-d:nimExperimentalAsyncjsThen"): + from std/sugar import `=>` + + proc fn(n: int): Future[int] {.async.} = + if n >= 7: raise newException(ValueError, "foobar: " & $n) + else: result = n * 2 + + proc asyncFact(n: int): Future[int] {.async.} = + if n > 0: result = n * await asyncFact(n-1) + else: result = 1 + + proc main() {.async.} = + block: # then + assert asyncFact(3).await == 3*2 + assert asyncFact(3).then(asyncFact).await == 6*5*4*3*2 + let x1 = await fn(3) + assert x1 == 3 * 2 + let x2 = await fn(4) + .then((a: int) => a.float) + .then((a: float) => $a) + assert x2 == "8.0" + + block: # then with `onReject` callback + var witness = 1 + await fn(6).then((a: int) => (witness = 2), (r: Error) => (witness = 3)) + assert witness == 2 + await fn(7).then((a: int) => (witness = 2), (r: Error) => (witness = 3)) + assert witness == 3 + + template impl(call): untyped = + when typeOrVoid(call) is void: + var ret: Future[void] + else: + var ret = default(maybeFuture(typeof(call))) + typeof(ret) + when T is void: + type A = impl(onSuccess()) + else: + type A = impl(onSuccess(default(T))) + var ret: A + asm "`ret` = `future`.then(`onSuccess`, `onReject`)" + return ret + + proc catch*[T](future: Future[T], onReject: OnReject): Future[void] = + ## See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch + runnableExamples("-d:nimExperimentalAsyncjsThen"): + from std/sugar import `=>` + from std/strutils import contains + + proc fn(n: int): Future[int] {.async.} = + if n >= 7: raise newException(ValueError, "foobar: " & $n) + else: result = n * 2 + + proc main() {.async.} = + var reason: Error + await fn(6).catch((r: Error) => (reason = r)) # note: `()` are needed, `=> reason = r` would not work + assert reason == nil + await fn(7).catch((r: Error) => (reason = r)) + assert reason != nil + assert "foobar: 7" in $reason.message + + discard main() + + asm "`result` = `future`.catch(`onReject`)" diff --git a/lib/js/dom.nim b/lib/js/dom.nim index d4e8ce86a4..a133f1f69a 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -10,7 +10,7 @@ ## Declaration of the Document Object Model for the `JavaScript backend ## `_. import std/private/since -when not defined(js) and not defined(Nimdoc): +when not defined(js): {.error: "This module only works on the JavaScript platform".} const @@ -37,6 +37,7 @@ type onmouseup*: proc (event: Event) {.closure.} onreset*: proc (event: Event) {.closure.} onselect*: proc (event: Event) {.closure.} + onstorage*: proc (event: Event) {.closure.} onsubmit*: proc (event: Event) {.closure.} onunload*: proc (event: Event) {.closure.} onloadstart*: proc (event: Event) {.closure.} @@ -72,6 +73,7 @@ type Resize = "resize", Scroll = "scroll", Select = "select", + Storage = "storage", Unload = "unload", Wheel = "wheel" @@ -125,7 +127,7 @@ type rangeCount*: int `type`*: cstring - LocalStorage* {.importc.} = ref object + Storage* {.importc.} = ref object Window* = ref WindowObj WindowObj {.importc.} = object of EventTargetObj @@ -153,7 +155,8 @@ type screen*: Screen performance*: Performance onpopstate*: proc (event: Event) - localStorage*: LocalStorage + localStorage*: Storage + sessionStorage*: Storage parent*: Window Frame* = ref FrameObj @@ -1210,6 +1213,13 @@ type ## see `docs`_ clipboardData*: DataTransfer + StorageEvent* = ref StorageEventObj ## see `docs`_ + StorageEventObj {.importc.} = object of Event + key*: cstring + newValue*, oldValue*: cstring + storageArea*: Storage + url*: cstring + TouchList* {.importc.} = ref object of RootObj length*: int @@ -1457,6 +1467,7 @@ else: proc insertBefore*(n, newNode, before: Node) {.importcpp.} proc getElementById*(d: Document, id: cstring): Element {.importcpp.} proc createElement*(d: Document, identifier: cstring): Element {.importcpp.} + proc createElementNS*(d: Document, namespaceURI, qualifiedIdentifier: cstring): Element {.importcpp.} proc createTextNode*(d: Document, identifier: cstring): Node {.importcpp.} proc createComment*(d: Document, data: cstring): Node {.importcpp.} @@ -1654,12 +1665,12 @@ proc getRangeAt*(s: Selection, index: int): Range converter toString*(s: Selection): cstring proc `$`*(s: Selection): string = $(s.toString()) -# LocalStorage "methods" -proc getItem*(ls: LocalStorage, key: cstring): cstring -proc setItem*(ls: LocalStorage, key, value: cstring) -proc hasItem*(ls: LocalStorage, key: cstring): bool -proc clear*(ls: LocalStorage) -proc removeItem*(ls: LocalStorage, key: cstring) +# Storage "methods" +proc getItem*(s: Storage, key: cstring): cstring +proc setItem*(s: Storage, key, value: cstring) +proc hasItem*(s: Storage, key: cstring): bool +proc clear*(s: Storage) +proc removeItem*(s: Storage, key: cstring) {.pop.} diff --git a/lib/js/dom_extensions.nim b/lib/js/dom_extensions.nim index 851ec0c5f3..a1ceff5b42 100644 --- a/lib/js/dom_extensions.nim +++ b/lib/js/dom_extensions.nim @@ -1,5 +1,5 @@ -import dom +import std/dom {.push importcpp.} proc elementsFromPoint*(n: DocumentOrShadowRoot; x, y: float): seq[Element] -{.pop.} \ No newline at end of file +{.pop.} diff --git a/lib/js/jsconsole.nim b/lib/js/jsconsole.nim index 35afd95ad3..bf43adddd4 100644 --- a/lib/js/jsconsole.nim +++ b/lib/js/jsconsole.nim @@ -9,11 +9,25 @@ ## Wrapper for the `console` object for the `JavaScript backend ## `_. +## +## Styled Messages +## =============== +## +## CSS-styled messages in the browser are useful for debugging purposes. +## To use them, prefix the message with one or more `%c`, +## and provide the CSS style as the last argument. +## The amount of `%c`'s must match the amount of CSS-styled strings. +## +runnableExamples("-r:off"): + console.log "%c My Debug Message", "color: red" # Notice the "%c" + console.log "%c My Debug %c Message", "color: red", "font-size: 2em" -when not defined(js) and not defined(Nimdoc): +import std/private/since, std/private/miscdollars # toLocation + +when not defined(js): {.error: "This module only works on the JavaScript platform".} -type Console* = ref object of RootObj +type Console* = ref object of JsRoot proc log*(console: Console) {.importcpp, varargs.} ## https://developer.mozilla.org/docs/Web/API/Console/log @@ -67,4 +81,44 @@ proc timeLog*(console: Console, label = "".cstring) {.importcpp.} proc table*(console: Console) {.importcpp, varargs.} ## https://developer.mozilla.org/docs/Web/API/Console/table +since (1, 5): + type InstantiationInfo = tuple[filename: string, line: int, column: int] + + func getMsg(info: InstantiationInfo; msg: string): string = + var temp = "" + temp.toLocation(info.filename, info.line, info.column + 1) + result.addQuoted("[jsAssert] " & temp) + result.add ',' + result.addQuoted(msg) + + template jsAssert*(console: Console; assertion) = + ## JavaScript `console.assert`, for NodeJS this prints to stderr, + ## assert failure just prints to console and do not quit the program, + ## this is not meant to be better or even equal than normal assertions, + ## is just for when you need faster performance *and* assertions, + ## otherwise use the normal assertions for better user experience. + ## https://developer.mozilla.org/en-US/docs/Web/API/Console/assert + runnableExamples: + console.jsAssert(42 == 42) # OK + console.jsAssert(42 != 42) # Fail, prints "Assertion failed" and continues + console.jsAssert('`' == '\n' and '\t' == '\0') # Message correctly formatted + assert 42 == 42 # Normal assertions keep working + + const + loc = instantiationInfo(fullPaths = compileOption("excessiveStackTrace")) + msg = getMsg(loc, astToStr(assertion)).cstring + {.line: loc.}: + {.emit: ["console.assert(", assertion, ", ", msg, ");"].} + + func dir*(console: Console; obj: auto) {.importcpp.} + ## https://developer.mozilla.org/en-US/docs/Web/API/Console/dir + + func dirxml*(console: Console; obj: auto) {.importcpp.} + ## https://developer.mozilla.org/en-US/docs/Web/API/Console/dirxml + + func timeStamp*(console: Console; label: cstring) {.importcpp.} + ## https://developer.mozilla.org/en-US/docs/Web/API/Console/timeStamp + ## ..warning:: non-standard + + var console* {.importc, nodecl.}: Console diff --git a/lib/js/jscore.nim b/lib/js/jscore.nim index 2e2bd2402a..693e507991 100644 --- a/lib/js/jscore.nim +++ b/lib/js/jscore.nim @@ -11,10 +11,11 @@ ## ## Unless your application has very ## specific requirements and solely targets JavaScript, you should be using -## the relevant functions in the ``math``, ``json``, and ``times`` stdlib +## the relevant functions in the `math`, `json`, and `times` stdlib ## modules instead. +import std/private/since -when not defined(js) and not defined(Nimdoc): +when not defined(js): {.error: "This module only works on the JavaScript platform".} type @@ -104,3 +105,8 @@ proc setFullYear*(d: DateTime, year: int) {.importcpp.} #JSON library proc stringify*(l: JsonLib, s: JsRoot): cstring {.importcpp.} proc parse*(l: JsonLib, s: cstring): JsRoot {.importcpp.} + + +since (1, 5): + func debugger*() {.importjs: "debugger@".} + ## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim index 9fe934f890..937e3727ba 100644 --- a/lib/js/jsffi.nim +++ b/lib/js/jsffi.nim @@ -8,8 +8,8 @@ # ## This Module implements types and macros to facilitate the wrapping of, and -## interaction with JavaScript libraries. Using the provided types ``JsObject`` -## and ``JsAssoc`` together with the provided macros allows for smoother +## interaction with JavaScript libraries. Using the provided types `JsObject` +## and `JsAssoc` together with the provided macros allows for smoother ## interfacing with JavaScript, allowing for example quick and easy imports of ## JavaScript variables: @@ -21,21 +21,21 @@ runnableExamples: var document {.importc, nodecl.}: JsObject var console {.importc, nodecl.}: JsObject # import the "$" function - proc jq(selector: JsObject): JsObject {.importcpp: "$$(#)".} + proc jq(selector: JsObject): JsObject {.importjs: "$$(#)".} # Use jQuery to make the following code run, after the document is ready. - # This uses an experimental ``.()`` operator for ``JsObject``, to emit - # JavaScript calls, when no corresponding proc exists for ``JsObject``. + # This uses an experimental `.()` operator for `JsObject`, to emit + # JavaScript calls, when no corresponding proc exists for `JsObject`. proc main = jq(document).ready(proc() = console.log("Hello JavaScript!") ) -when not defined(js) and not defined(nimdoc) and not defined(nimsuggest): +when not defined(js) and not defined(nimsuggest): {.fatal: "Module jsFFI is designed to be used with the JavaScript backend.".} -import macros, tables +import std/[macros, tables] const setImpl = "#[#] = #" @@ -70,7 +70,7 @@ template mangleJsName(name: cstring): cstring = # only values that can be mapped 1 to 1 with cstring should be keys: they have an injective function with cstring -proc toJsKey*[T: SomeInteger](text: cstring, t: type T): T {.importcpp: "parseInt(#)".} +proc toJsKey*[T: SomeInteger](text: cstring, t: type T): T {.importjs: "parseInt(#)".} proc toJsKey*[T: enum](text: cstring, t: type T): T = T(text.toJsKey(int)) @@ -78,7 +78,7 @@ proc toJsKey*[T: enum](text: cstring, t: type T): T = proc toJsKey*(text: cstring, t: type cstring): cstring = text -proc toJsKey*[T: SomeFloat](text: cstring, t: type T): T {.importcpp: "parseFloat(#)".} +proc toJsKey*[T: SomeFloat](text: cstring, t: type T): T {.importjs: "parseFloat(#)".} type JsKey* = concept a, type T @@ -93,21 +93,21 @@ type var jsArguments* {.importc: "arguments", nodecl}: JsObject - ## JavaScript's arguments pseudo-variable + ## JavaScript's arguments pseudo-variable. jsNull* {.importc: "null", nodecl.}: JsObject - ## JavaScript's null literal + ## JavaScript's null literal. jsUndefined* {.importc: "undefined", nodecl.}: JsObject - ## JavaScript's undefined literal + ## JavaScript's undefined literal. jsDirname* {.importc: "__dirname", nodecl.}: cstring - ## JavaScript's __dirname pseudo-variable + ## JavaScript's __dirname pseudo-variable. jsFilename* {.importc: "__filename", nodecl.}: cstring - ## JavaScript's __filename pseudo-variable + ## JavaScript's __filename pseudo-variable. -proc isNull*[T](x: T): bool {.noSideEffect, importcpp: "(# === null)".} - ## check if a value is exactly null +proc isNull*[T](x: T): bool {.noSideEffect, importjs: "(# === null)".} + ## Checks if a value is exactly null. -proc isUndefined*[T](x: T): bool {.noSideEffect, importcpp: "(# === undefined)".} - ## check if a value is exactly undefined +proc isUndefined*[T](x: T): bool {.noSideEffect, importjs: "(# === undefined)".} + ## Checks if a value is exactly undefined. # Exceptions type @@ -121,36 +121,36 @@ type JsURIError* {.importc: "URIError".} = object of JsError # New -proc newJsObject*: JsObject {.importcpp: "{@}".} - ## Creates a new empty JsObject +proc newJsObject*: JsObject {.importjs: "{@}".} + ## Creates a new empty JsObject. -proc newJsAssoc*[K: JsKey, V]: JsAssoc[K, V] {.importcpp: "{@}".} +proc newJsAssoc*[K: JsKey, V]: JsAssoc[K, V] {.importjs: "{@}".} ## Creates a new empty JsAssoc with key type `K` and value type `V`. # Checks proc hasOwnProperty*(x: JsObject, prop: cstring): bool - {.importcpp: "#.hasOwnProperty(#)".} + {.importjs: "#.hasOwnProperty(#)".} ## Checks, whether `x` has a property of name `prop`. -proc jsTypeOf*(x: JsObject): cstring {.importcpp: "typeof(#)".} +proc jsTypeOf*(x: JsObject): cstring {.importjs: "typeof(#)".} ## Returns the name of the JsObject's JavaScript type as a cstring. -proc jsNew*(x: auto): JsObject {.importcpp: "(new #)".} +proc jsNew*(x: auto): JsObject {.importjs: "(new #)".} ## Turns a regular function call into an invocation of the - ## JavaScript's `new` operator + ## JavaScript's `new` operator. -proc jsDelete*(x: auto): JsObject {.importcpp: "(delete #)".} - ## JavaScript's `delete` operator +proc jsDelete*(x: auto): JsObject {.importjs: "(delete #)".} + ## JavaScript's `delete` operator. proc require*(module: cstring): JsObject {.importc.} - ## JavaScript's `require` function + ## JavaScript's `require` function. # Conversion to and from JsObject -proc to*(x: JsObject, T: typedesc): T {.importcpp: "(#)".} +proc to*(x: JsObject, T: typedesc): T {.importjs: "(#)".} ## Converts a JsObject `x` to type `T`. -proc toJs*[T](val: T): JsObject {.importcpp: "(#)".} - ## Converts a value of any type to type JsObject +proc toJs*[T](val: T): JsObject {.importjs: "(#)".} + ## Converts a value of any type to type JsObject. template toJs*(s: string): JsObject = cstring(s).toJs @@ -160,50 +160,51 @@ macro jsFromAst*(n: untyped): untyped = result = newProc(procType = nnkDo, body = result) return quote: toJs(`result`) -proc `&`*(a, b: cstring): cstring {.importcpp: "(# + #)".} - ## Concatenation operator for JavaScript strings +proc `&`*(a, b: cstring): cstring {.importjs: "(# + #)".} + ## Concatenation operator for JavaScript strings. -proc `+` *(x, y: JsObject): JsObject {.importcpp: "(# + #)".} -proc `-` *(x, y: JsObject): JsObject {.importcpp: "(# - #)".} -proc `*` *(x, y: JsObject): JsObject {.importcpp: "(# * #)".} -proc `/` *(x, y: JsObject): JsObject {.importcpp: "(# / #)".} -proc `%` *(x, y: JsObject): JsObject {.importcpp: "(# % #)".} -proc `+=` *(x, y: JsObject): JsObject {.importcpp: "(# += #)", discardable.} -proc `-=` *(x, y: JsObject): JsObject {.importcpp: "(# -= #)", discardable.} -proc `*=` *(x, y: JsObject): JsObject {.importcpp: "(# *= #)", discardable.} -proc `/=` *(x, y: JsObject): JsObject {.importcpp: "(# /= #)", discardable.} -proc `%=` *(x, y: JsObject): JsObject {.importcpp: "(# %= #)", discardable.} -proc `++` *(x: JsObject): JsObject {.importcpp: "(++#)".} -proc `--` *(x: JsObject): JsObject {.importcpp: "(--#)".} -proc `>` *(x, y: JsObject): JsObject {.importcpp: "(# > #)".} -proc `<` *(x, y: JsObject): JsObject {.importcpp: "(# < #)".} -proc `>=` *(x, y: JsObject): JsObject {.importcpp: "(# >= #)".} -proc `<=` *(x, y: JsObject): JsObject {.importcpp: "(# <= #)".} -proc `**` *(x, y: JsObject): JsObject {.importcpp: "((#) ** #)".} -proc `and`*(x, y: JsObject): JsObject {.importcpp: "(# && #)".} -proc `or` *(x, y: JsObject): JsObject {.importcpp: "(# || #)".} -proc `not`*(x: JsObject): JsObject {.importcpp: "(!#)".} -proc `in` *(x, y: JsObject): JsObject {.importcpp: "(# in #)".} +proc `+` *(x, y: JsObject): JsObject {.importjs: "(# + #)".} +proc `-` *(x, y: JsObject): JsObject {.importjs: "(# - #)".} +proc `*` *(x, y: JsObject): JsObject {.importjs: "(# * #)".} +proc `/` *(x, y: JsObject): JsObject {.importjs: "(# / #)".} +proc `%` *(x, y: JsObject): JsObject {.importjs: "(# % #)".} +proc `+=` *(x, y: JsObject): JsObject {.importjs: "(# += #)", discardable.} +proc `-=` *(x, y: JsObject): JsObject {.importjs: "(# -= #)", discardable.} +proc `*=` *(x, y: JsObject): JsObject {.importjs: "(# *= #)", discardable.} +proc `/=` *(x, y: JsObject): JsObject {.importjs: "(# /= #)", discardable.} +proc `%=` *(x, y: JsObject): JsObject {.importjs: "(# %= #)", discardable.} +proc `++` *(x: JsObject): JsObject {.importjs: "(++#)".} +proc `--` *(x: JsObject): JsObject {.importjs: "(--#)".} +proc `>` *(x, y: JsObject): JsObject {.importjs: "(# > #)".} +proc `<` *(x, y: JsObject): JsObject {.importjs: "(# < #)".} +proc `>=` *(x, y: JsObject): JsObject {.importjs: "(# >= #)".} +proc `<=` *(x, y: JsObject): JsObject {.importjs: "(# <= #)".} +proc `**` *(x, y: JsObject): JsObject {.importjs: "((#) ** #)".} + # (#) needed, refs https://github.com/nim-lang/Nim/pull/16409#issuecomment-760550812 +proc `and`*(x, y: JsObject): JsObject {.importjs: "(# && #)".} +proc `or` *(x, y: JsObject): JsObject {.importjs: "(# || #)".} +proc `not`*(x: JsObject): JsObject {.importjs: "(!#)".} +proc `in` *(x, y: JsObject): JsObject {.importjs: "(# in #)".} -proc `[]`*(obj: JsObject, field: cstring): JsObject {.importcpp: getImpl.} - ## Return the value of a property of name `field` from a JsObject `obj`. +proc `[]`*(obj: JsObject, field: cstring): JsObject {.importjs: getImpl.} + ## Returns the value of a property of name `field` from a JsObject `obj`. -proc `[]`*(obj: JsObject, field: int): JsObject {.importcpp: getImpl.} - ## Return the value of a property of name `field` from a JsObject `obj`. +proc `[]`*(obj: JsObject, field: int): JsObject {.importjs: getImpl.} + ## Returns the value of a property of name `field` from a JsObject `obj`. -proc `[]=`*[T](obj: JsObject, field: cstring, val: T) {.importcpp: setImpl.} - ## Set the value of a property of name `field` in a JsObject `obj` to `v`. +proc `[]=`*[T](obj: JsObject, field: cstring, val: T) {.importjs: setImpl.} + ## Sets the value of a property of name `field` in a JsObject `obj` to `v`. -proc `[]=`*[T](obj: JsObject, field: int, val: T) {.importcpp: setImpl.} - ## Set the value of a property of name `field` in a JsObject `obj` to `v`. +proc `[]=`*[T](obj: JsObject, field: int, val: T) {.importjs: setImpl.} + ## Sets the value of a property of name `field` in a JsObject `obj` to `v`. proc `[]`*[K: JsKey, V](obj: JsAssoc[K, V], field: K): V - {.importcpp: getImpl.} - ## Return the value of a property of name `field` from a JsAssoc `obj`. + {.importjs: getImpl.} + ## Returns the value of a property of name `field` from a JsAssoc `obj`. proc `[]=`*[K: JsKey, V](obj: JsAssoc[K, V], field: K, val: V) - {.importcpp: setImpl.} - ## Set the value of a property of name `field` in a JsAssoc `obj` to `v`. + {.importjs: setImpl.} + ## Sets the value of a property of name `field` in a JsAssoc `obj` to `v`. proc `[]`*[V](obj: JsAssoc[cstring, V], field: string): V = obj[cstring(field)] @@ -211,8 +212,8 @@ proc `[]`*[V](obj: JsAssoc[cstring, V], field: string): V = proc `[]=`*[V](obj: JsAssoc[cstring, V], field: string, val: V) = obj[cstring(field)] = val -proc `==`*(x, y: JsRoot): bool {.importcpp: "(# === #)".} - ## Compare two JsObjects or JsAssocs. Be careful though, as this is comparison +proc `==`*(x, y: JsRoot): bool {.importjs: "(# === #)".} + ## Compares two JsObjects or JsAssocs. Be careful though, as this is comparison ## like in JavaScript, so if your JsObjects are in fact JavaScript Objects, ## and not strings or numbers, this is a *comparison of references*. @@ -228,7 +229,7 @@ macro `.`*(obj: JsObject, field: untyped): JsObject = let importString = "#." & $field result = quote do: proc helper(o: JsObject): JsObject - {.importcpp: `importString`, gensym.} + {.importjs: `importString`, gensym.} helper(`obj`) else: if not mangledNames.hasKey($field): @@ -236,7 +237,7 @@ macro `.`*(obj: JsObject, field: untyped): JsObject = let importString = "#." & mangledNames[$field] result = quote do: proc helper(o: JsObject): JsObject - {.importcpp: `importString`, gensym.} + {.importjs: `importString`, gensym.} helper(`obj`) macro `.=`*(obj: JsObject, field, value: untyped): untyped = @@ -246,7 +247,7 @@ macro `.=`*(obj: JsObject, field, value: untyped): untyped = let importString = "#." & $field & " = #" result = quote do: proc helper(o: JsObject, v: auto) - {.importcpp: `importString`, gensym.} + {.importjs: `importString`, gensym.} helper(`obj`, `value`) else: if not mangledNames.hasKey($field): @@ -254,7 +255,7 @@ macro `.=`*(obj: JsObject, field, value: untyped): untyped = let importString = "#." & mangledNames[$field] & " = #" result = quote do: proc helper(o: JsObject, v: auto) - {.importcpp: `importString`, gensym.} + {.importjs: `importString`, gensym.} helper(`obj`, `value`) macro `.()`*(obj: JsObject, @@ -285,7 +286,7 @@ macro `.()`*(obj: JsObject, importString = "#." & mangledNames[$field] & "(@)" result = quote: proc helper(o: JsObject): JsObject - {.importcpp: `importString`, gensym, discardable.} + {.importjs: `importString`, gensym, discardable.} helper(`obj`) for idx in 0 ..< args.len: let paramName = newIdentNode("param" & $idx) @@ -305,7 +306,7 @@ macro `.`*[K: cstring, V](obj: JsAssoc[K, V], importString = "#." & mangledNames[$field] result = quote do: proc helper(o: type(`obj`)): `obj`.V - {.importcpp: `importString`, gensym.} + {.importjs: `importString`, gensym.} helper(`obj`) macro `.=`*[K: cstring, V](obj: JsAssoc[K, V], @@ -322,7 +323,7 @@ macro `.=`*[K: cstring, V](obj: JsAssoc[K, V], importString = "#." & mangledNames[$field] & " = #" result = quote do: proc helper(o: type(`obj`), v: `obj`.V) - {.importcpp: `importString`, gensym.} + {.importjs: `importString`, gensym.} helper(`obj`, `value`) macro `.()`*[K: cstring, V: proc](obj: JsAssoc[K, V], @@ -341,7 +342,7 @@ macro `.()`*[K: cstring, V: proc](obj: JsAssoc[K, V], # Iterators: iterator pairs*(obj: JsObject): (cstring, JsObject) = - ## Yields tuples of type ``(cstring, JsObject)``, with the first entry + ## Yields tuples of type `(cstring, JsObject)`, with the first entry ## being the `name` of a fields in the JsObject and the second being its ## value wrapped into a JsObject. var k: cstring @@ -370,7 +371,7 @@ iterator keys*(obj: JsObject): cstring = {.emit: "}".} iterator pairs*[K: JsKey, V](assoc: JsAssoc[K, V]): (K,V) = - ## Yields tuples of type ``(K, V)``, with the first entry + ## Yields tuples of type `(K, V)`, with the first entry ## being a `key` in the JsAssoc and the second being its corresponding value. var k: cstring var v: V @@ -400,16 +401,16 @@ iterator keys*[K: JsKey, V](assoc: JsAssoc[K, V]): K = # Literal generation macro `{}`*(typ: typedesc, xs: varargs[untyped]): auto = - ## Takes a ``typedesc`` as its first argument, and a series of expressions of - ## type ``key: value``, and returns a value of the specified type with each - ## field ``key`` set to ``value``, as specified in the arguments of ``{}``. + ## Takes a `typedesc` as its first argument, and a series of expressions of + ## type `key: value`, and returns a value of the specified type with each + ## field `key` set to `value`, as specified in the arguments of `{}`. ## ## Example: ## ## .. code-block:: nim ## ## # Let's say we have a type with a ton of fields, where some fields do not - ## # need to be set, and we do not want those fields to be set to ``nil``: + ## # need to be set, and we do not want those fields to be set to `nil`: ## type ## ExtremelyHugeType = ref object ## a, b, c, d, e, f, g: int @@ -455,16 +456,16 @@ macro `{}`*(typ: typedesc, xs: varargs[untyped]): auto = # from a proc, `this` being the first argument. proc replaceSyms(n: NimNode): NimNode = - if n.kind == nnkSym: + if n.kind == nnkSym: result = newIdentNode($n) - else: + else: result = n for i in 0..= 0 and g.buf[lookbehind] notin {'\x0A', '\x0D'}: + while lookbehind >= 0 and g.buf[lookbehind] notin {'\n', '\r'}: if headerStart == -1 and g.buf[lookbehind] in {'|', '>'}: headerStart = lookbehind dec(lookbehind) @@ -728,12 +728,12 @@ proc yamlNextToken(g: var GeneralTokenizer) = # when the header is alone in a line, this line does not show the parent's # indentation, so we must go further. search the first previous line with # non-whitespace content. - while lookbehind >= 0 and g.buf[lookbehind] in {'\x0A', '\x0D'}: + while lookbehind >= 0 and g.buf[lookbehind] in {'\n', '\r'}: dec(lookbehind) while lookbehind >= 0 and g.buf[lookbehind] in {' ', '\t'}: dec(lookbehind) # now, find the beginning of the line... - while lookbehind >= 0 and g.buf[lookbehind] notin {'\x0A', '\x0D'}: + while lookbehind >= 0 and g.buf[lookbehind] notin {'\n', '\r'}: dec(lookbehind) # ... and its indentation indentation = 1 @@ -741,7 +741,7 @@ proc yamlNextToken(g: var GeneralTokenizer) = if lookbehind == -1: indentation = 0 # top level elif g.buf[lookbehind + 1] == '-' and g.buf[lookbehind + 2] == '-' and g.buf[lookbehind + 3] == '-' and - g.buf[lookbehind + 4] in {'\x09'..'\x0D', ' '}: + g.buf[lookbehind + 4] in {'\t'..'\r', ' '}: # this is a document start, therefore, we are at top level indentation = 0 # because lookbehind was at newline char when calculating indentation, we're @@ -749,7 +749,7 @@ proc yamlNextToken(g: var GeneralTokenizer) = let parentIndentation = indentation - 1 # find first content - while g.buf[pos] in {' ', '\x0A', '\x0D'}: + while g.buf[pos] in {' ', '\n', '\r'}: if g.buf[pos] == ' ': inc(indentation) else: indentation = 0 inc(pos) @@ -766,12 +766,12 @@ proc yamlNextToken(g: var GeneralTokenizer) = if (indentation < minIndentation and g.buf[pos] == '#') or (indentation == 0 and g.buf[pos] == '.' and g.buf[pos + 1] == '.' and g.buf[pos + 2] == '.' and - g.buf[pos + 3] in {'\0', '\x09'..'\x0D', ' '}): + g.buf[pos + 3] in {'\0', '\t'..'\r', ' '}): # comment after end of block scalar, or end of document break minIndentation = min(indentation, minIndentation) - while g.buf[pos] notin {'\0', '\x0A', '\x0D'}: inc(pos) - while g.buf[pos] in {' ', '\x0A', '\x0D'}: + while g.buf[pos] notin {'\0', '\n', '\r'}: inc(pos) + while g.buf[pos] in {' ', '\n', '\r'}: if g.buf[pos] == ' ': inc(indentation) else: indentation = 0 inc(pos) @@ -780,27 +780,27 @@ proc yamlNextToken(g: var GeneralTokenizer) = elif g.state == gtOther: # gtOther means 'inside YAML document' case g.buf[pos] - of ' ', '\x09'..'\x0D': + of ' ', '\t'..'\r': g.kind = gtWhitespace - while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos) + while g.buf[pos] in {' ', '\t'..'\r'}: inc(pos) of '#': g.kind = gtComment inc(pos) - while g.buf[pos] notin {'\0', '\x0A', '\x0D'}: inc(pos) + while g.buf[pos] notin {'\0', '\n', '\r'}: inc(pos) of '-': inc(pos) - if g.buf[pos] in {'\0', ' ', '\x09'..'\x0D'}: + if g.buf[pos] in {'\0', ' ', '\t'..'\r'}: g.kind = gtPunctuation elif g.buf[pos] == '-' and - (pos == 1 or g.buf[pos - 2] in {'\x0A', '\x0D'}): # start of line + (pos == 1 or g.buf[pos - 2] in {'\n', '\r'}): # start of line inc(pos) - if g.buf[pos] == '-' and g.buf[pos + 1] in {'\0', '\x09'..'\x0D', ' '}: + if g.buf[pos] == '-' and g.buf[pos + 1] in {'\0', '\t'..'\r', ' '}: inc(pos) g.kind = gtKeyword else: yamlPossibleNumber(g, pos) else: yamlPossibleNumber(g, pos) of '.': - if pos == 0 or g.buf[pos - 1] in {'\x0A', '\x0D'}: + if pos == 0 or g.buf[pos - 1] in {'\n', '\r'}: inc(pos) for i in 1..2: if g.buf[pos] != '.': break @@ -812,12 +812,12 @@ proc yamlNextToken(g: var GeneralTokenizer) = else: yamlPlainStrLit(g, pos) of '?': inc(pos) - if g.buf[pos] in {'\0', ' ', '\x09'..'\x0D'}: + if g.buf[pos] in {'\0', ' ', '\t'..'\r'}: g.kind = gtPunctuation else: yamlPlainStrLit(g, pos) of ':': inc(pos) - if g.buf[pos] in {'\0', '\x09'..'\x0D', ' ', '\'', '\"'} or + if g.buf[pos] in {'\0', '\t'..'\r', ' ', '\'', '\"'} or (pos > 0 and g.buf[pos - 2] in {'}', ']', '\"', '\''}): g.kind = gtPunctuation else: yamlPlainStrLit(g, pos) @@ -836,7 +836,7 @@ proc yamlNextToken(g: var GeneralTokenizer) = inc(pos) if g.buf[pos] == '<': # literal tag (e.g. `!`) - while g.buf[pos] notin {'\0', '>', '\x09'..'\x0D', ' '}: inc(pos) + while g.buf[pos] notin {'\0', '>', '\t'..'\r', ' '}: inc(pos) if g.buf[pos] == '>': inc(pos) else: while g.buf[pos] in {'A'..'Z', 'a'..'z', '0'..'9', '-'}: inc(pos) @@ -845,17 +845,17 @@ proc yamlNextToken(g: var GeneralTokenizer) = # prefixed tag (e.g. `!!str`) inc(pos) while g.buf[pos] notin - {'\0', '\x09'..'\x0D', ' ', ',', '[', ']', '{', '}'}: inc(pos) - of '\0', '\x09'..'\x0D', ' ': discard + {'\0', '\t'..'\r', ' ', ',', '[', ']', '{', '}'}: inc(pos) + of '\0', '\t'..'\r', ' ': discard else: # local tag (e.g. `!nim:system:int`) - while g.buf[pos] notin {'\0', '\x09'..'\x0D', ' '}: inc(pos) + while g.buf[pos] notin {'\0', '\t'..'\r', ' '}: inc(pos) of '&': g.kind = gtLabel - while g.buf[pos] notin {'\0', '\x09'..'\x0D', ' '}: inc(pos) + while g.buf[pos] notin {'\0', '\t'..'\r', ' '}: inc(pos) of '*': g.kind = gtReference - while g.buf[pos] notin {'\0', '\x09'..'\x0D', ' '}: inc(pos) + while g.buf[pos] notin {'\0', '\t'..'\r', ' '}: inc(pos) of '|', '>': # this can lead to incorrect tokenization when | or > appear inside flow # content. checking whether we're inside flow content is not @@ -871,18 +871,18 @@ proc yamlNextToken(g: var GeneralTokenizer) = # outside document case g.buf[pos] of '%': - if pos == 0 or g.buf[pos - 1] in {'\x0A', '\x0D'}: + if pos == 0 or g.buf[pos - 1] in {'\n', '\r'}: g.kind = gtDirective - while g.buf[pos] notin {'\0', '\x0A', '\x0D'}: inc(pos) + while g.buf[pos] notin {'\0', '\n', '\r'}: inc(pos) else: g.state = gtOther yamlPlainStrLit(g, pos) - of ' ', '\x09'..'\x0D': + of ' ', '\t'..'\r': g.kind = gtWhitespace - while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos) + while g.buf[pos] in {' ', '\t'..'\r'}: inc(pos) of '#': g.kind = gtComment - while g.buf[pos] notin {'\0', '\x0A', '\x0D'}: inc(pos) + while g.buf[pos] notin {'\0', '\n', '\r'}: inc(pos) of '\0': g.kind = gtEof else: g.kind = gtNone @@ -917,7 +917,7 @@ when isMainModule: # Try to work running in both the subdir or at the root. for filename in ["doc/keywords.txt", "../../../doc/keywords.txt"]: try: - let input = string(readFile(filename)) + let input = readFile(filename) keywords = input.splitWhitespace() break except: diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 0d86edcdb4..b5eef76105 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -7,11 +7,37 @@ # distribution, for details about the copyright. # -## This module implements a `reStructuredText`:idx: parser. A large -## subset is implemented. Some features of the `markdown`:idx: wiki syntax are +## ================================== +## rst +## ================================== +## +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## Nim-flavored reStructuredText +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## +## This module implements a `reStructuredText`:idx: (RST) parser. +## A large subset is implemented with some limitations_ and +## `Nim-specific features`_. +## A few `extra features`_ of the `Markdown`:idx: syntax are ## also supported. ## -## Supported RST features: +## Nim can output the result to HTML [#html]_ or Latex [#latex]_. +## +## .. [#html] commands ``nim doc`` for ``*.nim`` files and +## ``nim rst2html`` for ``*.rst`` files +## +## .. [#latex] command ``nim rst2tex`` for ``*.rst``. +## +## If you are new to RST please consider reading the following: +## +## 1) a short `quick introduction`_ +## 2) an `RST reference`_: a comprehensive cheatsheet for RST +## 3) a more formal 50-page `RST specification`_. +## +## Features +## -------- +## +## Supported standard RST features: ## ## * body elements ## + sections @@ -20,40 +46,67 @@ ## + bullet lists using \+, \*, \- ## + enumerated lists using arabic numerals or alphabet ## characters: 1. ... 2. ... *or* a. ... b. ... *or* A. ... B. ... +## + footnotes (including manually numbered, auto-numbered, auto-numbered +## with label, and auto-symbol footnotes) and citations ## + definition lists ## + field lists ## + option lists ## + indented literal blocks ## + simple tables -## + directives -## - image, figure -## - code-block -## - substitution definitions: replace and image -## - ... a few more +## + directives (see official documentation in `RST directives list`_): +## - ``image``, ``figure`` for including images and videos +## - ``code`` +## - ``contents`` (table of contents), ``container``, ``raw`` +## - ``include`` +## - admonitions: "attention", "caution", "danger", "error", "hint", +## "important", "note", "tip", "warning", "admonition" +## - substitution definitions: `replace` and `image` ## + comments ## * inline markup -## + *emphasis*, **strong emphasis**, `interpreted text`, -## ``inline literals``, hyperlink references, substitution references, -## standalone hyperlinks +## + *emphasis*, **strong emphasis**, +## ``inline literals``, hyperlink references (including embedded URI), +## substitution references, standalone hyperlinks, +## internal links (inline and outline) +## + \`interpreted text\` with roles ``:literal:``, ``:strong:``, +## ``emphasis``, ``:sub:``/``:subscript:``, ``:sup:``/``:supscript:`` +## (see `RST roles list`_ for description). +## + inline internal targets ## -## Additional features: +## .. _`Nim-specific features`: +## +## Additional Nim-specific features: +## +## * directives: ``code-block`` [cmp:Sphinx]_, ``title``, +## ``index`` [cmp:Sphinx]_ ## ## * ***triple emphasis*** (bold and italic) using \*\*\* +## * ``:idx:`` role for \`interpreted text\` to include the link to this +## text into an index (example: `Nim index`_). +## +## .. [cmp:Sphinx] similar but different from the directives of +## Python `Sphinx directives`_ extensions +## +## .. _`extra features`: ## ## Optional additional features, turned on by ``options: RstParseOption`` in ## `rstParse proc <#rstParse,string,string,int,int,bool,RstParseOptions,FindFileHandler,MsgHandler>`_: ## ## * emoji / smiley symbols -## * markdown tables -## * markdown code blocks -## * markdown links -## * markdown headlines +## * Markdown tables +## * Markdown code blocks +## * Markdown links +## * Markdown headlines ## * using ``1`` as auto-enumerator in enumerated lists like RST ``#`` ## (auto-enumerator ``1`` can not be used with ``#`` in the same list) ## -## **Note:** By default nim has ``roSupportMarkdown`` turned **on**. +## .. Note:: By default Nim has ``roSupportMarkdown`` and +## ``roSupportRawDirective`` turned **on**. ## -## Limitations: +## .. warning:: Using Nim-specific features can cause other RST implementations +## to fail on your document. +## +## Limitations +## ----------- ## ## * no Unicode support in character width calculations ## * body elements @@ -61,17 +114,40 @@ ## - no quoted literal blocks ## - no doctest blocks ## - no grid tables -## - directives: no support for admonitions (notes, caution) -## - no footnotes & citations support -## - no inline internal targets +## - some directives are missing (check official `RST directives list`_): +## ``parsed-literal``, ``sidebar``, ``topic``, ``math``, ``rubric``, +## ``epigraph``, ``highlights``, ``pull-quote``, ``compound``, +## ``table``, ``csv-table``, ``list-table``, ``section-numbering``, +## ``header``, ``footer``, ``meta``, ``class`` +## - no ``role`` directives and no custom interpreted text roles +## - some standard roles are not supported (check `RST roles list`_) ## * inline markup ## - no simple-inline-markup -## - no embedded URI and aliases +## - no embedded aliases ## -## **Note:** Import ``packages/docutils/rst`` to use this module +## Usage +## ----- +## +## See `Nim DocGen Tools Guide `_ for the details about +## ``nim doc``, ``nim rst2html`` and ``nim rst2tex`` commands. +## +## See `packages/docutils/rstgen module `_ to know how to +## generate HTML or Latex strings to embed them into your documents. +## +## .. Tip:: Import ``packages/docutils/rst`` to use this module +## programmatically. +## +## .. _quick introduction: https://docutils.sourceforge.io/docs/user/rst/quickstart.html +## .. _RST reference: https://docutils.sourceforge.io/docs/user/rst/quickref.html +## .. _RST specification: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html +## .. _RST directives list: https://docutils.sourceforge.io/docs/ref/rst/directives.html +## .. _RST roles list: https://docutils.sourceforge.io/docs/ref/rst/roles.html +## .. _Nim index: https://nim-lang.org/docs/theindex.html +## .. _Sphinx directives: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html import - os, strutils, rstast + os, strutils, rstast, std/enumutils, algorithm, lists, sequtils, + std/private/miscdollars type RstParseOption* = enum ## options for the RST parser @@ -80,7 +156,7 @@ type roSupportSmilies, ## make the RST parser support smilies like ``:)`` roSupportRawDirective, ## support the ``raw`` directive (don't support ## it for sandboxing) - roSupportMarkdown ## support additional features of markdown + roSupportMarkdown ## support additional features of Markdown RstParseOptions* = set[RstParseOption] @@ -93,14 +169,16 @@ type meCannotOpenFile = "cannot open '$1'", meExpected = "'$1' expected", meGridTableNotImplemented = "grid table is not implemented", - meMarkdownIllformedTable = "illformed delimiter row of a markdown table", - meNewSectionExpected = "new section expected", + meMarkdownIllformedTable = "illformed delimiter row of a Markdown table", + meNewSectionExpected = "new section expected $1", meGeneralParseError = "general parse error", meInvalidDirective = "invalid directive: '$1'", + meFootnoteMismatch = "mismatch in number of footnotes and their refs: $1", mwRedefinitionOfLabel = "redefinition of label '$1'", mwUnknownSubstitution = "unknown substitution '$1'", mwUnsupportedLanguage = "language '$1' not supported", - mwUnsupportedField = "field '$1' not supported" + mwUnsupportedField = "field '$1' not supported", + mwRstStyle = "RST style: $1" MsgHandler* = proc (filename: string, line, col: int, msgKind: MsgKind, arg: string) {.closure, gcsafe.} ## what to do in case of an error @@ -234,27 +312,27 @@ proc getBracket(L: var Lexer, tok: var Token) = proc getIndentAux(L: var Lexer, start: int): int = var pos = start # skip the newline (but include it in the token!) - if L.buf[pos] == '\x0D': - if L.buf[pos + 1] == '\x0A': inc pos, 2 + if L.buf[pos] == '\r': + if L.buf[pos + 1] == '\n': inc pos, 2 else: inc pos - elif L.buf[pos] == '\x0A': + elif L.buf[pos] == '\n': inc pos if L.skipPounds: if L.buf[pos] == '#': inc pos if L.buf[pos] == '#': inc pos while true: case L.buf[pos] - of ' ', '\x0B', '\x0C': + of ' ', '\v', '\f': inc pos inc result - of '\x09': + of '\t': inc pos result = result - (result mod 8) + 8 else: break # EndOfFile also leaves the loop if L.buf[pos] == '\0': result = 0 - elif L.buf[pos] == '\x0A' or L.buf[pos] == '\x0D': + elif L.buf[pos] == '\n' or L.buf[pos] == '\r': # look at the next line for proper indentation: result = getIndentAux(L, pos) L.bufpos = pos # no need to set back buf @@ -278,12 +356,12 @@ proc rawGetTok(L: var Lexer, tok: var Token) = case c of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '0'..'9': getThing(L, tok, SymChars) - of ' ', '\x09', '\x0B', '\x0C': - getThing(L, tok, {' ', '\x09'}) + of ' ', '\t', '\v', '\f': + getThing(L, tok, {' ', '\t'}) tok.kind = tkWhite - if L.buf[L.bufpos] in {'\x0D', '\x0A'}: + if L.buf[L.bufpos] in {'\r', '\n'}: rawGetTok(L, tok) # ignore spaces before \n - of '\x0D', '\x0A': + of '\r', '\n': getIndent(L, tok) L.adornmentLine = false of '!', '\"', '#', '$', '%', '&', '\'', '*', '+', ',', '-', '.', @@ -337,24 +415,49 @@ proc getTokens(buffer: string, skipPounds: bool, tokens: var TokenSeq): int = tokens[0].kind = tkIndent type - LevelMap = array[char, int] + LevelInfo = object + symbol: char # adornment character + hasOverline: bool # has also overline (besides underline)? + line: int # the last line of this style occurrence + # (for error message) + hasPeers: bool # has headings on the same level of hierarchy? + LevelMap = seq[LevelInfo] # Saves for each possible title adornment + # style its level in the current document. Substitution = object key*: string value*: PRstNode + AnchorSubst = tuple + mainAnchor: string + aliases: seq[string] + FootnoteType = enum + fnManualNumber, # manually numbered footnote like [3] + fnAutoNumber, # auto-numbered footnote [#] + fnAutoNumberLabel, # auto-numbered with label [#label] + fnAutoSymbol, # auto-symbol footnote [*] + fnCitation # simple text label like [citation2021] + FootnoteSubst = tuple + kind: FootnoteType # discriminator + number: int # valid for fnManualNumber (always) and fnAutoNumber, + # fnAutoNumberLabel after resolveSubs is called + autoNumIdx: int # order of occurence: fnAutoNumber, fnAutoNumberLabel + autoSymIdx: int # order of occurence: fnAutoSymbol + label: string # valid for fnAutoNumberLabel SharedState = object options: RstParseOptions # parsing options - uLevel, oLevel: int # counters for the section levels + hLevels: LevelMap # hierarchy of heading styles + hTitleCnt: int # =0 if no title, =1 if only main title, + # =2 if both title and subtitle are present + hCurLevel: int # current section level subs: seq[Substitution] # substitutions refs: seq[Substitution] # references - underlineToLevel: LevelMap # Saves for each possible title adornment - # character its level in the - # current document. - # This is for single underline adornments. - overlineToLevel: LevelMap # Saves for each possible title adornment - # character its level in the current - # document. - # This is for over-underline adornments. + anchors: seq[AnchorSubst] # internal target substitutions + lineFootnoteNum: seq[int] # footnote line, auto numbers .. [#] + lineFootnoteNumRef: seq[int] # footnote line, their reference [#]_ + lineFootnoteSym: seq[int] # footnote line, auto symbols .. [*] + lineFootnoteSymRef: seq[int] # footnote line, their reference [*]_ + footnotes: seq[FootnoteSubst] # correspondence b/w footnote label, + # number, order of occurrence msgHandler: MsgHandler # How to handle errors. findFile: FindFileHandler # How to find files. @@ -365,18 +468,28 @@ type s*: PSharedState indentStack*: seq[int] filename*: string - line*, col*: int + line*, col*: int ## initial line/column of whole text or + ## documenation fragment that will be added + ## in case of error/warning reporting to + ## (relative) line/column of the token. hasToc*: bool + curAnchor*: string # variable to track latest anchor in s.anchors EParseError* = object of ValueError +const + LineRstInit* = 1 ## Initial line number for standalone RST text + ColRstInit* = 0 ## Initial column number for standalone RST text + ## (Nim global reporting adds ColOffset=1) + ColRstOffset* = 1 ## 1: a replica of ColOffset for internal use + template currentTok(p: RstParser): Token = p.tok[p.idx] template prevTok(p: RstParser): Token = p.tok[p.idx - 1] template nextTok(p: RstParser): Token = p.tok[p.idx + 1] proc whichMsgClass*(k: MsgKind): MsgClass = ## returns which message class `k` belongs to. - case ($k)[1] + case k.symbolName[1] of 'e', 'E': result = mcError of 'w', 'W': result = mcWarning of 'h', 'H': result = mcHint @@ -386,7 +499,9 @@ proc defaultMsgHandler*(filename: string, line, col: int, msgkind: MsgKind, arg: string) = let mc = msgkind.whichMsgClass let a = $msgkind % arg - let message = "$1($2, $3) $4: $5" % [filename, $line, $col, $mc, a] + var message: string + toLocation(message, filename, line, col + ColRstOffset) + message.add " $1: $2" % [$mc, a] if mc == mcError: raise newException(EParseError, message) else: writeLine(stdout, message) @@ -404,13 +519,15 @@ proc newSharedState(options: RstParseOptions, result.msgHandler = if not isNil(msgHandler): msgHandler else: defaultMsgHandler result.findFile = if not isNil(findFile): findFile else: defaultFindFile +proc curLine(p: RstParser): int = p.line + currentTok(p).line + proc findRelativeFile(p: RstParser; filename: string): string = result = p.filename.splitFile.dir / filename if not fileExists(result): result = p.s.findFile(filename) proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string) = - p.s.msgHandler(p.filename, p.line + currentTok(p).line, + p.s.msgHandler(p.filename, curLine(p), p.col + currentTok(p).col, msgKind, arg) proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string, line, col: int) = @@ -418,7 +535,7 @@ proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string, line, col: int) = p.col + col, msgKind, arg) proc rstMessage(p: RstParser, msgKind: MsgKind) = - p.s.msgHandler(p.filename, p.line + currentTok(p).line, + p.s.msgHandler(p.filename, curLine(p), p.col + currentTok(p).col, msgKind, currentTok(p).symbol) @@ -437,8 +554,8 @@ proc initParser(p: var RstParser, sharedState: PSharedState) = p.idx = 0 p.filename = "" p.hasToc = false - p.col = 0 - p.line = 1 + p.col = ColRstInit + p.line = LineRstInit p.s = sharedState proc addNodesAux(n: PRstNode, result: var string) = @@ -539,8 +656,158 @@ proc findRef(p: var RstParser, key: string): PRstNode = if key == p.s.refs[i].key: return p.s.refs[i].value +proc addAnchor(p: var RstParser, refn: string, reset: bool) = + ## add anchor `refn` to anchor aliases and update last anchor ``curAnchor`` + if p.curAnchor == "": + p.s.anchors.add (refn, @[refn]) + else: + p.s.anchors[^1].mainAnchor = refn + p.s.anchors[^1].aliases.add refn + if reset: + p.curAnchor = "" + else: + p.curAnchor = refn + +proc findMainAnchor(p: RstParser, refn: string): string = + for subst in p.s.anchors: + if subst.mainAnchor == refn: # no need to rename + result = subst.mainAnchor + break + var toLeave = false + for anchor in subst.aliases: + if anchor == refn: # this anchor will be named as mainAnchor + result = subst.mainAnchor + toLeave = true + if toLeave: + break + +proc addFootnoteNumManual(p: var RstParser, num: int) = + ## add manually-numbered footnote + for fnote in p.s.footnotes: + if fnote.number == num: + rstMessage(p, mwRedefinitionOfLabel, $num) + return + p.s.footnotes.add((fnManualNumber, num, -1, -1, $num)) + +proc addFootnoteNumAuto(p: var RstParser, label: string) = + ## add auto-numbered footnote. + ## Empty label [#] means it'll be resolved by the occurrence. + if label == "": # simple auto-numbered [#] + p.s.lineFootnoteNum.add curLine(p) + p.s.footnotes.add((fnAutoNumber, -1, p.s.lineFootnoteNum.len, -1, label)) + else: # auto-numbered with label [#label] + for fnote in p.s.footnotes: + if fnote.label == label: + rstMessage(p, mwRedefinitionOfLabel, label) + return + p.s.footnotes.add((fnAutoNumberLabel, -1, -1, -1, label)) + +proc addFootnoteSymAuto(p: var RstParser) = + p.s.lineFootnoteSym.add curLine(p) + p.s.footnotes.add((fnAutoSymbol, -1, -1, p.s.lineFootnoteSym.len, "")) + +proc orderFootnotes(p: var RstParser) = + ## numerate auto-numbered footnotes taking into account that all + ## manually numbered ones always have preference. + ## Save the result back to p.s.footnotes. + + # Report an error if found any mismatch in number of automatic footnotes + proc listFootnotes(lines: seq[int]): string = + result.add $lines.len & " (lines " & join(lines, ", ") & ")" + if p.s.lineFootnoteNum.len != p.s.lineFootnoteNumRef.len: + rstMessage(p, meFootnoteMismatch, + "$1 != $2" % [listFootnotes(p.s.lineFootnoteNum), + listFootnotes(p.s.lineFootnoteNumRef)] & + " for auto-numbered footnotes") + if p.s.lineFootnoteSym.len != p.s.lineFootnoteSymRef.len: + rstMessage(p, meFootnoteMismatch, + "$1 != $2" % [listFootnotes(p.s.lineFootnoteSym), + listFootnotes(p.s.lineFootnoteSymRef)] & + " for auto-symbol footnotes") + + var result: seq[FootnoteSubst] + var manuallyN, autoN, autoSymbol: seq[FootnoteSubst] + for fs in p.s.footnotes: + if fs.kind == fnManualNumber: manuallyN.add fs + elif fs.kind in {fnAutoNumber, fnAutoNumberLabel}: autoN.add fs + else: autoSymbol.add fs + + if autoN.len == 0: + result = manuallyN + else: + # fill gaps between manually numbered footnotes in ascending order + manuallyN.sort() # sort by number - its first field + var lst = initSinglyLinkedList[FootnoteSubst]() + for elem in manuallyN: lst.append(elem) + var firstAuto = 0 + if lst.head == nil or lst.head.value.number != 1: + # no manual footnote [1], start numeration from 1 for auto-numbered + lst.prepend (autoN[0].kind, 1, autoN[0].autoNumIdx, -1, autoN[0].label) + firstAuto = 1 + var curNode = lst.head + var nextNode: SinglyLinkedNode[FootnoteSubst] + # go simultaneously through `autoN` and `lst` looking for gaps + for (kind, x, autoNumIdx, y, label) in autoN[firstAuto .. ^1]: + while (nextNode = curNode.next; nextNode != nil): + if nextNode.value.number - curNode.value.number > 1: + # gap found, insert new node `n` between curNode and nextNode: + var n = newSinglyLinkedNode((kind, curNode.value.number + 1, + autoNumIdx, -1, label)) + curNode.next = n + n.next = nextNode + curNode = n + break + else: + curNode = nextNode + if nextNode == nil: # no gap found, just append + lst.append (kind, curNode.value.number + 1, autoNumIdx, -1, label) + curNode = lst.tail + result = lst.toSeq + + # we use ASCII symbols instead of those recommended in RST specification: + const footnoteAutoSymbols = ["*", "^", "+", "=", "~", "$", "@", "%", "&"] + for fs in autoSymbol: + # assignment order: *, **, ***, ^, ^^, ^^^, ... &&&, ****, *****, ... + let i = fs.autoSymIdx - 1 + let symbolNum = (i div 3) mod footnoteAutoSymbols.len + let nSymbols = (1 + i mod 3) + 3 * (i div (3 * footnoteAutoSymbols.len)) + let label = footnoteAutoSymbols[symbolNum].repeat(nSymbols) + result.add((fs.kind, -1, -1, fs.autoSymIdx, label)) + + p.s.footnotes = result + +proc getFootnoteNum(p: var RstParser, label: string): int = + ## get number from label. Must be called after `orderFootnotes`. + result = -1 + for fnote in p.s.footnotes: + if fnote.label == label: + return fnote.number + +proc getFootnoteNum(p: var RstParser, order: int): int = + ## get number from occurrence. Must be called after `orderFootnotes`. + result = -1 + for fnote in p.s.footnotes: + if fnote.autoNumIdx == order: + return fnote.number + +proc getAutoSymbol(p: var RstParser, order: int): string = + ## get symbol from occurrence of auto-symbol footnote. + result = "???" + for fnote in p.s.footnotes: + if fnote.autoSymIdx == order: + return fnote.label + +proc newRstNodeA(p: var RstParser, kind: RstNodeKind): PRstNode = + ## create node and consume the current anchor + result = newRstNode(kind) + if p.curAnchor != "": + result.anchor = p.curAnchor + p.curAnchor = "" + +template newLeaf(s: string): PRstNode = newRstLeaf(s) + proc newLeaf(p: var RstParser): PRstNode = - result = newRstNode(rnLeaf, currentTok(p).symbol) + result = newLeaf(currentTok(p).symbol) proc getReferenceName(p: var RstParser, endStr: string): PRstNode = var res = newRstNode(rnInner) @@ -591,7 +858,10 @@ proc isInlineMarkupEnd(p: RstParser, markup: string): bool = proc isInlineMarkupStart(p: RstParser, markup: string): bool = # rst rules: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules var d: char - result = currentTok(p).symbol == markup + if markup != "_`": + result = currentTok(p).symbol == markup + else: # _` is a 2 token case + result = currentTok(p).symbol == "_" and nextTok(p).symbol == "`" if not result: return # Rule 6: result = p.idx == 0 or prevTok(p).kind in {tkIndent, tkWhite} or @@ -623,6 +893,7 @@ proc match(p: RstParser, start: int, expr: string): bool = # ' ' tkWhite # 'a' tkAdornment # 'i' tkIndent + # 'I' tkIndent or tkEof # 'p' tkPunct # 'T' always true # 'E' whitespace, indent or eof @@ -637,6 +908,7 @@ proc match(p: RstParser, start: int, expr: string): bool = of 'w': result = p.tok[j].kind == tkWord of ' ': result = p.tok[j].kind == tkWhite of 'i': result = p.tok[j].kind == tkIndent + of 'I': result = p.tok[j].kind in {tkIndent, tkEof} of 'p': result = p.tok[j].kind == tkPunct of 'a': result = p.tok[j].kind == tkAdornment of 'o': result = p.tok[j].kind == tkOther @@ -678,7 +950,8 @@ proc fixupEmbeddedRef(n, a, b: PRstNode) = for i in countup(sep + 1, n.len - 2): b.add(n.sons[i]) proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = - result = n + var newKind = n.kind + var newSons = n.sons if isInlineMarkupEnd(p, "_") or isInlineMarkupEnd(p, "__"): inc p.idx if p.tok[p.idx-2].symbol == "`" and p.tok[p.idx-3].symbol == ">": @@ -686,40 +959,42 @@ proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode = var b = newRstNode(rnInner) fixupEmbeddedRef(n, a, b) if a.len == 0: - result = newRstNode(rnStandaloneHyperlink) - result.add(b) + newKind = rnStandaloneHyperlink + newSons = @[b] else: - result = newRstNode(rnHyperlink) - result.add(a) - result.add(b) + newKind = rnHyperlink + newSons = @[a, b] setRef(p, rstnodeToRefname(a), b) elif n.kind == rnInterpretedText: - n.kind = rnRef + newKind = rnRef else: - result = newRstNode(rnRef) - result.add(n) + newKind = rnRef + newSons = @[n] + result = newRstNode(newKind, newSons) elif match(p, p.idx, ":w:"): # a role: if nextTok(p).symbol == "idx": - n.kind = rnIdx + newKind = rnIdx elif nextTok(p).symbol == "literal": - n.kind = rnInlineLiteral + newKind = rnInlineLiteral elif nextTok(p).symbol == "strong": - n.kind = rnStrongEmphasis + newKind = rnStrongEmphasis elif nextTok(p).symbol == "emphasis": - n.kind = rnEmphasis + newKind = rnEmphasis elif nextTok(p).symbol == "sub" or nextTok(p).symbol == "subscript": - n.kind = rnSub + newKind = rnSub elif nextTok(p).symbol == "sup" or nextTok(p).symbol == "supscript": - n.kind = rnSup + newKind = rnSup else: - result = newRstNode(rnGeneralRole) - n.kind = rnInner - result.add(n) - result.add(newRstNode(rnLeaf, nextTok(p).symbol)) + newKind = rnGeneralRole + let newN = newRstNode(rnInner, n.sons) + newSons = @[newN, newLeaf(nextTok(p).symbol)] inc p.idx, 3 + result = newRstNode(newKind, newSons) + else: # no change + result = n proc matchVerbatim(p: RstParser, start: int, expr: string): int = result = start @@ -740,14 +1015,21 @@ proc parseSmiley(p: var RstParser): PRstNode = result.text = val return +proc validRefnamePunct(x: string): bool = + ## https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#reference-names + x.len == 1 and x[0] in {'-', '_', '.', ':', '+'} + proc isUrl(p: RstParser, i: int): bool = result = p.tok[i+1].symbol == ":" and p.tok[i+2].symbol == "//" and p.tok[i+3].kind == tkWord and p.tok[i].symbol in ["http", "https", "ftp", "telnet", "file"] -proc parseUrl(p: var RstParser, father: PRstNode) = - #if currentTok(p).symbol[strStart] == '<': - if isUrl(p, p.idx): +proc parseWordOrRef(p: var RstParser, father: PRstNode) = + ## Parses a normal word or may be a reference or URL. + if nextTok(p).kind != tkPunct: # <- main path, a normal word + father.add newLeaf(p) + inc p.idx + elif isUrl(p, p.idx): # URL http://something var n = newRstNode(rnStandaloneHyperlink) while true: case currentTok(p).kind @@ -760,15 +1042,31 @@ proc parseUrl(p: var RstParser, father: PRstNode) = inc p.idx father.add(n) else: - var n = newLeaf(p) + # check for reference (probably, long one like some.ref.with.dots_ ) + var saveIdx = p.idx + var isRef = false inc p.idx - if currentTok(p).symbol == "_": n = parsePostfix(p, n) - father.add(n) + while currentTok(p).kind in {tkWord, tkPunct}: + if currentTok(p).kind == tkPunct: + if isInlineMarkupEnd(p, "_"): + isRef = true + break + if not validRefnamePunct(currentTok(p).symbol): + break + inc p.idx + if isRef: + let r = newRstNode(rnRef) + for i in saveIdx..p.idx-1: r.add newLeaf(p.tok[i].symbol) + father.add r + inc p.idx # skip final _ + else: # 1 normal word + father.add newLeaf(p.tok[saveIdx].symbol) + p.idx = saveIdx + 1 proc parseBackslash(p: var RstParser, father: PRstNode) = assert(currentTok(p).kind == tkPunct) if currentTok(p).symbol == "\\\\": - father.add(newRstNode(rnLeaf, "\\")) + father.add newLeaf("\\") inc p.idx elif currentTok(p).symbol == "\\": # XXX: Unicode? @@ -800,13 +1098,13 @@ proc parseUntil(p: var RstParser, father: PRstNode, postfix: string, father.add(newLeaf(p)) inc p.idx of tkIndent: - father.add(newRstNode(rnLeaf, " ")) + father.add newLeaf(" ") inc p.idx if currentTok(p).kind == tkIndent: rstMessage(p, meExpected, postfix, line, col) break of tkWhite: - father.add(newRstNode(rnLeaf, " ")) + father.add newLeaf(" ") inc p.idx else: rstMessage(p, meExpected, postfix, line, col) @@ -817,7 +1115,7 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode = inc p.idx else: args = nil - var n = newRstNode(rnLeaf, "") + var n = newLeaf("") while true: case currentTok(p).kind of tkEof: @@ -835,7 +1133,7 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode = inc p.idx var lb = newRstNode(rnLiteralBlock) lb.add(n) - result = newRstNode(rnCodeBlock) + result = newRstNodeA(p, rnCodeBlock) result.add(args) result.add(PRstNode(nil)) result.add(lb) @@ -865,7 +1163,56 @@ proc parseMarkdownLink(p: var RstParser; father: PRstNode): bool = p.idx = i result = true +proc getFootnoteType(label: PRstNode): (FootnoteType, int) = + if label.sons.len >= 1 and label.sons[0].kind == rnLeaf and + label.sons[0].text == "#": + if label.sons.len == 1: + result = (fnAutoNumber, -1) + else: + result = (fnAutoNumberLabel, -1) + elif label.len == 1 and label.sons[0].kind == rnLeaf and + label.sons[0].text == "*": + result = (fnAutoSymbol, -1) + elif label.len == 1 and label.sons[0].kind == rnLeaf: + try: + result = (fnManualNumber, parseInt(label.sons[0].text)) + except: + result = (fnCitation, -1) + else: + result = (fnCitation, -1) + +proc parseFootnoteName(p: var RstParser, reference: bool): PRstNode = + ## parse footnote/citation label. Precondition: start at `[`. + ## Label text should be valid ref. name symbol, otherwise nil is returned. + var i = p.idx + 1 + result = newRstNode(rnInner) + while true: + if p.tok[i].kind in {tkEof, tkIndent, tkWhite}: + return nil + if p.tok[i].kind == tkPunct: + case p.tok[i].symbol: + of "]": + if i > p.idx + 1 and (not reference or (p.tok[i+1].kind == tkPunct and p.tok[i+1].symbol == "_")): + inc i # skip ] + if reference: inc i # skip _ + break # to succeed, it's a footnote/citation indeed + else: + return nil + of "#": + if i != p.idx + 1: + return nil + of "*": + if i != p.idx + 1 and p.tok[i].kind != tkPunct and p.tok[i+1].symbol != "]": + return nil + else: + if not validRefnamePunct(p.tok[i].symbol): + return nil + result.add newLeaf(p.tok[i].symbol) + inc i + p.idx = i + proc parseInline(p: var RstParser, father: PRstNode) = + var n: PRstNode # to be used in `if` condition case currentTok(p).kind of tkPunct: if isInlineMarkupStart(p, "***"): @@ -880,6 +1227,13 @@ proc parseInline(p: var RstParser, father: PRstNode) = var n = newRstNode(rnEmphasis) parseUntil(p, n, "*", true) father.add(n) + elif isInlineMarkupStart(p, "_`"): + var n = newRstNode(rnInlineTarget) + inc p.idx + parseUntil(p, n, "`", false) + let refn = rstnodeToRefname(n) + p.s.anchors.add (refn, @[refn]) + father.add(n) elif roSupportMarkdown in p.s.options and currentTok(p).symbol == "```": inc p.idx father.add(parseMarkdownCodeblock(p)) @@ -900,6 +1254,20 @@ proc parseInline(p: var RstParser, father: PRstNode) = currentTok(p).symbol == "[" and nextTok(p).symbol != "[" and parseMarkdownLink(p, father): discard "parseMarkdownLink already processed it" + elif isInlineMarkupStart(p, "[") and nextTok(p).symbol != "[" and + (n = parseFootnoteName(p, reference=true); n != nil): + var nn = newRstNode(rnFootnoteRef) + nn.add n + let (fnType, _) = getFootnoteType(n) + case fnType + of fnAutoSymbol: + p.s.lineFootnoteSymRef.add curLine(p) + nn.order = p.s.lineFootnoteSymRef.len + of fnAutoNumber: + p.s.lineFootnoteNumRef.add curLine(p) + nn.order = p.s.lineFootnoteNumRef.len + else: discard + father.add(nn) else: if roSupportSmilies in p.s.options: let n = parseSmiley(p) @@ -913,7 +1281,7 @@ proc parseInline(p: var RstParser, father: PRstNode) = if n != nil: father.add(n) return - parseUrl(p, father) + parseWordOrRef(p, father) of tkAdornment, tkOther, tkWhite: if roSupportMarkdown in p.s.options and currentTok(p).symbol == "```": inc p.idx @@ -947,6 +1315,7 @@ proc getDirective(p: var RstParser): string = result = "" # error else: result = "" + result = result.toLowerAscii() proc parseComment(p: var RstParser): PRstNode = case currentTok(p).kind @@ -968,21 +1337,6 @@ proc parseComment(p: var RstParser): PRstNode = while currentTok(p).kind notin {tkIndent, tkEof}: inc p.idx result = nil -type - DirKind = enum # must be ordered alphabetically! - dkNone, dkAuthor, dkAuthors, dkCode, dkCodeBlock, dkContainer, dkContents, - dkFigure, dkImage, dkInclude, dkIndex, dkRaw, dkTitle - -const - DirIds: array[0..12, string] = ["", "author", "authors", "code", - "code-block", "container", "contents", "figure", "image", "include", - "index", "raw", "title"] - -proc getDirKind(s: string): DirKind = - let i = find(DirIds, s) - if i >= 0: result = DirKind(i) - else: result = dkNone - proc parseLine(p: var RstParser, father: PRstNode) = while true: case currentTok(p).kind @@ -1025,7 +1379,7 @@ proc parseFields(p: var RstParser): PRstNode = if currentTok(p).kind == tkIndent and nextTok(p).symbol == ":" or atStart: var col = if atStart: currentTok(p).col else: currentTok(p).ival - result = newRstNode(rnFieldList) + result = newRstNodeA(p, rnFieldList) if not atStart: inc p.idx while true: result.add(parseField(p)) @@ -1066,8 +1420,8 @@ proc getArgument(n: PRstNode): string = proc parseDotDot(p: var RstParser): PRstNode {.gcsafe.} proc parseLiteralBlock(p: var RstParser): PRstNode = - result = newRstNode(rnLiteralBlock) - var n = newRstNode(rnLeaf, "") + result = newRstNodeA(p, rnLiteralBlock) + var n = newLeaf("") if currentTok(p).kind == tkIndent: var indent = currentTok(p).ival inc p.idx @@ -1091,14 +1445,33 @@ proc parseLiteralBlock(p: var RstParser): PRstNode = inc p.idx result.add(n) -proc getLevel(map: var LevelMap, lvl: var int, c: char): int = - if map[c] == 0: - inc lvl - map[c] = lvl - result = map[c] +proc getLevel(p: var RstParser, c: char, hasOverline: bool): int = + ## Returns (preliminary) heading level corresponding to `c` and + ## `hasOverline`. If level does not exist, add it first. + for i, hType in p.s.hLevels: + if hType.symbol == c and hType.hasOverline == hasOverline: + p.s.hLevels[i].line = curLine(p) + p.s.hLevels[i].hasPeers = true + return i + p.s.hLevels.add LevelInfo(symbol: c, hasOverline: hasOverline, + line: curLine(p), hasPeers: false) + result = p.s.hLevels.len - 1 -proc tokenAfterNewline(p: RstParser): int = - result = p.idx +proc countTitles(p: var RstParser, n: PRstNode) = + ## Fill `p.s.hTitleCnt` + for node in n.sons: + if node != nil: + if node.kind notin {rnOverline, rnSubstitutionDef, rnDefaultRole}: + break + if node.kind == rnOverline: + if p.s.hLevels[p.s.hTitleCnt].hasPeers: + break + inc p.s.hTitleCnt + if p.s.hTitleCnt >= 2: + break + +proc tokenAfterNewline(p: RstParser, start: int): int = + result = start while true: case p.tok[result].kind of tkEof: @@ -1108,22 +1481,52 @@ proc tokenAfterNewline(p: RstParser): int = break else: inc result +proc tokenAfterNewline(p: RstParser): int {.inline.} = + result = tokenAfterNewline(p, p.idx) + proc isAdornmentHeadline(p: RstParser, adornmentIdx: int): bool = + ## check that underline/overline length is enough for the heading. + ## No support for Unicode. + if p.tok[adornmentIdx].symbol in ["::", "..", "|"]: + return false var headlineLen = 0 - if p.idx < adornmentIdx: # underline + var failure = "" + if p.idx < adornmentIdx: # check for underline + if p.idx > 0: + headlineLen = currentTok(p).col - p.tok[adornmentIdx].col + if headlineLen > 0: + rstMessage(p, mwRstStyle, "indentation of heading text allowed" & + " only for overline titles") for i in p.idx ..< adornmentIdx-1: # adornmentIdx-1 is a linebreak headlineLen += p.tok[i].symbol.len - else: # overline + result = p.tok[adornmentIdx].symbol.len >= headlineLen and headlineLen != 0 + if not result: + failure = "(underline '" & p.tok[adornmentIdx].symbol & "' is too short)" + else: # p.idx == adornmentIdx, at overline. Check overline and underline var i = p.idx + 2 + headlineLen = p.tok[i].col - p.tok[adornmentIdx].col while p.tok[i].kind notin {tkEof, tkIndent}: headlineLen += p.tok[i].symbol.len inc i - return p.tok[adornmentIdx].symbol.len >= headlineLen + result = p.tok[adornmentIdx].symbol.len >= headlineLen and + headlineLen != 0 + if result: + result = result and p.tok[i].kind == tkIndent and + p.tok[i+1].kind == tkAdornment and + p.tok[i+1].symbol == p.tok[adornmentIdx].symbol + if not result: + failure = "(underline '" & p.tok[i+1].symbol & "' does not match " & + "overline '" & p.tok[adornmentIdx].symbol & "')" + else: + failure = "(overline '" & p.tok[adornmentIdx].symbol & "' is too short)" + if not result: + rstMessage(p, meNewSectionExpected, failure) proc isLineBlock(p: RstParser): bool = var j = tokenAfterNewline(p) result = currentTok(p).col == p.tok[j].col and p.tok[j].symbol == "|" or - p.tok[j].col > currentTok(p).col + p.tok[j].col > currentTok(p).col or + p.tok[j].symbol == "\n" proc predNL(p: RstParser): bool = result = true @@ -1171,7 +1574,7 @@ proc whichSection(p: RstParser): RstNodeKind = return rnDirective case currentTok(p).kind of tkAdornment: - if match(p, p.idx + 1, "ii") and currentTok(p).symbol.len >= 4: + if match(p, p.idx + 1, "iI") and currentTok(p).symbol.len >= 4: result = rnTransition elif match(p, p.idx, "+a+"): result = rnGridTable @@ -1185,13 +1588,14 @@ proc whichSection(p: RstParser): RstNodeKind = result = rnLeaf of tkPunct: if isMarkdownHeadline(p): - result = rnHeadline + result = rnMarkdownHeadline elif roSupportMarkdown in p.s.options and predNL(p) and match(p, p.idx, "| w") and findPipe(p, p.idx+3): result = rnMarkdownTable elif currentTok(p).symbol == "|" and isLineBlock(p): result = rnLineBlock - elif match(p, tokenAfterNewline(p), "ai"): + elif match(p, tokenAfterNewline(p), "aI") and + isAdornmentHeadline(p, tokenAfterNewline(p)): result = rnHeadline elif predNL(p) and currentTok(p).symbol in ["+", "*", "-"] and nextTok(p).kind == tkWhite: @@ -1210,7 +1614,7 @@ proc whichSection(p: RstParser): RstNodeKind = result = rnParagraph of tkWord, tkOther, tkWhite: let tokIdx = tokenAfterNewline(p) - if match(p, tokIdx, "ai"): + if match(p, tokIdx, "aI"): if isAdornmentHeadline(p, tokIdx): result = rnHeadline else: result = rnParagraph elif match(p, p.idx, "e) ") or match(p, p.idx, "e. "): result = rnEnumList @@ -1219,22 +1623,30 @@ proc whichSection(p: RstParser): RstNodeKind = else: result = rnLeaf proc parseLineBlock(p: var RstParser): PRstNode = + ## Returns rnLineBlock with all sons of type rnLineBlockItem result = nil - if nextTok(p).kind == tkWhite: + if nextTok(p).kind in {tkWhite, tkIndent}: var col = currentTok(p).col - result = newRstNode(rnLineBlock) - pushInd(p, p.tok[p.idx + 2].col) - inc p.idx, 2 + result = newRstNodeA(p, rnLineBlock) while true: var item = newRstNode(rnLineBlockItem) - parseSection(p, item) + if nextTok(p).kind == tkWhite: + if nextTok(p).symbol.len > 1: # pass additional indentation after '| ' + item.lineIndent = nextTok(p).symbol + inc p.idx, 2 + pushInd(p, p.tok[p.idx].col) + parseSection(p, item) + popInd(p) + else: # tkIndent => add an empty line + item.lineIndent = "\n" + inc p.idx, 1 result.add(item) if currentTok(p).kind == tkIndent and currentTok(p).ival == col and - nextTok(p).symbol == "|" and p.tok[p.idx + 2].kind == tkWhite: - inc p.idx, 3 + nextTok(p).symbol == "|" and + p.tok[p.idx + 2].kind in {tkWhite, tkIndent}: + inc p.idx, 1 else: break - popInd(p) proc parseParagraph(p: var RstParser, result: PRstNode) = while true: @@ -1246,8 +1658,9 @@ proc parseParagraph(p: var RstParser, result: PRstNode) = elif currentTok(p).ival == currInd(p): inc p.idx case whichSection(p) - of rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective: - result.add(newRstNode(rnLeaf, " ")) + of rnParagraph, rnLeaf, rnHeadline, rnMarkdownHeadline, + rnOverline, rnDirective: + result.add newLeaf(" ") of rnLineBlock: result.addIfNotNil(parseLineBlock(p)) else: break @@ -1257,7 +1670,7 @@ proc parseParagraph(p: var RstParser, result: PRstNode) = if currentTok(p).symbol == "::" and nextTok(p).kind == tkIndent and currInd(p) < nextTok(p).ival: - result.add(newRstNode(rnLeaf, ":")) + result.add newLeaf(":") inc p.idx # skip '::' result.add(parseLiteralBlock(p)) break @@ -1267,20 +1680,61 @@ proc parseParagraph(p: var RstParser, result: PRstNode) = parseInline(p, result) else: break +proc checkHeadingHierarchy(p: RstParser, lvl: int) = + if lvl - p.s.hCurLevel > 1: # broken hierarchy! + proc descr(l: int): string = + (if p.s.hLevels[l].hasOverline: "overline " else: "underline ") & + repeat(p.s.hLevels[l].symbol, 5) + var msg = "(section level inconsistent: " + msg.add descr(lvl) & " unexpectedly found, " & + "while the following intermediate section level(s) are missing on lines " + msg.add $p.s.hLevels[p.s.hCurLevel].line & ".." & $curLine(p) & ":" + for l in p.s.hCurLevel+1 .. lvl-1: + msg.add " " & descr(l) + if l != lvl-1: msg.add "," + rstMessage(p, meNewSectionExpected, msg & ")") + proc parseHeadline(p: var RstParser): PRstNode = - result = newRstNode(rnHeadline) if isMarkdownHeadline(p): + result = newRstNode(rnMarkdownHeadline) + # Note that level hierarchy is not checked for markdown headings result.level = currentTok(p).symbol.len assert(nextTok(p).kind == tkWhite) inc p.idx, 2 parseUntilNewline(p, result) else: + result = newRstNode(rnHeadline) parseUntilNewline(p, result) assert(currentTok(p).kind == tkIndent) assert(nextTok(p).kind == tkAdornment) var c = nextTok(p).symbol[0] inc p.idx, 2 - result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c) + result.level = getLevel(p, c, hasOverline=false) + checkHeadingHierarchy(p, result.level) + p.s.hCurLevel = result.level + addAnchor(p, rstnodeToRefname(result), reset=true) + +proc parseOverline(p: var RstParser): PRstNode = + var c = currentTok(p).symbol[0] + inc p.idx, 2 + result = newRstNode(rnOverline) + while true: + parseUntilNewline(p, result) + if currentTok(p).kind == tkIndent: + inc p.idx + if prevTok(p).ival > currInd(p): + result.add newLeaf(" ") + else: + break + else: + break + result.level = getLevel(p, c, hasOverline=true) + checkHeadingHierarchy(p, result.level) + p.s.hCurLevel = result.level + if currentTok(p).kind == tkAdornment: + inc p.idx + if currentTok(p).kind == tkIndent: inc p.idx + addAnchor(p, rstnodeToRefname(result), reset=true) type IntSeq = seq[int] @@ -1316,7 +1770,7 @@ proc parseSimpleTable(p: var RstParser): PRstNode = c: char q: RstParser a, b: PRstNode - result = newRstNode(rnTable) + result = newRstNodeA(p, rnTable) cols = @[] row = @[] a = nil @@ -1331,7 +1785,8 @@ proc parseSimpleTable(p: var RstParser): PRstNode = getColumns(p, cols) setLen(row, cols.len) if a != nil: - for j in 0 ..< a.len: a.sons[j].kind = rnTableHeaderCell + for j in 0 ..< a.len: # fix rnTableDataCell -> rnTableHeaderCell + a.sons[j] = newRstNode(rnTableHeaderCell, a.sons[j].sons) if currentTok(p).kind == tkEof: break for j in countup(0, high(row)): row[j] = "" # the following while loop iterates over the lines a single cell may span: @@ -1348,7 +1803,7 @@ proc parseSimpleTable(p: var RstParser): PRstNode = if currentTok(p).kind == tkIndent: inc p.idx if tokEnd(p) <= cols[0]: break if currentTok(p).kind in {tkEof, tkAdornment}: break - for j in countup(1, high(row)): row[j].add('\x0A') + for j in countup(1, high(row)): row[j].add('\n') a = newRstNode(rnTableRow) for j in countup(0, high(row)): initParser(q, p.s) @@ -1395,7 +1850,7 @@ proc parseMarkdownTable(p: var RstParser): PRstNode = colNum: int a, b: PRstNode q: RstParser - result = newRstNode(rnMarkdownTable) + result = newRstNodeA(p, rnMarkdownTable) proc parseRow(p: var RstParser, cellKind: RstNodeKind, result: PRstNode) = row = readTableRow(p) @@ -1419,36 +1874,17 @@ proc parseMarkdownTable(p: var RstParser): PRstNode = parseRow(p, rnTableDataCell, result) proc parseTransition(p: var RstParser): PRstNode = - result = newRstNode(rnTransition) + result = newRstNodeA(p, rnTransition) inc p.idx if currentTok(p).kind == tkIndent: inc p.idx if currentTok(p).kind == tkIndent: inc p.idx -proc parseOverline(p: var RstParser): PRstNode = - var c = currentTok(p).symbol[0] - inc p.idx, 2 - result = newRstNode(rnOverline) - while true: - parseUntilNewline(p, result) - if currentTok(p).kind == tkIndent: - inc p.idx - if prevTok(p).ival > currInd(p): - result.add(newRstNode(rnLeaf, " ")) - else: - break - else: - break - result.level = getLevel(p.s.overlineToLevel, p.s.oLevel, c) - if currentTok(p).kind == tkAdornment: - inc p.idx # XXX: check? - if currentTok(p).kind == tkIndent: inc p.idx - proc parseBulletList(p: var RstParser): PRstNode = result = nil if nextTok(p).kind == tkWhite: var bullet = currentTok(p).symbol var col = currentTok(p).col - result = newRstNode(rnBulletList) + result = newRstNodeA(p, rnBulletList) pushInd(p, p.tok[p.idx + 2].col) inc p.idx, 2 while true: @@ -1464,7 +1900,7 @@ proc parseBulletList(p: var RstParser): PRstNode = popInd(p) proc parseOptionList(p: var RstParser): PRstNode = - result = newRstNode(rnOptionList) + result = newRstNodeA(p, rnOptionList) while true: if isOptionList(p): var a = newRstNode(rnOptionGroup) @@ -1497,7 +1933,7 @@ proc parseDefinitionList(p: var RstParser): PRstNode = if j >= 1 and p.tok[j].kind == tkIndent and p.tok[j].ival > currInd(p) and p.tok[j - 1].symbol != "::": var col = currentTok(p).col - result = newRstNode(rnDefList) + result = newRstNodeA(p, rnDefList) while true: j = p.idx var a = newRstNode(rnDefName) @@ -1535,22 +1971,50 @@ proc parseEnumList(p: var RstParser): PRstNode = wildToken: array[0..5, int] = [4, 3, 3, 4, 3, 3] # number of tokens wildIndex: array[0..5, int] = [1, 0, 0, 1, 0, 0] # position of enumeration sequence (number/letter) in enumerator - result = newRstNode(rnEnumList) let col = currentTok(p).col var w = 0 while w < wildcards.len: if match(p, p.idx, wildcards[w]): break inc w assert w < wildcards.len + + proc checkAfterNewline(p: RstParser, report: bool): bool = + ## If no indentation on the next line then parse as a normal paragraph + ## according to the RST spec. And report a warning with suggestions + let j = tokenAfterNewline(p, start=p.idx+1) + let requiredIndent = p.tok[p.idx+wildToken[w]].col + if p.tok[j].kind notin {tkIndent, tkEof} and + p.tok[j].col < requiredIndent and + (p.tok[j].col > col or + (p.tok[j].col == col and not match(p, j, wildcards[w]))): + if report: + let n = p.line + p.tok[j].line + let msg = "\n" & """ + not enough indentation on line $2 + (should be at column $3 if it's a continuation of enum. list), + or no blank line after line $1 (if it should be the next paragraph), + or no escaping \ at the beginning of line $1 + (if lines $1..$2 are a normal paragraph, not enum. list)""". + unindent(8) + let c = p.col + requiredIndent + ColRstOffset + rstMessage(p, mwRstStyle, msg % [$(n-1), $n, $c], + p.tok[j].line, p.tok[j].col) + result = false + else: + result = true + + if not checkAfterNewline(p, report = true): + return nil + result = newRstNodeA(p, rnEnumList) let autoEnums = if roSupportMarkdown in p.s.options: @["#", "1"] else: @["#"] var prevAE = "" # so as not allow mixing auto-enumerators `1` and `#` var curEnum = 1 for i in 0 ..< wildToken[w]-1: # add first enumerator with (, ), and . if p.tok[p.idx + i].symbol == "#": prevAE = "#" - result.text.add "1" + result.labelFmt.add "1" else: - result.text.add p.tok[p.idx + i].symbol + result.labelFmt.add p.tok[p.idx + i].symbol var prevEnum = p.tok[p.idx + wildIndex[w]].symbol inc p.idx, wildToken[w] while true: @@ -1561,6 +2025,10 @@ proc parseEnumList(p: var RstParser): PRstNode = result.add(item) if currentTok(p).kind == tkIndent and currentTok(p).ival == col and match(p, p.idx+1, wildcards[w]): + # don't report to avoid duplication of warning since for + # subsequent enum. items parseEnumList will be called second time: + if not checkAfterNewline(p, report = false): + break let enumerator = p.tok[p.idx + 1 + wildIndex[w]].symbol # check that it's in sequence: enumerator == next(prevEnum) if "n" in wildcards[w]: # arabic numeral @@ -1590,6 +2058,7 @@ proc sonKind(father: PRstNode, i: int): RstNodeKind = if i < father.len: result = father.sons[i].kind proc parseSection(p: var RstParser, result: PRstNode) = + ## parse top-level RST elements: sections, transitions and body elements. while true: var leave = false assert(p.idx >= 0) @@ -1598,7 +2067,7 @@ proc parseSection(p: var RstParser, result: PRstNode) = inc p.idx elif currentTok(p).ival > currInd(p): pushInd(p, currentTok(p).ival) - var a = newRstNode(rnBlockQuote) + var a = newRstNodeA(p, rnBlockQuote) parseSection(p, a) result.add(a) popInd(p) @@ -1618,14 +2087,14 @@ proc parseSection(p: var RstParser, result: PRstNode) = of rnLineBlock: a = parseLineBlock(p) of rnDirective: a = parseDotDot(p) of rnEnumList: a = parseEnumList(p) - of rnLeaf: rstMessage(p, meNewSectionExpected) + of rnLeaf: rstMessage(p, meNewSectionExpected, "(syntax error)") of rnParagraph: discard of rnDefList: a = parseDefinitionList(p) of rnFieldList: if p.idx > 0: dec p.idx a = parseFields(p) of rnTransition: a = parseTransition(p) - of rnHeadline: a = parseHeadline(p) + of rnHeadline, rnMarkdownHeadline: a = parseHeadline(p) of rnOverline: a = parseOverline(p) of rnTable: a = parseSimpleTable(p) of rnMarkdownTable: a = parseMarkdownTable(p) @@ -1634,11 +2103,12 @@ proc parseSection(p: var RstParser, result: PRstNode) = #InternalError("rst.parseSection()") discard if a == nil and k != rnDirective: - a = newRstNode(rnParagraph) + a = newRstNodeA(p, rnParagraph) parseParagraph(p, a) result.addIfNotNil(a) if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph: - result.sons[0].kind = rnInner + result.sons[0] = newRstNode(rnInner, result.sons[0].sons, + anchor=result.sons[0].anchor) proc parseSectionWrapper(p: var RstParser): PRstNode = result = newRstNode(rnInner) @@ -1660,17 +2130,17 @@ type DirFlags = set[DirFlag] SectionParser = proc (p: var RstParser): PRstNode {.nimcall.} -proc parseDirective(p: var RstParser, flags: DirFlags): PRstNode = +proc parseDirective(p: var RstParser, k: RstNodeKind, flags: DirFlags): PRstNode = ## Parses arguments and options for a directive block. ## ## A directive block will always have three sons: the arguments for the - ## directive (rnDirArg), the options (rnFieldList) and the block - ## (rnLineBlock). This proc parses the two first nodes, the block is left to + ## directive (rnDirArg), the options (rnFieldList) and the directive + ## content block. This proc parses the two first nodes, the 3rd is left to ## the outer `parseDirective` call. ## ## Both rnDirArg and rnFieldList children nodes might be nil, so you need to ## check them before accessing. - result = newRstNode(rnDirective) + result = newRstNodeA(p, k) var args: PRstNode = nil var options: PRstNode = nil if hasArg in flags: @@ -1701,17 +2171,34 @@ proc parseDirective(p: var RstParser, flags: DirFlags): PRstNode = proc indFollows(p: RstParser): bool = result = currentTok(p).kind == tkIndent and currentTok(p).ival > currInd(p) -proc parseDirective(p: var RstParser, flags: DirFlags, - contentParser: SectionParser): PRstNode = - ## Returns a generic rnDirective tree. - ## - ## The children are rnDirArg, rnFieldList and rnLineBlock. Any might be nil. - result = parseDirective(p, flags) - if not isNil(contentParser) and indFollows(p): - pushInd(p, currentTok(p).ival) +proc parseBlockContent(p: var RstParser, father: var PRstNode, + contentParser: SectionParser): bool = + ## parse the final content part of explicit markup blocks (directives, + ## footnotes, etc). Returns true if succeeded. + if currentTok(p).kind != tkIndent or indFollows(p): + var nextIndent = p.tok[tokenAfterNewline(p)-1].ival + if nextIndent <= currInd(p): # parse only this line + nextIndent = currentTok(p).col + pushInd(p, nextIndent) var content = contentParser(p) popInd(p) - result.add(content) + father.add content + result = true + +proc parseDirective(p: var RstParser, k: RstNodeKind, flags: DirFlags, + contentParser: SectionParser): PRstNode = + ## A helper proc that does main work for specific directive procs. + ## Always returns a generic rnDirective tree with these 3 children: + ## + ## 1) rnDirArg + ## 2) rnFieldList + ## 3) a node returned by `contentParser`. + ## + ## .. warning:: Any of the 3 children may be nil. + result = parseDirective(p, k, flags) + if not isNil(contentParser) and + parseBlockContent(p, result, contentParser): + discard "result is updated by parseBlockContent" else: result.add(PRstNode(nil)) @@ -1744,7 +2231,7 @@ proc dirInclude(p: var RstParser): PRstNode = # encoding (if specified). # result = nil - var n = parseDirective(p, {hasArg, argIsFile, hasOptions}, nil) + var n = parseDirective(p, rnDirective, {hasArg, argIsFile, hasOptions}, nil) var filename = strip(addNodes(n.sons[0])) var path = p.findRelativeFile(filename) if path == "": @@ -1753,9 +2240,9 @@ proc dirInclude(p: var RstParser): PRstNode = # XXX: error handling; recursive file inclusion! if getFieldValue(n, "literal") != "": result = newRstNode(rnLiteralBlock) - result.add(newRstNode(rnLeaf, readFile(path))) + result.add newLeaf(readFile(path)) else: - let inputString = readFile(path).string() + let inputString = readFile(path) let startPosition = block: let searchFor = n.getFieldValue("start-after").strip() @@ -1805,16 +2292,16 @@ proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode = ## As an extension this proc will process the ``file`` extension field and if ## present will replace the code block with the contents of the referenced ## file. - result = parseDirective(p, {hasArg, hasOptions}, parseLiteralBlock) + result = parseDirective(p, rnCodeBlock, {hasArg, hasOptions}, parseLiteralBlock) var filename = strip(getFieldValue(result, "file")) if filename != "": var path = p.findRelativeFile(filename) if path == "": rstMessage(p, meCannotOpenFile, filename) var n = newRstNode(rnLiteralBlock) - n.add(newRstNode(rnLeaf, readFile(path))) + n.add newLeaf(readFile(path)) result.sons[2] = n - # Extend the field block if we are using our custom extension. + # Extend the field block if we are using our custom Nim extension. if nimExtension: # Create a field block if the input block didn't have any. if result.sons[1].isNil: result.sons[1] = newRstNode(rnFieldList) @@ -1823,38 +2310,36 @@ proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode = var extraNode = newRstNode(rnField) extraNode.add(newRstNode(rnFieldName)) extraNode.add(newRstNode(rnFieldBody)) - extraNode.sons[0].add(newRstNode(rnLeaf, "default-language")) - extraNode.sons[1].add(newRstNode(rnLeaf, "Nim")) + extraNode.sons[0].add newLeaf("default-language") + extraNode.sons[1].add newLeaf("Nim") result.sons[1].add(extraNode) - result.kind = rnCodeBlock - proc dirContainer(p: var RstParser): PRstNode = - result = parseDirective(p, {hasArg}, parseSectionWrapper) - assert(result.kind == rnDirective) + result = parseDirective(p, rnContainer, {hasArg}, parseSectionWrapper) assert(result.len == 3) - result.kind = rnContainer proc dirImage(p: var RstParser): PRstNode = - result = parseDirective(p, {hasOptions, hasArg, argIsFile}, nil) - result.kind = rnImage + result = parseDirective(p, rnImage, {hasOptions, hasArg, argIsFile}, nil) proc dirFigure(p: var RstParser): PRstNode = - result = parseDirective(p, {hasOptions, hasArg, argIsFile}, + result = parseDirective(p, rnFigure, {hasOptions, hasArg, argIsFile}, parseSectionWrapper) - result.kind = rnFigure proc dirTitle(p: var RstParser): PRstNode = - result = parseDirective(p, {hasArg}, nil) - result.kind = rnTitle + result = parseDirective(p, rnTitle, {hasArg}, nil) proc dirContents(p: var RstParser): PRstNode = - result = parseDirective(p, {hasArg}, nil) - result.kind = rnContents + result = parseDirective(p, rnContents, {hasArg}, nil) proc dirIndex(p: var RstParser): PRstNode = - result = parseDirective(p, {}, parseSectionWrapper) - result.kind = rnIndex + result = parseDirective(p, rnIndex, {}, parseSectionWrapper) + +proc dirAdmonition(p: var RstParser, d: string): PRstNode = + result = parseDirective(p, rnAdmonition, {}, parseSectionWrapper) + result.adType = d + +proc dirDefaultRole(p: var RstParser): PRstNode = + result = parseDirective(p, rnDefaultRole, {hasArg}, nil) proc dirRawAux(p: var RstParser, result: var PRstNode, kind: RstNodeKind, contentParser: SectionParser) = @@ -1866,9 +2351,9 @@ proc dirRawAux(p: var RstParser, result: var PRstNode, kind: RstNodeKind, else: var f = readFile(path) result = newRstNode(kind) - result.add(newRstNode(rnLeaf, f)) + result.add newLeaf(f) else: - result.kind = kind + result = newRstNode(kind, result.sons) result.add(parseDirBody(p, contentParser)) proc dirRaw(p: var RstParser): PRstNode = @@ -1880,7 +2365,7 @@ proc dirRaw(p: var RstParser): PRstNode = # # html # latex - result = parseDirective(p, {hasOptions, hasArg, argIsWord}) + result = parseDirective(p, rnDirective, {hasOptions, hasArg, argIsWord}) if result.sons[0] != nil: if cmpIgnoreCase(result.sons[0].sons[0].text, "html") == 0: dirRawAux(p, result, rnRawHtml, parseLiteralBlock) @@ -1891,29 +2376,93 @@ proc dirRaw(p: var RstParser): PRstNode = else: dirRawAux(p, result, rnRaw, parseSectionWrapper) -proc parseDotDot(p: var RstParser): PRstNode = +proc selectDir(p: var RstParser, d: string): PRstNode = result = nil + case d + of "admonition", "attention", "caution": result = dirAdmonition(p, d) + of "code": result = dirCodeBlock(p) + of "code-block": result = dirCodeBlock(p, nimExtension = true) + of "container": result = dirContainer(p) + of "contents": result = dirContents(p) + of "danger", "error": result = dirAdmonition(p, d) + of "figure": result = dirFigure(p) + of "hint": result = dirAdmonition(p, d) + of "image": result = dirImage(p) + of "important": result = dirAdmonition(p, d) + of "include": result = dirInclude(p) + of "index": result = dirIndex(p) + of "note": result = dirAdmonition(p, d) + of "raw": + if roSupportRawDirective in p.s.options: + result = dirRaw(p) + else: + rstMessage(p, meInvalidDirective, d) + of "tip": result = dirAdmonition(p, d) + of "title": result = dirTitle(p) + of "warning": result = dirAdmonition(p, d) + of "default-role": result = dirDefaultRole(p) + else: + let tok = p.tok[p.idx-2] # report on directive in ".. directive::" + rstMessage(p, meInvalidDirective, d, tok.line, tok.col) + +proc prefix(ftnType: FootnoteType): string = + case ftnType + of fnManualNumber: result = "footnote-" + of fnAutoNumber: result = "footnoteauto-" + of fnAutoNumberLabel: result = "footnote-" + of fnAutoSymbol: result = "footnotesym-" + of fnCitation: result = "citation-" + +proc parseFootnote(p: var RstParser): PRstNode = + ## Parses footnotes and citations, always returns 2 sons: + ## + ## 1) footnote label, always containing rnInner with 1 or more sons + ## 2) footnote body, which may be nil + inc p.idx + let label = parseFootnoteName(p, reference=false) + if label == nil: + dec p.idx + return nil + result = newRstNode(rnFootnote) + result.add label + let (fnType, i) = getFootnoteType(label) + var name = "" + var anchor = fnType.prefix + case fnType + of fnManualNumber: + addFootnoteNumManual(p, i) + anchor.add $i + of fnAutoNumber, fnAutoNumberLabel: + name = rstnodeToRefname(label) + addFootnoteNumAuto(p, name) + if fnType == fnAutoNumberLabel: + anchor.add name + else: # fnAutoNumber + result.order = p.s.lineFootnoteNum.len + anchor.add $result.order + of fnAutoSymbol: + addFootnoteSymAuto(p) + result.order = p.s.lineFootnoteSym.len + anchor.add $p.s.lineFootnoteSym.len + of fnCitation: + anchor.add rstnodeToRefname(label) + addAnchor(p, anchor, reset=true) + result.anchor = anchor + if currentTok(p).kind == tkWhite: inc p.idx + discard parseBlockContent(p, result, parseSectionWrapper) + if result.len < 2: + result.add nil + +proc parseDotDot(p: var RstParser): PRstNode = + # parse "explicit markup blocks" + result = nil + var n: PRstNode # to store result, workaround for bug 16855 var col = currentTok(p).col inc p.idx var d = getDirective(p) if d != "": pushInd(p, col) - case getDirKind(d) - of dkInclude: result = dirInclude(p) - of dkImage: result = dirImage(p) - of dkFigure: result = dirFigure(p) - of dkTitle: result = dirTitle(p) - of dkContainer: result = dirContainer(p) - of dkContents: result = dirContents(p) - of dkRaw: - if roSupportRawDirective in p.s.options: - result = dirRaw(p) - else: - rstMessage(p, meInvalidDirective, d) - of dkCode: result = dirCodeBlock(p) - of dkCodeBlock: result = dirCodeBlock(p, nimExtension = true) - of dkIndex: result = dirIndex(p) - else: rstMessage(p, meInvalidDirective, d) + result = selectDir(p, d) popInd(p) elif match(p, p.idx, " _"): # hyperlink target: @@ -1921,7 +2470,10 @@ proc parseDotDot(p: var RstParser): PRstNode = var a = getReferenceName(p, ":") if currentTok(p).kind == tkWhite: inc p.idx var b = untilEol(p) - setRef(p, rstnodeToRefname(a), b) + if len(b) == 0: # set internal anchor + addAnchor(p, rstnodeToRefname(a), reset=false) + else: # external hyperlink + setRef(p, rstnodeToRefname(a), b) elif match(p, p.idx, " |"): # substitution definitions: inc p.idx, 2 @@ -1938,17 +2490,16 @@ proc parseDotDot(p: var RstParser): PRstNode = else: rstMessage(p, meInvalidDirective, currentTok(p).symbol) setSub(p, addNodes(a), b) - elif match(p, p.idx, " ["): - # footnotes, citations - inc p.idx, 2 - var a = getReferenceName(p, "]") - if currentTok(p).kind == tkWhite: inc p.idx - var b = untilEol(p) - setRef(p, rstnodeToRefname(a), b) + elif match(p, p.idx, " [") and + (n = parseFootnote(p); n != nil): + result = n else: result = parseComment(p) proc resolveSubs(p: var RstParser, n: PRstNode): PRstNode = + ## Resolves substitutions and anchor aliases, groups footnotes. + ## Takes input node `n` and returns the same node with recursive + ## substitutions in `n.sons` to `result`. result = n if n == nil: return case n.kind @@ -1959,21 +2510,104 @@ proc resolveSubs(p: var RstParser, n: PRstNode): PRstNode = else: var key = addNodes(n) var e = getEnv(key) - if e != "": result = newRstNode(rnLeaf, e) + if e != "": result = newLeaf(e) else: rstMessage(p, mwUnknownSubstitution, key) + of rnHeadline, rnOverline: + # fix up section levels depending on presence of a title and subtitle + if p.s.hTitleCnt == 2: + if n.level == 1: # it's the subtitle + n.level = 0 + elif n.level >= 2: # normal sections + n.level -= 1 + elif p.s.hTitleCnt == 0: + n.level += 1 of rnRef: - var y = findRef(p, rstnodeToRefname(n)) + let refn = rstnodeToRefname(n) + var y = findRef(p, refn) if y != nil: result = newRstNode(rnHyperlink) - n.kind = rnInner - result.add(n) - result.add(y) + let text = newRstNode(rnInner, n.sons) + result.sons = @[text, y] + else: + let s = findMainAnchor(p, refn) + if s != "": + result = newRstNode(rnInternalRef) + let text = newRstNode(rnInner, n.sons) + result.sons = @[text, # visible text of reference + newLeaf(s)] # link itself + of rnFootnote: + var (fnType, num) = getFootnoteType(n.sons[0]) + case fnType + of fnManualNumber, fnCitation: + discard "no need to alter fixed text" + of fnAutoNumberLabel, fnAutoNumber: + if fnType == fnAutoNumberLabel: + let labelR = rstnodeToRefname(n.sons[0]) + num = getFootnoteNum(p, labelR) + else: + num = getFootnoteNum(p, n.order) + var nn = newRstNode(rnInner) + nn.add newLeaf($num) + result.sons[0] = nn + of fnAutoSymbol: + let sym = getAutoSymbol(p, n.order) + n.sons[0].sons[0].text = sym + n.sons[1] = resolveSubs(p, n.sons[1]) + of rnFootnoteRef: + var (fnType, num) = getFootnoteType(n.sons[0]) + template addLabel(number: int | string) = + var nn = newRstNode(rnInner) + nn.add newLeaf($number) + result.add(nn) + var refn = fnType.prefix + # create new rnFootnoteRef, add final label, and finalize target refn: + result = newRstNode(rnFootnoteRef) + case fnType + of fnManualNumber: + addLabel num + refn.add $num + of fnAutoNumber: + addLabel getFootnoteNum(p, n.order) + refn.add $n.order + of fnAutoNumberLabel: + addLabel getFootnoteNum(p, rstnodeToRefname(n)) + refn.add rstnodeToRefname(n) + of fnAutoSymbol: + addLabel getAutoSymbol(p, n.order) + refn.add $n.order + of fnCitation: + result.add n.sons[0] + refn.add rstnodeToRefname(n) + let s = findMainAnchor(p, refn) + if s != "": + result.add newLeaf(s) # add link + else: + rstMessage(p, mwUnknownSubstitution, refn) + result.add newLeaf(refn) # add link of rnLeaf: discard of rnContents: p.hasToc = true else: - for i in 0 ..< n.len: n.sons[i] = resolveSubs(p, n.sons[i]) + var regroup = false + for i in 0 ..< n.len: + n.sons[i] = resolveSubs(p, n.sons[i]) + if n.sons[i] != nil and n.sons[i].kind == rnFootnote: + regroup = true + if regroup: # group footnotes together into rnFootnoteGroup + var newSons: seq[PRstNode] + var i = 0 + while i < n.len: + if n.sons[i] != nil and n.sons[i].kind == rnFootnote: + var grp = newRstNode(rnFootnoteGroup) + while i < n.len and n.sons[i].kind == rnFootnote: + grp.sons.add n.sons[i] + inc i + newSons.add grp + else: + newSons.add n.sons[i] + inc i + result.sons = newSons proc rstParse*(text, filename: string, line, column: int, hasToc: var bool, @@ -1985,5 +2619,8 @@ proc rstParse*(text, filename: string, p.filename = filename p.line = line p.col = column + getTokens(text, roSkipPounds in options, p.tok) - result = resolveSubs(p, parseDoc(p)) + let unresolved = parseDoc(p) + countTitles(p, unresolved) + orderFootnotes(p) + result = resolveSubs(p, unresolved) hasToc = p.hasToc diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 5e2d21c048..c68df7daa1 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -18,6 +18,7 @@ type rnInner, # an inner node or a root rnHeadline, # a headline rnOverline, # an over- and underlined headline + rnMarkdownHeadline, # a Markdown headline rnTransition, # a transition (the -------------
    thingie) rnParagraph, # a paragraph rnBulletList, # a bullet list @@ -35,14 +36,19 @@ type rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString, rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock, rnLineBlock, # the | thingie - rnLineBlockItem, # sons of the | thing + rnLineBlockItem, # a son of rnLineBlock - one line inside it. + # When `RstNode` lineIndent="\n" the line's empty rnBlockQuote, # text just indented rnTable, rnGridTable, rnMarkdownTable, rnTableRow, rnTableHeaderCell, rnTableDataCell, - rnLabel, # used for footnotes and other things rnFootnote, # a footnote - rnCitation, # similar to footnote - rnStandaloneHyperlink, rnHyperlink, rnRef, rnDirective, # a directive - rnDirArg, rnRaw, rnTitle, rnContents, rnImage, rnFigure, rnCodeBlock, + rnCitation, # similar to footnote, so use rnFootnote instead + rnFootnoteGroup, # footnote group - exists for a purely stylistic + # reason: to display a few footnotes as 1 block + rnStandaloneHyperlink, rnHyperlink, rnRef, rnInternalRef, rnFootnoteRef, + rnDirective, # a general directive + rnDirArg, # a directive argument (for some directives). + # here are directives that are not rnDirective: + rnRaw, rnTitle, rnContents, rnImage, rnFigure, rnCodeBlock, rnAdmonition, rnRawHtml, rnRawLatex, rnContainer, # ``container`` directive rnIndex, # index directve: @@ -58,33 +64,56 @@ type rnTripleEmphasis, # "***" rnInterpretedText, # "`" rnInlineLiteral, # "``" + rnInlineTarget, # "_`target`" rnSubstitutionReferences, # "|" rnSmiley, # some smiley + rnDefaultRole, # .. default-role:: code rnLeaf # a leaf; the node's text field contains the # leaf val PRstNode* = ref RstNode ## an RST node RstNodeSeq* = seq[PRstNode] - RstNode* {.acyclic, final.} = object ## an RST node's description - kind*: RstNodeKind ## the node's kind - text*: string ## valid for leafs in the AST; and the title of - ## the document or the section; and rnEnumList - level*: int ## valid for some node kinds + RstNode* {.acyclic, final.} = object ## AST node (result of RST parsing) + case kind*: RstNodeKind ## the node's kind + of rnLeaf, rnSmiley: + text*: string ## string that is expected to be displayed + of rnEnumList: + labelFmt*: string ## label format like "(1)" + of rnLineBlockItem: + lineIndent*: string ## a few spaces or newline at the line beginning + of rnAdmonition: + adType*: string ## admonition type: "note", "caution", etc. This + ## text will set the style and also be displayed + of rnOverline, rnHeadline, rnMarkdownHeadline: + level*: int ## level of headings starting from 1 (main + ## chapter) to larger ones (minor sub-sections) + ## level=0 means it's document title or subtitle + of rnFootnote, rnCitation, rnFootnoteRef: + order*: int ## footnote order (for auto-symbol footnotes and + ## auto-numbered ones without a label) + else: + discard + anchor*: string ## anchor, internal link target + ## (aka HTML id tag, aka Latex label/hypertarget) sons*: RstNodeSeq ## the node's sons proc len*(n: PRstNode): int = result = len(n.sons) -proc newRstNode*(kind: RstNodeKind): PRstNode = - new(result) - result.sons = @[] - result.kind = kind +proc newRstNode*(kind: RstNodeKind, sons: seq[PRstNode] = @[], + anchor = ""): PRstNode = + result = PRstNode(kind: kind, sons: sons) -proc newRstNode*(kind: RstNodeKind, s: string): PRstNode = +proc newRstNode*(kind: RstNodeKind, s: string): PRstNode {.deprecated.} = + assert kind in {rnLeaf, rnSmiley} result = newRstNode(kind) result.text = s +proc newRstLeaf*(s: string): PRstNode = + result = newRstNode(rnLeaf) + result.text = s + proc lastSon*(n: PRstNode): PRstNode = result = n.sons[len(n.sons)-1] @@ -92,7 +121,7 @@ proc add*(father, son: PRstNode) = add(father.sons, son) proc add*(father: PRstNode; s: string) = - add(father.sons, newRstNode(rnLeaf, s)) + add(father.sons, newRstLeaf(s)) proc addIfNotNil*(father, son: PRstNode) = if son != nil: add(father, son) @@ -298,7 +327,7 @@ proc renderRstToJsonNode(node: PRstNode): JsonNode = (key: "kind", val: %($node.kind)), (key: "level", val: %BiggestInt(node.level)) ] - if node.text.len > 0: + if node.kind in {rnLeaf, rnSmiley} and node.text.len > 0: result.add("text", %node.text) if len(node.sons) > 0: var accm = newSeq[JsonNode](len(node.sons)) @@ -316,3 +345,33 @@ proc renderRstToJson*(node: PRstNode): string = ## "sons":optional node array ## } renderRstToJsonNode(node).pretty + +proc renderRstToStr*(node: PRstNode, indent=0): string = + ## Writes the parsed RST `node` into a compact string + ## representation in the format (one line per every sub-node): + ## ``indent - kind - text - level - order - anchor (if non-zero)`` + ## (suitable for debugging of RST parsing). + if node == nil: + result.add " ".repeat(indent) & "[nil]\n" + return + result.add " ".repeat(indent) & $node.kind + case node.kind + of rnLeaf, rnSmiley: + result.add (if node.text == "": "" else: "\t'" & node.text & "'") + of rnEnumList: + result.add "\tlabelFmt=" & node.labelFmt + of rnLineBlockItem: + var txt: string + if node.lineIndent == "\n": txt = "\t(blank line)" + else: txt = "\tlineIndent=" & $node.lineIndent.len + result.add txt + of rnHeadline, rnOverline, rnMarkdownHeadline: + result.add "\tlevel=" & $node.level + of rnFootnote, rnCitation, rnFootnoteRef: + result.add (if node.order == 0: "" else: "\torder=" & $node.order) + else: + discard + result.add (if node.anchor == "": "" else: "\tanchor='" & node.anchor & "'") + result.add "\n" + for son in node.sons: + result.add renderRstToStr(son, indent=indent+2) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 4d056a83ed..c52a0fdccd 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -23,7 +23,23 @@ ## many options and tweaking, but you are not limited to snippets and can ## generate `LaTeX documents `_ too. ## -## **Note:** Import ``packages/docutils/rstgen`` to use this module +## `Docutils configuration files`_ are not supported. Instead HTML generation +## can be tweaked by editing file ``config/nimdoc.cfg``. +## +## .. _Docutils configuration files: https://docutils.sourceforge.io/docs/user/config.htm +## +## There are stylistic difference between how this module renders some elements +## and how original Python Docutils does: +## +## * Backreferences to TOC in section headings are not generated. +## In HTML each section is also a link that points to the section itself: +## this is done for user to be able to copy the link into clipboard. +## +## * The same goes for footnotes/citations links: they point to themselves. +## No backreferences are generated since finding all references of a footnote +## can be done by simply searching for [footnoteName]. +## +## .. Tip: Import ``packages/docutils/rstgen`` to use this module import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils, algorithm, parseutils @@ -272,13 +288,25 @@ proc renderRstToOut*(d: var RstGenerator, n: PRstNode, result: var string) proc renderAux(d: PDoc, n: PRstNode, result: var string) = for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result) -proc renderAux(d: PDoc, n: PRstNode, frmtA, frmtB: string, result: var string) = +template idS(txt: string): string = + if txt == "": "" + else: + case d.target + of outHtml: + " id=\"" & txt & "\"" + of outLatex: + "\\label{" & txt & "}\\hypertarget{" & txt & "}{}" + # we add \label for page number references via \pageref, while + # \hypertarget is for clickable links via \hyperlink. + +proc renderAux(d: PDoc, n: PRstNode, html, tex: string, result: var string) = + # formats sons of `n` as substitution variable $1 inside strings `html` and + # `tex`, internal target (anchor) is provided as substitute $2. var tmp = "" for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], tmp) - if d.target != outLatex: - result.addf(frmtA, [tmp]) - else: - result.addf(frmtB, [tmp]) + case d.target + of outHtml: result.addf(html, [tmp, n.anchor.idS]) + of outLatex: result.addf(tex, [tmp, n.anchor.idS]) # ---------------- index handling -------------------------------------------- @@ -746,13 +774,13 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) = d.tocPart[length].n = n d.tocPart[length].header = tmp - dispA(d.target, result, "\n$3", "\\rsth$4{$3}\\label{$2}\n", - [$n.level, d.tocPart[length].refname, tmp, $chr(n.level - 1 + ord('A'))]) + dispA(d.target, result, "\n$3", "\\rsth$4{$3}$2\n", + [$n.level, refname.idS, tmp, $chr(n.level - 1 + ord('A')), refname]) else: - dispA(d.target, result, "\n$3", - "\\rsth$4{$3}\\label{$2}\n", [ - $n.level, refname, tmp, + dispA(d.target, result, "\n$3", + "\\rsth$4{$3}$2\n", [ + $n.level, refname.idS, tmp, $chr(n.level - 1 + ord('A'))]) # Generate index entry using spaces to indicate TOC level for the output HTML. @@ -769,11 +797,11 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) = spaces(max(0, n.level)) & tmp) proc renderOverline(d: PDoc, n: PRstNode, result: var string) = - if d.meta[metaTitle].len == 0: + if n.level == 0 and d.meta[metaTitle].len == 0: for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], d.meta[metaTitle]) d.currentSection = d.meta[metaTitle] - elif d.meta[metaSubtitle].len == 0: + elif n.level == 0 and d.meta[metaSubtitle].len == 0: for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], d.meta[metaSubtitle]) d.currentSection = d.meta[metaSubtitle] @@ -781,9 +809,9 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) = var tmp = "" for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp) d.currentSection = tmp - dispA(d.target, result, "
    $3
    ", - "\\rstov$4{$3}\\label{$2}\n", [$n.level, - rstnodeToRefname(n), tmp, $chr(n.level - 1 + ord('A'))]) + dispA(d.target, result, "
    $3
    ", + "\\rstov$4{$3}$2\n", [$n.level, + rstnodeToRefname(n).idS, tmp, $chr(n.level - 1 + ord('A'))]) proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) = @@ -841,12 +869,12 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) = if arg.endsWith(".mp4") or arg.endsWith(".ogg") or arg.endsWith(".webm"): htmlOut = """ - """ else: - htmlOut = "" + htmlOut = "" # support for `:target:` links for images: var target = esc(d.target, getFieldValue(n, "target").strip()) @@ -859,8 +887,8 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) = "\\href{$2}{$1}", [htmlOut, target]) htmlOut = htmlOutWithLink - dispA(d.target, result, htmlOut, "\\includegraphics$2{$1}", - [esc(d.target, arg), options]) + dispA(d.target, result, htmlOut, "$3\\includegraphics$2{$1}", + [esc(d.target, arg), options, n.anchor.idS]) if len(n) >= 3: renderRstToOut(d, n.sons[2], result) proc renderSmiley(d: PDoc, n: PRstNode, result: var string) = @@ -892,8 +920,11 @@ proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) = of "test": params.testCmd = n.getFieldValue.strip if params.testCmd.len == 0: - params.testCmd = "$nim r --backend:$backend $options" # see `interpSnippetCmd` + # factor with D20210224T221756. Note that `$docCmd` should appear before `$file` + # but after all other options, but currently `$options` merges both options and `$file` so it's tricky. + params.testCmd = "$nim r --backend:$backend --lib:$libpath $docCmd $options" else: + # consider whether `$docCmd` should be appended here too params.testCmd = unescape(params.testCmd) of "status", "exitcode": var status: int @@ -925,7 +956,8 @@ proc parseCodeBlockParams(d: PDoc, n: PRstNode): CodeBlockParams = if result.langStr != "": result.lang = getSourceLanguage(result.langStr) -proc buildLinesHtmlTable(d: PDoc; params: CodeBlockParams, code: string): +proc buildLinesHtmlTable(d: PDoc; params: CodeBlockParams, code: string, + idStr: string): tuple[beginTable, endTable: string] = ## Returns the necessary tags to start/end a code block in HTML. ## @@ -937,21 +969,22 @@ proc buildLinesHtmlTable(d: PDoc; params: CodeBlockParams, code: string): let id = $d.listingCounter if not params.numberLines: result = (d.config.getOrDefault"doc.listing_start" % - [id, sourceLanguageToStr[params.lang]], + [id, sourceLanguageToStr[params.lang], idStr], d.config.getOrDefault"doc.listing_end" % id) return var codeLines = code.strip.countLines assert codeLines > 0 - result.beginTable = """
    """
    +  result.beginTable = """""" % [idStr] &
    +      """
    """
       var line = params.startLine
       while codeLines > 0:
         result.beginTable.add($line & "\n")
         line.inc
         codeLines.dec
    -  result.beginTable.add("
    " & ( + result.beginTable.add("" & ( d.config.getOrDefault"doc.listing_start" % - [id, sourceLanguageToStr[params.lang]])) + [id, sourceLanguageToStr[params.lang], idStr])) result.endTable = (d.config.getOrDefault"doc.listing_end" % id) & "
    " & ( d.config.getOrDefault"doc.listing_button" % id) @@ -975,9 +1008,10 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) = if params.testCmd.len > 0 and d.onTestSnippet != nil: d.onTestSnippet(d, params.filename, params.testCmd, params.status, m.text) - let (blockStart, blockEnd) = buildLinesHtmlTable(d, params, m.text) - - dispA(d.target, result, blockStart, "\\begin{rstpre}\n", []) + let (blockStart, blockEnd) = buildLinesHtmlTable(d, params, m.text, + n.anchor.idS) + dispA(d.target, result, blockStart, + "\\begin{rstpre}\n" & n.anchor.idS & "\n", []) if params.lang == langNone: if len(params.langStr) > 0: d.msgHandler(d.filename, 1, 0, mwUnsupportedLanguage, params.langStr) @@ -1035,83 +1069,106 @@ proc renderEnumList(d: PDoc, n: PRstNode, result: var string) = specStart = "" i1 = 0 pre = "" - i2 = n.text.len-1 + i2 = n.labelFmt.len - 1 post = "" - if n.text[0] == '(': + if n.labelFmt[0] == '(': i1 = 1 pre = "(" - if n.text[^1] == ')' or n.text[^1] == '.': - i2 = n.text.len-2 - post = $n.text[^1] + if n.labelFmt[^1] == ')' or n.labelFmt[^1] == '.': + i2 = n.labelFmt.len - 2 + post = $n.labelFmt[^1] let enumR = i1 .. i2 # enumerator range without surrounding (, ), . if d.target == outLatex: - result.add ("\n%"&n.text&"\n") + result.add ("\n%" & n.labelFmt & "\n") # use enumerate parameters from package enumitem - if n.text[i1].isDigit: + if n.labelFmt[i1].isDigit: var labelDef = "" if pre != "" or post != "": labelDef = "label=" & pre & "\\arabic*" & post & "," - if n.text[enumR] != "1": - specStart = "start=$1" % [n.text[enumR]] + if n.labelFmt[enumR] != "1": + specStart = "start=$1" % [n.labelFmt[enumR]] if labelDef != "" or specStart != "": specifier = "[$1$2]" % [labelDef, specStart] else: let (first, labelDef) = - if n.text[i1].isUpperAscii: ('A', "label=" & pre & "\\Alph*" & post) + if n.labelFmt[i1].isUpperAscii: ('A', "label=" & pre & "\\Alph*" & post) else: ('a', "label=" & pre & "\\alph*" & post) - if n.text[i1] != first: - specStart = ",start=" & $(ord(n.text[i1]) - ord(first) + 1) + if n.labelFmt[i1] != first: + specStart = ",start=" & $(ord(n.labelFmt[i1]) - ord(first) + 1) specifier = "[$1$2]" % [labelDef, specStart] else: # HTML # TODO: implement enumerator formatting using pre and post ( and ) for HTML - if n.text[i1].isDigit: - if n.text[enumR] != "1": - specStart = " start=\"$1\"" % [n.text[enumR]] + if n.labelFmt[i1].isDigit: + if n.labelFmt[enumR] != "1": + specStart = " start=\"$1\"" % [n.labelFmt[enumR]] specifier = "class=\"simple\"" & specStart else: let (first, labelDef) = - if n.text[i1].isUpperAscii: ('A', "class=\"upperalpha simple\"") + if n.labelFmt[i1].isUpperAscii: ('A', "class=\"upperalpha simple\"") else: ('a', "class=\"loweralpha simple\"") - if n.text[i1] != first: - specStart = " start=\"$1\"" % [ $(ord(n.text[i1]) - ord(first) + 1) ] + if n.labelFmt[i1] != first: + specStart = " start=\"$1\"" % [ $(ord(n.labelFmt[i1]) - ord(first) + 1) ] specifier = labelDef & specStart - renderAux(d, n, "
      $1
    \n", - "\\begin{enumerate}" & specifier & "$1\\end{enumerate}\n", + renderAux(d, n, "$1\n", + "\\begin{enumerate}" & specifier & "$2$1\\end{enumerate}\n", result) +proc renderAdmonition(d: PDoc, n: PRstNode, result: var string) = + var + htmlCls = "admonition_warning" + texSz = "\\large" + texColor = "orange" + case n.adType + of "hint", "note", "tip": + htmlCls = "admonition-info"; texSz = "\\normalsize"; texColor = "green" + of "attention", "admonition", "important", "warning": + htmlCls = "admonition-warning"; texSz = "\\large"; texColor = "orange" + of "danger", "error": + htmlCls = "admonition-error"; texSz = "\\Large"; texColor = "red" + else: discard + let txt = n.adType.capitalizeAscii() + let htmlHead = "
    " + renderAux(d, n, + htmlHead & "" & txt & + ":\n" & "$1
    \n", + "\n\n\\begin{mdframed}[linecolor=" & texColor & "]$2\n" & + "{" & texSz & "\\color{" & texColor & "}{\\textbf{" & txt & ":}}} " & + "$1\n\\end{mdframed}\n", + result) + proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = if n == nil: return case n.kind of rnInner: renderAux(d, n, result) - of rnHeadline: renderHeadline(d, n, result) + of rnHeadline, rnMarkdownHeadline: renderHeadline(d, n, result) of rnOverline: renderOverline(d, n, result) - of rnTransition: renderAux(d, n, "
    \n", "\\hrule\n", result) - of rnParagraph: renderAux(d, n, "

    $1

    \n", "$1\n\n", result) + of rnTransition: renderAux(d, n, "\n", "\\hrule$2\n", result) + of rnParagraph: renderAux(d, n, "$1

    \n", "$2\n$1\n\n", result) of rnBulletList: - renderAux(d, n, "
      $1
    \n", - "\\begin{itemize}$1\\end{itemize}\n", result) + renderAux(d, n, "$1\n", + "\\begin{itemize}\n$2\n$1\\end{itemize}\n", result) of rnBulletItem, rnEnumItem: - renderAux(d, n, "
  • $1
  • \n", "\\item $1\n", result) + renderAux(d, n, "$1\n", "\\item $2$1\n", result) of rnEnumList: renderEnumList(d, n, result) of rnDefList: - renderAux(d, n, "
    $1
    \n", - "\\begin{description}$1\\end{description}\n", result) + renderAux(d, n, "$1\n", + "\\begin{description}\n$2\n$1\\end{description}\n", result) of rnDefItem: renderAux(d, n, result) - of rnDefName: renderAux(d, n, "
    $1
    \n", "\\item[$1] ", result) - of rnDefBody: renderAux(d, n, "
    $1
    \n", "$1\n", result) + of rnDefName: renderAux(d, n, "$1\n", "$2\\item[$1] ", result) + of rnDefBody: renderAux(d, n, "$1\n", "$2\n$1\n", result) of rnFieldList: var tmp = "" for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp) if tmp.len != 0: dispA(d.target, result, - "" & + "" & "" & "" & "$1" & "
    ", - "\\begin{description}$1\\end{description}\n", - [tmp]) + "\\begin{description}\n$2\n$1\\end{description}\n", + [tmp, n.anchor.idS]) of rnField: renderField(d, n, result) of rnFieldName: renderAux(d, n, "$1:", @@ -1121,8 +1178,8 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = of rnIndex: renderRstToOut(d, n.sons[2], result) of rnOptionList: - renderAux(d, n, "$1
    ", - "\\begin{description}\n$1\\end{description}\n", result) + renderAux(d, n, "$1", + "\\begin{description}\n$2\n$1\\end{description}\n", result) of rnOptionListItem: renderAux(d, n, "$1\n", "$1", result) of rnOptionGroup: @@ -1132,21 +1189,35 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = of rnOption, rnOptionString, rnOptionArgument: doAssert false, "renderRstToOut" of rnLiteralBlock: - renderAux(d, n, "
    $1
    \n", - "\\begin{rstpre}\n$1\n\\end{rstpre}\n", result) + renderAux(d, n, "$1\n", + "\\begin{rstpre}\n$2\n$1\n\\end{rstpre}\n", result) of rnQuotedLiteralBlock: doAssert false, "renderRstToOut" of rnLineBlock: - renderAux(d, n, "

    $1

    ", "$1\n\n", result) + 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) of rnLineBlockItem: - renderAux(d, n, "$1
    ", "$1\\\\\n", result) + 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) of rnBlockQuote: - renderAux(d, n, "

    $1

    \n", - "\\begin{quote}$1\\end{quote}\n", result) + 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
    ", - "\\begin{table}\\begin{rsttab}{" & + "$1", + "\\begin{table}\n$2\n\\begin{rsttab}{" & texColumns(n) & "|}\n\\hline\n$1\\end{rsttab}\\end{table}", result) of rnTableRow: if len(n) >= 1: @@ -1165,12 +1236,24 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = 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 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) + dispA(d.target, result, + "
    " & + "[$3]" & + "
      $1\n\n", + "\\item[\\textsuperscript{[$3]}]$2 $1\n", + [body, n.anchor.idS, mark, n.anchor]) of rnRef: var tmp = "" renderAux(d, n, tmp) @@ -1181,6 +1264,21 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = renderAux(d, n, "$1", "\\href{$1}{$1}", result) + of rnInternalRef: + var tmp = "" + renderAux(d, n.sons[0], tmp) + dispA(d.target, result, + "$1", + "\\hyperlink{$2}{$1} (p.~\\pageref{$2})", [tmp, n.sons[1].text]) + of rnFootnoteRef: + var tmp = "[" + renderAux(d, n.sons[0], tmp) + tmp.add "]" + dispA(d.target, result, + "" & + "$1", + "\\textsuperscript{\\hyperlink{$2}{\\textbf{$1}}}", + [tmp, n.sons[1].text]) of rnHyperlink: var tmp0 = "" var tmp1 = "" @@ -1225,9 +1323,17 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = renderAux(d, n, "$1", "\\texttt{$1}", result) + of rnInlineTarget: + var tmp = "" + renderAux(d, n, tmp) + dispA(d.target, result, + "$1", + "\\label{$2}\\hypertarget{$2}{$1}", + [tmp, rstnodeToRefname(n)]) of rnSmiley: renderSmiley(d, n, result) 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]) @@ -1360,7 +1466,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") @@ -1370,7 +1476,8 @@ $content # ---------- forum --------------------------------------------------------- proc rstToHtml*(s: string, options: RstParseOptions, - config: StringTableRef): string = + config: StringTableRef, + msgHandler: MsgHandler = rst.defaultMsgHandler): string = ## Converts an input rst string into embeddable HTML. ## ## This convenience proc parses any input string using rst markup (it doesn't @@ -1397,10 +1504,10 @@ proc rstToHtml*(s: string, options: RstParseOptions, const filen = "input" var d: RstGenerator - initRstGenerator(d, outHtml, config, filen, options, myFindFile, - rst.defaultMsgHandler) + initRstGenerator(d, outHtml, config, filen, options, myFindFile, msgHandler) var dummyHasToc = false - var rst = rstParse(s, filen, 0, 1, dummyHasToc, options) + var rst = rstParse(s, filen, line=LineRstInit, column=ColRstInit, + dummyHasToc, options, myFindFile, msgHandler) result = "" renderRstToOut(d, rst, result) @@ -1412,4 +1519,7 @@ proc rstToLatex*(rstSource: string; options: RstParseOptions): string {.inline, var option: bool var rstGenera: RstGenerator rstGenera.initRstGenerator(outLatex, defaultConfig(), "input", options) - rstGenera.renderRstToOut(rstParse(rstSource, "", 1, 1, option, options), result) + rstGenera.renderRstToOut( + rstParse(rstSource, "", line=LineRstInit, column=ColRstInit, + option, options), + result) diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim index 9f0cf75eda..1f105ecac2 100644 --- a/lib/posix/epoll.nim +++ b/lib/posix/epoll.nim @@ -57,10 +57,10 @@ proc epoll_create1*(flags: cint): cint {.importc: "epoll_create1", 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). + ## 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_*`` + ## 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. diff --git a/lib/posix/kqueue.nim b/lib/posix/kqueue.nim index 18b47f5d50..c83ae33ea3 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 680b61461d..5ce9bf2fb7 100644 --- a/lib/posix/linux.nim +++ b/lib/posix/linux.nim @@ -1,24 +1,35 @@ import posix +## Flags of `clone` syscall. +## See `clone syscall manual +## `_ for more information. const - 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 + 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 + CLONE_STOPPED* {.deprecated.} = 0x02000000'i32 # fn should be of type proc (a2: pointer): void {.cdecl.} proc clone*(fn: pointer; child_stack: pointer; flags: cint; diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index c7a324cde4..520d0caa0f 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -27,7 +27,7 @@ ## 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 @@ -90,8 +90,8 @@ 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) ## \ ## 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. @@ -189,7 +189,7 @@ proc posix_fadvise*(a1: cint, a2, a3: Off, a4: cint): cint {. 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: "".} @@ -586,6 +586,8 @@ 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.} @@ -876,14 +878,18 @@ proc CMSG_NXTHDR*(mhdr: ptr Tmsghdr, cmsg: ptr Tcmsghdr): ptr Tcmsghdr {. proc CMSG_FIRSTHDR*(mhdr: ptr Tmsghdr): ptr Tcmsghdr {. importc, header: "".} +{.push warning[deprecated]: off.} proc CMSG_SPACE*(len: csize): csize {. importc, header: "", deprecated: "argument `len` should be of type `csize_t`".} +{.pop.} proc CMSG_SPACE*(len: csize_t): csize_t {. importc, header: "".} +{.push warning[deprecated]: off.} proc CMSG_LEN*(len: csize): csize {. importc, header: "", deprecated: "argument `len` should be of type `csize_t`".} +{.pop.} proc CMSG_LEN*(len: csize_t): csize_t {. importc, header: "".} @@ -902,7 +908,7 @@ when defined(linux) or defined(bsd): 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: "".} @@ -1042,16 +1048,16 @@ 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. + ## .. 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 `mkstemps` and thus + ## can't be a string literal. If in doubt make a copy of the cstring before + ## passing it in. proc mkdtemp*(tmpl: cstring): pointer {.importc, header: "", sideEffect.} @@ -1077,13 +1083,13 @@ 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: ## ## .. code-block:: - ## from posix import SIGINT, SIGTERM, onSignal + ## from std/posix import SIGINT, SIGTERM, onSignal ## onSignal(SIGINT, SIGTERM): ## echo "bye from signal ", sig diff --git a/lib/posix/posix_haiku.nim b/lib/posix/posix_haiku.nim index eaf2cfb857..d626b21060 100644 --- a/lib/posix/posix_haiku.nim +++ b/lib/posix/posix_haiku.nim @@ -58,7 +58,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) @@ -551,7 +551,7 @@ 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 + # 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 diff --git a/lib/posix/posix_macos_amd64.nim b/lib/posix/posix_macos_amd64.nim index 94c08acad4..2e68af3308 100644 --- a/lib/posix/posix_macos_amd64.nim +++ b/lib/posix/posix_macos_amd64.nim @@ -45,7 +45,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) @@ -561,7 +561,7 @@ 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 diff --git a/lib/posix/posix_openbsd_amd64.nim b/lib/posix/posix_openbsd_amd64.nim index 584d065011..1ef4a4182d 100644 --- a/lib/posix/posix_openbsd_amd64.nim +++ b/lib/posix/posix_openbsd_amd64.nim @@ -45,7 +45,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) diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index a5eb32d226..6584bfab2e 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -64,7 +64,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) @@ -615,7 +615,7 @@ 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 diff --git a/lib/posix/posix_utils.nim b/lib/posix/posix_utils.nim index d083e20b9a..aeec73a451 100644 --- a/lib/posix/posix_utils.nim +++ b/lib/posix/posix_utils.nim @@ -11,7 +11,8 @@ # Where possible, contribute OS-independent procs in `os `_ instead. -import posix +import posix, parsecfg, os +import std/private/since type Uname* = object sysname*, nodename*, release*, version*, machine*: string @@ -107,3 +108,22 @@ proc mkdtemp*(prefix: string): string = if mkdtemp(tmpl) == nil: 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/prelude.nim b/lib/prelude.nim deleted file mode 100644 index 4d8c7d7f09..0000000000 --- a/lib/prelude.nim +++ /dev/null @@ -1,23 +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. -# - -## 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, hashes, tables, sets, sequtils -## when not defined(js): import parseopt - -import os, strutils, times, parseutils, hashes, tables, sets, sequtils -when not defined(js): import parseopt diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index f2e4848df9..a32df65bb4 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -7,11 +7,11 @@ # distribution, for details about the copyright. # -## This module implements some common generic algorithms. +## This module implements some common generic algorithms on `openArray`s. ## ## Basic usage ## =========== -## +## runnableExamples: type People = tuple @@ -30,9 +30,7 @@ runnableExamples: (year: 2010, name: "Jane")] proc myCmp(x, y: People): int = - if x.name < y.name: -1 - elif x.name == y.name: 0 - else: 1 + cmp(x.name, y.name) # Sorting with custom proc a.sort(myCmp) @@ -49,18 +47,18 @@ type Descending, Ascending proc `*`*(x: int, order: SortOrder): int {.inline.} = - ## Flips ``x`` if ``order == Descending``. - ## If ``order == Ascending`` then ``x`` is returned. + ## Flips the sign of `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 @@ -71,9 +69,9 @@ 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) = - ## Fills the slice ``a[first..last]`` with ``value``. + ## Assigns `value` to all elements of the slice `a[first..last]`. ## - ## If an invalid range is passed, it raises IndexDefect. + ## If an invalid range is passed, it raises `IndexDefect`. runnableExamples: var a: array[6, int] a.fill(1, 3, 9) @@ -84,7 +82,7 @@ proc fill*[T](a: var openArray[T], first, last: Natural, value: T) = fillImpl(a, first, last, value) proc fill*[T](a: var openArray[T], value: T) = - ## Fills the container ``a`` with ``value``. + ## Assigns `value` to all elements of the container `a`. runnableExamples: var a: array[6, int] a.fill(9) @@ -95,13 +93,13 @@ 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 `IndexDefect`. ## ## **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) @@ -117,23 +115,24 @@ 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], first: Natural, last: int): seq[T] = - ## Returns the reverse of the slice ``a[first..last]``. + ## Returns the reverse of the slice `a[first..last]`. ## - ## If an invalid range is passed, it raises IndexDefect. + ## If an invalid range is passed, it raises `IndexDefect`. ## ## **See also:** ## * `reverse proc<#reverse,openArray[T],Natural,Natural>`_ reverse a slice @@ -143,7 +142,7 @@ proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] = a = [1, 2, 3, 4, 5, 6] b = a.reversed(1, 3) assert b == @[4, 3, 2] - assert last >= first-1 + assert last >= first - 1 var i = last - first var x = first.int result = newSeq[T](i + 1) @@ -153,7 +152,7 @@ proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] = inc(x) proc reversed*[T](a: openArray[T]): seq[T] = - ## Returns the reverse of the container ``a``. + ## Returns the reverse of the container `a`. ## ## **See also:** ## * `reverse proc<#reverse,openArray[T],Natural,Natural>`_ reverse a slice @@ -166,19 +165,20 @@ proc reversed*[T](a: openArray[T]): seq[T] = reversed(a, 0, a.high) proc binarySearch*[T, K](a: openArray[T], key: K, - cmp: proc (x: T, y: K): int {.closure.}): int = - ## Binary search for ``key`` in ``a``. Returns -1 if not found. + cmp: proc (x: T, y: K): int {.closure.}): int = + ## 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`` is the comparator function to use, the expected return values are - ## the same as that of system.cmp. + ## `cmp` is the comparator function to use, the expected return values are + ## the same as those of system.cmp. runnableExamples: assert binarySearch(["a", "b", "c", "d"], "d", system.cmp[string]) == 3 - assert binarySearch(["a", "b", "d", "c"], "d", system.cmp[string]) == 2 - if a.len == 0: - return -1 - + assert binarySearch(["a", "b", "c", "d"], "c", system.cmp[string]) == 2 let len = a.len + if len == 0: + return -1 + if len == 1: if cmp(a[0], key) == 0: return 0 @@ -196,7 +196,7 @@ proc binarySearch*[T, K](a: openArray[T], key: K, if cmpRes == 0: return i - if cmpRes < 1: + if cmpRes < 0: result = i step = step shr 1 if cmp(a[result], key) != 0: result = -1 @@ -216,30 +216,32 @@ 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``. Returns -1 if not found. + ## Binary search for `key` in `a`. Return the index of `key` or -1 if not found. + ## Assumes that `a` is sorted. runnableExamples: assert binarySearch([0, 1, 2, 3, 4], 4) == 4 - assert binarySearch([0, 1, 4, 2, 3], 4) == 2 + assert binarySearch([0, 1, 2, 3, 4], 2) == 2 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 = - ## Returns a position to the first element in the ``a`` that is greater than - ## ``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 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. ## 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 `IndexDefect`. ## - ## The version uses ``cmp`` to compare the elements. - ## The expected return values are the same as that of ``system.cmp``. + ## This version uses `cmp` to compare the elements. + ## The expected return values are the same as those 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] @@ -261,33 +263,35 @@ proc lowerBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {. count = step proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T]) - ## Returns a position to the first element in the ``a`` that is greater than - ## ``key``, or last if no such element is found. + ## 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. ## 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. ## - ## The version uses the default comparison function ``cmp``. + ## This 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 = - ## 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. +proc upperBound*[T, K](a: openArray[T], key: K, + cmp: proc(x: T, k: K): int {.closure.}): int = + ## Returns the index of the first element in `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, 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 `IndexDefect`. ## - ## The version uses ``cmp`` to compare the elements. The expected - ## return values are the same as that of ``system.cmp``. + ## This version uses `cmp` to compare the elements. The expected + ## return values are the same as those 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] @@ -309,19 +313,20 @@ proc upperBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {. count = step proc upperBound*[T](a: openArray[T], key: T): int = upperBound(a, key, cmp[T]) - ## 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. + ## Returns the index of the first element in `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, upperBound(thing, elm))`` + ## `insert(thing, elm, upperBound(thing, elm))` ## the sequence will still be sorted. + ## Assumes that `a` is sorted. ## - ## The version uses the default comparison function ``cmp``. + ## This 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: @@ -331,10 +336,10 @@ template `<-` (a, b) = 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 + # 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 safes up to 40% of merge calls + # On random data this saves 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: @@ -372,14 +377,15 @@ func sort*[T](a: var openArray[T], cmp: proc (x, y: T): int {.closure.}, order = SortOrder.Ascending) = ## Default Nim sort (an implementation of merge sort). The sorting - ## is guaranteed to be stable and the worst case is guaranteed to - ## be O(n log n). + ## 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`. ## ## 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`. ## ## .. code-block:: nim ## @@ -400,7 +406,7 @@ func sort*[T](a: var openArray[T], ## ## **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: @@ -411,8 +417,7 @@ func sort*[T](a: var openArray[T], sort(d, myCmp) assert d == ["fo", "qux", "boo", "barr"] var n = a.len - var b: seq[T] - newSeq(b, n div 2) + var b = newSeq[T](n div 2) var s = 1 while s < n: var m = n-1-s @@ -423,17 +428,17 @@ func sort*[T](a: var openArray[T], 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] = - ## Returns ``a`` sorted by ``cmp`` in the specified ``order``. + ## Returns `a` sorted by `cmp` in the specified `order`. ## ## **See also:** ## * `sort func<#sort,openArray[T],proc(T,T)>`_ @@ -454,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)>`_ @@ -472,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 do + ## Because the underlying `cmp()` is defined for tuples you can also 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] @@ -510,9 +515,9 @@ template sortedByIt*(seq1, op: untyped): untyped = func isSorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, 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. + ## 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. ## ## **See also:** ## * `isSorted proc<#isSorted,openArray[T]>`_ @@ -535,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)>`_ @@ -555,46 +560,49 @@ proc isSorted*[T](a: openArray[T], order = SortOrder.Ascending): bool = isSorted(a, system.cmp[T], order) proc product*[T](x: openArray[seq[T]]): seq[seq[T]] = - ## Produces the Cartesian product of the array. Warning: complexity - ## may explode. + ## 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. 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 x.len == 0: + if xLen == 0: return - if x.len == 1: + if xLen == 1: result = @x return var - indexes = newSeq[int](x.len) - initial = newSeq[int](x.len) + indices = newSeq[int](xLen) + initial = newSeq[int](xLen) index = 0 - var next = newSeq[T]() - next.setLen(x.len) - for i in 0..(x.len-1): + var next = newSeq[T](xLen) + for i in 0 ..< xLen: if len(x[i]) == 0: return - initial[i] = len(x[i])-1 - indexes = initial + initial[i] = len(x[i]) - 1 + indices = initial while true: - while indexes[index] == -1: - indexes[index] = initial[index] + while indices[index] == -1: + indices[index] = initial[index] index += 1 - if index == x.len: return - indexes[index] -= 1 - for ni, i in indexes: + if index == xLen: return + indices[index] -= 1 + for ni, i in indices: next[ni] = x[ni][i] result.add(next) index = 0 - indexes[index] -= 1 + indices[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 last. + ## will **not** give you all permutations but stop with the last. ## ## **See also:** ## * `prevPermutation proc<#prevPermutation,openArray[T]>`_ @@ -630,7 +638,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:** @@ -664,7 +672,8 @@ proc prevPermutation*[T](x: var openArray[T]): bool {.discardable.} = result = true proc rotateInternal[T](arg: var openArray[T]; first, middle, last: int): int = - ## A port of std::rotate from c++. Ported from `this reference `_. + ## A port of std::rotate from C++. + ## Ported from [this reference](http://www.cplusplus.com/reference/algorithm/rotate/). result = first + last - middle if first == middle or middle == last: @@ -703,7 +712,8 @@ 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] = - result = newSeq[T](arg.len) + let argLen = arg.len + result = newSeq[T](argLen) for i in 0 ..< first: result[i] = arg[i] let n = last - middle @@ -712,34 +722,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 ..< arg.len: + for i in last ..< argLen: 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 `IndexDefect`. ## - ## ``slice`` + ## `slice` ## The indices of the element range that should be rotated. ## - ## ``dist`` + ## `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) @@ -751,15 +761,16 @@ proc rotateLeft*[T](arg: var openArray[T]; slice: HSlice[int, int]; doAssertRaises(IndexDefect, 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.} = - ## Default arguments for slice, so that this procedure operates on the entire - ## ``arg``, and not just on a part of it. + ## 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. ## ## **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) @@ -768,22 +779,22 @@ 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 `IndexDefect`. ## - ## ``slice`` + ## `slice` ## The indices of the element range that should be rotated. ## - ## ``dist`` + ## `dist` ## The distance in amount of elements that the data should be rotated. ## Can be negative, can be any number. ## @@ -800,11 +811,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 @@ -817,6 +828,6 @@ 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, arg.len) + let argLen = arg.len + let distLeft = ((dist mod argLen) + argLen) mod argLen + arg.rotatedInternal(0, distLeft, argLen) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 1b35482682..55a20270d9 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,9 +35,9 @@ ## 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: @@ -49,18 +49,18 @@ ## echo(future.read) ## ) ## -## All asynchronous functions returning a ``Future`` will not block. They +## 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 +## 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. ## @@ -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,23 +86,23 @@ ## 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. ## ## Handling Exceptions ## ------------------- ## -## The most reliable way to handle exceptions is to use ``yield`` on a future -## then check the future's ``failed`` property. For example: +## The most reliable way to handle exceptions is to use `yield` on a future +## then check the future's `failed` property. For example: ## ## .. code-block:: Nim ## var future = sock.recv(100) @@ -110,7 +110,7 @@ ## if future.failed: ## # Handle exception ## -## The ``async`` procedures also offer limited support for the try statement. +## The `async` procedures also offer limited support for the try statement. ## ## .. code-block:: Nim ## try: @@ -129,9 +129,9 @@ ## ## 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 +## 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. +## `waitFor` for that purpose. ## ## Examples ## ======== @@ -144,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 @@ -164,7 +164,7 @@ ## Limitations/Bugs ## ================ ## -## * The effect system (``raises: []``) does not work with async procedures. +## * The effect system (`raises: []`) does not work with async procedures. import os, tables, strutils, times, heapqueue, options, asyncstreams import options, math, std/monotimes @@ -232,7 +232,7 @@ 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. + ## Returns `true` on success. ## ## This procedure is not guaranteed to be available for all platforms. ## Test for availability with `declared() `_. @@ -307,7 +307,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, @@ -430,16 +430,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 @@ -503,17 +503,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 @@ -569,11 +569,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") @@ -607,16 +607,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") @@ -652,17 +652,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) @@ -715,11 +715,11 @@ 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 + ## 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) @@ -796,9 +796,9 @@ 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 @@ -810,7 +810,7 @@ when defined(windows) or defined(nimdoc): getGlobalDispatcher().handles.excl(socket) proc unregister*(fd: AsyncFD) = - ## Unregisters ``fd``. + ## Unregisters `fd`. getGlobalDispatcher().handles.excl(fd) proc contains*(disp: PDispatcher, fd: AsyncFD): bool = @@ -910,9 +910,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). @@ -921,16 +921,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). @@ -939,8 +939,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) @@ -980,12 +980,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 @@ -1014,8 +1014,8 @@ 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. + ## Registers callback `cb` to be called when process with process ID + ## `pid` exited. const NULL = Handle(0) let p = getGlobalDispatcher() let procFlags = SYNCHRONIZE @@ -1033,10 +1033,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 @@ -1048,12 +1048,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)) @@ -1064,14 +1064,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() @@ -1279,7 +1279,7 @@ else: var newList = newSeqOfCap[Callback](newLength) var cb = curList[0] - if not cb(fd.AsyncFD): + if not cb(fd): newList.add(cb) withData(p.selector, fd.int, adata) do: @@ -1460,8 +1460,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") @@ -1491,9 +1491,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") @@ -1563,45 +1563,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() @@ -1609,8 +1609,8 @@ 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 + ## 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() @@ -1621,7 +1621,7 @@ proc drain*(timeout = 500) = break 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) @@ -1686,13 +1686,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))) @@ -1802,9 +1802,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. @@ -1832,7 +1832,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: @@ -1843,11 +1843,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`") @@ -1870,7 +1870,7 @@ proc accept*(socket: 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 + ## 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. @@ -1890,7 +1890,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: diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim index 71b42c763b..c51b338e33 100644 --- a/lib/pure/asyncfile.nim +++ b/lib/pure/asyncfile.nim @@ -10,7 +10,7 @@ ## This module implements asynchronous file reading and writing. ## ## .. code-block:: Nim -## import asyncfile, asyncdispatch, os +## import std/[asyncfile, asyncdispatch, os] ## ## proc main() {.async.} = ## var file = openAsync(getTempDir() / "foobar.txt", fmReadWrite) @@ -90,8 +90,8 @@ 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) @@ -124,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): @@ -201,7 +201,7 @@ 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 + ## 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 @@ -332,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. @@ -401,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. diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index b538e10c91..0ee45785da 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -19,30 +19,30 @@ ## =========================== ## ## 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. +## connect to an FTP server. You can do so with the `connect` procedure. ## ## .. code-block::nim -## import asyncdispatch, asyncftpclient +## import std/[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. +## 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 +## 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 +## working directory before you do so with the `pwd` procedure, you can also ## instead specify an absolute path. ## ## .. code-block::nim -## import asyncdispatch, asyncftpclient +## import std/[asyncdispatch, asyncftpclient] ## proc main() {.async.} = ## var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test") ## await ftp.connect() @@ -56,14 +56,14 @@ ## ======================================== ## ## 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. +## by specifying a `onProgressChanged` procedure to the `store` or +## `retrFile` procedures. ## -## Procs that take an ``onProgressChanged`` callback will call this every -## ``progressInterval`` milliseconds. +## Procs that take an `onProgressChanged` callback will call this every +## `progressInterval` milliseconds. ## ## .. code-block::nim -## import asyncdispatch, asyncftpclient +## import std/[asyncdispatch, asyncftpclient] ## ## proc onProgressChanged(total, progress: BiggestInt, ## speed: float) {.async.} = @@ -134,44 +134,44 @@ type const multiLineLimit = 10000 -proc expectReply(ftp: AsyncFtpClient): Future[TaintedString] {.async.} = +proc expectReply(ftp: AsyncFtpClient): Future[string] {.async.} = var line = await ftp.csock.recvLine() - result = TaintedString(line) + result = line var count = 0 while line.len > 3 and line[3] == '-': ## Multi-line reply. line = await ftp.csock.recvLine() - string(result).add("\n" & line) + 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.} = +proc send*(ftp: AsyncFtpClient, m: string): Future[string] {.async.} = ## Send a message to the server, and wait for a primary reply. - ## ``\c\L`` is added for you. + ## `\c\L` is added for you. ## - ## You need to make sure that the message ``m`` doesn't contain any newline - ## characters. Failing to do so will raise ``AssertionDefect``. + ## You need to make sure that the message `m` doesn't contain any newline + ## characters. Failing to do so will raise `AssertionDefect`. ## ## **Note:** The server may return multiple lines of coded replies. doAssert(not m.contains({'\c', '\L'}), "message shouldn't contain any newline characters") await ftp.csock.send(m & "\c\L") return await ftp.expectReply() -proc assertReply(received: TaintedString, expected: varargs[string]) = +proc assertReply(received: string, expected: varargs[string]) = for i in items(expected): - if received.string.startsWith(i): return + if received.startsWith(i): return raise newException(ReplyError, "Expected reply '$1' got: $2" % - [expected.join("' or '"), received.string]) + [expected.join("' or '"), received]) proc pasv(ftp: AsyncFtpClient) {.async.} = ## Negotiate a data connection. ftp.dsock = newAsyncSocket() - var pasvMsg = (await ftp.send("PASV")).string.strip.TaintedString + var pasvMsg = (await ftp.send("PASV")).strip assertReply(pasvMsg, "227") - var betweenParens = captureBetween(pasvMsg.string, '(', ')') + var betweenParens = captureBetween(pasvMsg, '(', ')') var nums = betweenParens.split(',') var ip = nums[0 .. ^3] var port = nums[^2 .. ^1] @@ -183,11 +183,11 @@ proc normalizePathSep(path: string): string = return replace(path, '\\', '/') proc connect*(ftp: AsyncFtpClient) {.async.} = - ## Connect to the FTP server specified by ``ftp``. + ## 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"): + if reply.startsWith("120"): # 120 Service ready in nnn minutes. # We wait until we receive 220. reply = await ftp.expectReply() @@ -201,14 +201,14 @@ proc connect*(ftp: AsyncFtpClient) {.async.} = if ftp.pass != "": assertReply(await(ftp.send("PASS " & ftp.pass)), "230") -proc pwd*(ftp: AsyncFtpClient): Future[TaintedString] {.async.} = +proc pwd*(ftp: AsyncFtpClient): Future[string] {.async.} = ## Returns the current working directory. let wd = await ftp.send("PWD") assertReply wd, "257" - return wd.string.captureBetween('"').TaintedString # " + return wd.captureBetween('"') # " proc cd*(ftp: AsyncFtpClient, dir: string) {.async.} = - ## Changes the current directory on the remote FTP server to ``dir``. + ## Changes the current directory on the remote FTP server to `dir`. assertReply(await(ftp.send("CWD " & dir.normalizePathSep)), "250") proc cdup*(ftp: AsyncFtpClient) {.async.} = @@ -221,18 +221,18 @@ proc getLines(ftp: AsyncFtpClient): Future[string] {.async.} = assert ftp.dsockConnected while ftp.dsockConnected: let r = await ftp.dsock.recvLine() - if r.string == "": + if r == "": ftp.dsockConnected = false else: - result.add(r.string & "\n") + result.add(r & "\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 + ## 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. + ## use asyncdispatch's `poll` to progress this operation. await ftp.pasv() assertReply(await(ftp.send("NLST " & dir.normalizePathSep)), ["125", "150"]) @@ -240,20 +240,20 @@ proc listDirs*(ftp: AsyncFtpClient, dir = ""): Future[seq[string]] {.async.} = result = splitLines(await ftp.getLines()) proc fileExists*(ftp: AsyncFtpClient, file: string): Future[bool] {.async.} = - ## Determines whether ``file`` exists. + ## 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 + ## 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 reply = "" var previousDirs = "" for p in split(dir, {os.DirSep, os.AltSep}): if p != "": @@ -264,7 +264,7 @@ proc createDir*(ftp: AsyncFtpClient, dir: string, recursive = false){.async.} = proc chmod*(ftp: AsyncFtpClient, path: string, permissions: set[FilePermission]) {.async.} = - ## Changes permission of ``path`` to ``permissions``. + ## Changes permission of `path` to `permissions`. var userOctal = 0 var groupOctal = 0 var otherOctal = 0 @@ -285,7 +285,7 @@ proc chmod*(ftp: AsyncFtpClient, path: string, " " & path.normalizePathSep)), "200") proc list*(ftp: AsyncFtpClient, dir = ""): Future[string] {.async.} = - ## Lists all files in ``dir``. If ``dir`` is ``""``, uses the current + ## Lists all files in `dir`. If `dir` is `""`, uses the current ## working directory. await ftp.pasv() @@ -295,7 +295,7 @@ proc list*(ftp: AsyncFtpClient, dir = ""): Future[string] {.async.} = result = await ftp.getLines() proc retrText*(ftp: AsyncFtpClient, file: string): Future[string] {.async.} = - ## Retrieves ``file``. File must be ASCII text. + ## Retrieves `file`. File must be ASCII text. await ftp.pasv() let reply = await ftp.send("RETR " & file.normalizePathSep) assertReply(reply, ["125", "150"]) @@ -331,25 +331,25 @@ proc getFile(ftp: AsyncFtpClient, file: File, total: BiggestInt, proc defaultOnProgressChanged*(total, progress: BiggestInt, speed: float): Future[void] {.nimcall, gcsafe.} = - ## Default FTP ``onProgressChanged`` handler. Does nothing. + ## 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``. + ## 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: + if {'(', ')'} notin reply: raise newException(ReplyError, "Reply has no file size.") var fileSize: BiggestInt - if reply.string.captureBetween('(', ')').parseBiggestInt(fileSize) == 0: + if reply.captureBetween('(', ')').parseBiggestInt(fileSize) == 0: raise newException(ReplyError, "Reply has no file size.") await getFile(ftp, destFile, fileSize, onProgressChanged) @@ -390,12 +390,12 @@ proc doUpload(ftp: AsyncFtpClient, file: File, proc store*(ftp: AsyncFtpClient, file, dest: string, onProgressChanged: ProgressChangedProc = defaultOnProgressChanged) {.async.} = - ## Uploads ``file`` to ``dest`` on the remote FTP server. Usage of this + ## 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``. + ## 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() @@ -406,21 +406,21 @@ proc store*(ftp: AsyncFtpClient, file, dest: string, 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`` + ## `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 + ## 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 + ## 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 = "", progressInterval: int = 1000): AsyncFtpClient = - ## Creates a new ``AsyncFtpClient`` object. + ## Creates a new `AsyncFtpClient` object. new result result.user = user result.pass = pass diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 2333c5ef16..c0c5c3f07f 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -9,7 +9,7 @@ import os, tables, strutils, times, heapqueue, options, deques, cstrutils -import "system/stacktraces" +import system/stacktraces # TODO: This shouldn't need to be included, but should ideally be exported. type @@ -86,19 +86,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 ()) = - ## Call ``cbproc`` "soon". + ## 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() @@ -117,29 +117,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 = "" @@ -190,7 +190,7 @@ proc add(callbacks: var CallbackList, function: CallbackFunc) = last.next = newCallback proc complete*[T](future: Future[T], val: T) = - ## Completes ``future`` with value ``val``. + ## Completes `future` with value `val`. #assert(not future.finished, "Future already finished, cannot finish twice.") checkFinished(future) assert(future.error == nil) @@ -200,7 +200,7 @@ proc complete*[T](future: Future[T], val: T) = when isFutureLoggingEnabled: logFutureFinish(future) proc complete*(future: Future[void]) = - ## Completes a void ``future``. + ## Completes a void `future`. #assert(not future.finished, "Future already finished, cannot finish twice.") checkFinished(future) assert(future.error == nil) @@ -209,7 +209,7 @@ proc complete*(future: Future[void]) = 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) @@ -218,7 +218,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) @@ -230,7 +230,7 @@ proc complete*[T](future: FutureVar[T], val: T) = 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 @@ -247,7 +247,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) @@ -258,7 +258,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) @@ -267,9 +267,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 @@ -277,7 +277,7 @@ 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) proc getHint(entry: StackTraceEntry): string = @@ -359,12 +359,15 @@ proc injectStacktrace[T](future: Future[T]) = 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. {.push hint[ConvFromXtoItselfNotNeeded]: off.} - let fut = Future[T](future) + when future is Future[T]: + let fut = future + else: + let fut = Future[T](future) {.pop.} if fut.finished: if fut.error != nil: @@ -377,40 +380,40 @@ proc read*[T](future: Future[T] | FutureVar[T]): T = 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. @@ -421,7 +424,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 = @@ -437,7 +440,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]) = @@ -450,14 +453,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 f3f59baf8b..38be4ceac6 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -13,37 +13,35 @@ ## 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. -## -## Example -## ======= -## -## 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 -## -## proc main {.async.} = -## var server = newAsyncHttpServer() -## proc cb(req: Request) {.async.} = -## 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()) -## -## server.listen Port(8080) -## while true: -## if server.shouldAcceptRequest(): -## asyncCheck server.acceptRequest(cb) -## else: -## poll() -## -## asyncCheck main() -## runForever() + +runnableExamples("-r:off"): + # 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. + import std/asyncdispatch + proc main {.async.} = + const port = 8080 + 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()) + + echo "test this with: curl localhost:" & $port & "/" + server.listen(Port(port)) + 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 httpcore +import std/private/since export httpcore except parseHeader @@ -72,9 +70,25 @@ type maxBody: int ## The maximum content-length that will be read for the body. maxFDs: int +func getSocket*(a: AsyncHttpServer): AsyncSocket {.since: (1, 5, 1).} = + ## Returns the `AsyncHttpServer`s internal `AsyncSocket` instance. + ## + ## Useful for identifying what port the AsyncHttpServer is bound to, if it + ## was chosen automatically. + runnableExamples: + from std/asyncdispatch import Port + from std/asyncnet import getFd + from std/nativesockets import getLocalAddr, AF_INET + let server = newAsyncHttpServer() + server.listen(Port(0)) # Socket is not bound until this point + let port = getLocalAddr(server.getSocket.getFd, AF_INET)[1] + doAssert uint16(port) > 0 + server.close() + a.socket + proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, maxBody = 8388608): AsyncHttpServer = - ## Creates a new ``AsyncHttpServer`` instance. + ## Creates a new `AsyncHttpServer` instance. result = AsyncHttpServer(reuseAddr: reuseAddr, reusePort: reusePort, maxBody: maxBody) proc addHeaders(msg: var string, headers: HttpHeaders) = @@ -89,7 +103,7 @@ 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. @@ -97,7 +111,7 @@ proc respond*(req: Request, code: HttpCode, content: string, ## Example: ## ## .. code-block::nim - ## import json + ## import std/json ## proc handler(req: Request) {.async.} = ## if req.url.path == "/hello-world": ## let msg = %* {"message": "Hello World"} @@ -122,7 +136,7 @@ proc respond*(req: Request, code: HttpCode, content: string, 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" @@ -143,6 +157,17 @@ 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], @@ -262,6 +287,43 @@ proc processRequest( 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 + 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") + return true + + inc sizeOrData elif request.reqMethod == HttpPost: await request.respond(Http411, "Content-Length required.") return true @@ -368,23 +430,3 @@ proc serve*(server: AsyncHttpServer, port: Port, proc close*(server: AsyncHttpServer) = ## Terminates the async http server instance. server.socket.close() - -when not defined(testing) and isMainModule: - proc main {.async.} = - 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()) - - server.listen Port(5555) - while true: - if server.shouldAcceptRequest(): - asyncCheck server.acceptRequest(cb) - else: - poll() - - asyncCheck main() - runForever() diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index c60c5e4ca1..3097ac104e 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -146,7 +146,7 @@ template await*[T](f: Future[T]): auto {.used.} = 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. + ## The `async` macro supports a stmtList holding multiple async procedures. if prc.kind == nnkProcTy: result = prc if prc[0][0].kind == nnkEmpty: @@ -320,8 +320,8 @@ proc stripReturnType(returnType: NimNode): NimNode = 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]`. @@ -349,8 +349,8 @@ 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)) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 455efe1c1b..f36c427de5 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 @@ -67,7 +67,7 @@ ## ## .. code-block::nim ## -## import asyncnet, asyncdispatch +## import std/[asyncnet, asyncdispatch] ## ## var clients {.threadvar.}: seq[AsyncSocket] ## @@ -134,16 +134,16 @@ proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET, protocol: Protocol = IPPROTO_TCP, buffered = true, inheritable = defined(nimInheritHandles)): owned(AsyncSocket) = - ## Creates a new ``AsyncSocket`` based on the supplied params. + ## 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 + ## 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 @@ -165,7 +165,7 @@ proc newAsyncSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, ## 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 + ## If `inheritable` is false (the default), the new file descriptor will not ## be inheritable by child processes. let fd = createAsyncNativeSocket(domain, sockType, protocol, inheritable) if fd.SocketHandle == osInvalidSocket: @@ -192,7 +192,7 @@ proc newAsyncSocket*(domain, sockType, protocol: cint, ## 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 + ## If `inheritable` is false (the default), the new file descriptor will not ## be inheritable by child processes. let fd = createAsyncNativeSocket(domain, sockType, protocol, inheritable) if fd.SocketHandle == osInvalidSocket: @@ -233,7 +233,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: @@ -259,11 +259,9 @@ when defineSsl: ErrClearError() # Call the desired operation. opResult = op - # Bit hackish here. - # TODO: Introduce an async template transformation pragma? # Send any remaining pending SSL data. - yield sendPendingSslData(socket, flags) + await sendPendingSslData(socket, flags) # If the operation failed, try to see if SSL has some data to read # or write. @@ -281,9 +279,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) @@ -292,9 +290,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: @@ -310,7 +308,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 @@ -321,10 +319,8 @@ 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 = recvIntoFut.read() + res = await asyncdispatch.recvInto(socket.fd.AsyncFD, buf, size, flags) res template readIntoBuf(socket: AsyncSocket, @@ -336,10 +332,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 @@ -350,7 +346,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 @@ -384,10 +380,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 @@ -398,7 +394,7 @@ 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) shallow(result) @@ -436,7 +432,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") @@ -450,7 +446,7 @@ 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: @@ -468,7 +464,7 @@ proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}, ## 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 + ## 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. @@ -490,7 +486,7 @@ 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 + ## 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") @@ -506,25 +502,24 @@ 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") @@ -599,26 +594,25 @@ 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 @@ -629,8 +623,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. @@ -638,9 +632,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 @@ -739,7 +733,7 @@ proc close*(socket: AsyncSocket) = when defineSsl: 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. @@ -759,8 +753,8 @@ when defineSsl: 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 @@ -793,18 +787,18 @@ when defineSsl: 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 = @@ -818,7 +812,7 @@ proc isClosed*(socket: AsyncSocket): bool = 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 + ## 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. @@ -865,9 +859,9 @@ 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 + ## 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. ## @@ -876,8 +870,8 @@ proc recvFrom*(socket: AsyncSocket, data: FutureVar[string], size: int, ## 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. + ## * `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 @@ -919,8 +913,8 @@ 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 + ## 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. ## diff --git a/lib/pure/asyncstreams.nim b/lib/pure/asyncstreams.nim index 7ffde9c106..083c6f0eab 100644 --- a/lib/pure/asyncstreams.nim +++ b/lib/pure/asyncstreams.nim @@ -21,16 +21,17 @@ 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 @@ -39,20 +40,29 @@ 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. + ## Completes a `FutureStream` signalling the end of data. + assert(future.error == nil, "Trying to complete failed stream") 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 @@ -60,15 +70,19 @@ proc `callback=`*[T](future: FutureStream[T], 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." @@ -81,14 +95,14 @@ 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]) = @@ -107,10 +121,17 @@ proc read*[T](future: FutureStream[T]): owned(Future[(bool, T)]) = res[0] = true res[1] = fs.queue.popFirst() - resFut.complete(res) + 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: savedCb() + if not savedCb.isNil: + if fs.queue.len > 0: + savedCb() + else: + future.cb = savedCb if future.queue.len > 0 or future.finished: newCb(future) diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index 40c9af9056..bf196b54de 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -24,14 +24,14 @@ ## ------------- ## ## .. code-block::nim -## import base64 +## import std/base64 ## let encoded = encode("Hello World") ## assert encoded == "SGVsbG8gV29ybGQ=" ## ## Apart from strings you can also encode lists of integers or characters: ## ## .. code-block::nim -## import base64 +## import std/base64 ## let encodedInts = encode([1,2,3]) ## assert encodedInts == "AQID" ## let encodedChars = encode(['h','e','y']) @@ -42,7 +42,7 @@ ## ------------- ## ## .. code-block::nim -## import base64 +## import std/base64 ## let decoded = decode("SGVsbG8gV29ybGQ=") ## assert decoded == "Hello World" ## @@ -50,7 +50,7 @@ ## --------------- ## ## .. code-block::nim -## import base64 +## import std/base64 ## doAssert encode("c\xf7>", safe = true) == "Y_c-" ## doAssert encode("c\xf7>", safe = false) == "Y/c+" ## @@ -149,9 +149,9 @@ proc encode*[T: SomeInteger|char](s: openArray[T], safe = false): string = ## This procedure encodes an openarray (array or sequence) of either integers ## or characters. ## - ## If ``safe`` is ``true`` then it will encode using the + ## 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 ``/``. + ## which substitutes `-` instead of `+` and `_` instead of `/`. ## * https://en.wikipedia.org/wiki/Base64#URL_applications ## * https://tools.ietf.org/html/rfc4648#page-7 ## @@ -165,13 +165,13 @@ proc encode*[T: SomeInteger|char](s: openArray[T], safe = false): string = encodeImpl() proc encode*(s: string, safe = false): string = - ## Encodes ``s`` into base64 representation. + ## Encodes `s` into base64 representation. ## ## This procedure encodes a string. ## - ## If ``safe`` is ``true`` then it will encode using the + ## 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 ``/``. + ## which substitutes `-` instead of `+` and `_` instead of `/`. ## * https://en.wikipedia.org/wiki/Base64#URL_applications ## * https://tools.ietf.org/html/rfc4648#page-7 ## @@ -183,8 +183,8 @@ proc encode*(s: string, safe = false): string = encodeImpl() proc encodeMime*(s: string, lineLen = 75, newLine = "\r\n"): string = - ## Encodes ``s`` into base64 representation as lines. - ## Used in email MIME format, use ``lineLen`` and ``newline``. + ## Encodes `s` into base64 representation as lines. + ## Used in email MIME format, use `lineLen` and `newline`. ## ## This procedure encodes a string according to MIME spec. ## @@ -193,6 +193,7 @@ proc encodeMime*(s: string, lineLen = 75, newLine = "\r\n"): string = ## * `decode proc<#decode,string>`_ for decoding a string runnableExamples: assert encodeMime("Hello World", 4, "\n") == "SGVs\nbG8g\nV29y\nbGQ=" + result = newStringOfCap(encodeSize(s.len)) for i, c in encode(s): if i != 0 and (i mod lineLen == 0): result.add(newLine) @@ -214,7 +215,7 @@ 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:** diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 4f22388f36..377602e75d 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -8,27 +8,30 @@ # ## 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``. ## -## The module will fallback to pure nim procs incase the backend is not supported. +## 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. ## 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 function/intrinsics some functions can return +## As a result of using optimized functions/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`, `countTrailingZeroBits` -## may return undefined and/or platform dependent value if given invalid input. +## At this time only `fastLog2`, `firstSetBit`, `countLeadingZeroBits` and `countTrailingZeroBits` +## may return undefined and/or platform dependent values if given invalid input. import macros import std/private/since +from std/private/vmutils import forwardImpl, toUnsigned -proc bitnot*[T: SomeInteger](x: T): T {.magic: "BitnotI", noSideEffect.} + + +func bitnot*[T: SomeInteger](x: T): T {.magic: "BitnotI".} ## Computes the `bitwise complement` of the integer `x`. func internalBitand[T: SomeInteger](x, y: T): T {.magic: "BitandI".} @@ -58,339 +61,317 @@ macro bitxor*[T: SomeInteger](x, y: T; z: varargs[T]): T = 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 -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) +type BitsRange*[T] = range[0..sizeof(T)*8-1] + ## A range with all bit positions for type `T`. -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) +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 -when defined(nimHasalignOf): - type BitsRange*[T] = range[0..sizeof(T)*8-1] - ## A range with all bit positions for type ``T`` + let + upmost = sizeof(T) * 8 - 1 + uv = when v is SomeUnsignedInt: v else: v.toUnsigned + (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T - 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 +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 - let - upmost = sizeof(T) * 8 - 1 - uv = when v is SomeUnsignedInt: v else: v.toUnsigned - (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T + let + upmost = sizeof(T) * 8 - 1 + uv = when v is SomeUnsignedInt: v else: v.toUnsigned + v = (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T - 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 +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 - let - upmost = sizeof(T) * 8 - 1 - uv = when v is SomeUnsignedInt: v else: v.toUnsigned - v = (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T + let + upmost = sizeof(T) * 8 - 1 + bitmask = when T is SomeUnsignedInt: + bitnot(0.T) + else: + bitnot(0.T).toUnsigned + (bitmask shl (upmost - slice.b + slice.a) shr (upmost - slice.b)).T - 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 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 - let - upmost = sizeof(T) * 8 - 1 - bitmask = when T is SomeUnsignedInt: - bitnot(0.T) - else: - bitnot(0.T).toUnsigned - (bitmask shl (upmost - slice.b + slice.a) shr (upmost - slice.b)).T + bitand(v, mask) - 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` operation. - runnableExamples: - var v = 0b0000_0011'u8 - doAssert v.masked(0b0000_1010'u8) == 0b0000_0010'u8 +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 - bitand(v, mask) + bitand(v, toMask[T](slice)) - func masked*[T: SomeInteger](v: T; slice: Slice[int]): T {.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` operation. - runnableExamples: - var v = 0b0000_1011'u8 - doAssert v.masked(1 .. 3) == 0b0000_1010'u8 +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 - bitand(v, toMask[T](slice)) + v = bitand(v, mask) - 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` operation. - runnableExamples: - var v = 0b0000_0011'u8 - v.mask(0b0000_1010'u8) - doAssert v == 0b0000_0010'u8 +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, mask) + v = bitand(v, toMask[T](slice)) - 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` operation. - runnableExamples: - var v = 0b0000_1011'u8 - v.mask(1 .. 3) - doAssert v == 0b0000_1010'u8 +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 - v = bitand(v, toMask[T](slice)) + bitor(v, mask) - 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` operation. - runnableExamples: - var v = 0b0000_0011'u8 - doAssert v.setMasked(0b0000_1010'u8) == 0b0000_1011'u8 +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, mask) + bitor(v, toMask[T](slice)) - 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` operation. - runnableExamples: - var v = 0b0000_0011'u8 - doAssert v.setMasked(2 .. 3) == 0b0000_1111'u8 +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 - bitor(v, toMask[T](slice)) + v = bitor(v, mask) - 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` operation. - runnableExamples: - var v = 0b0000_0011'u8 - v.setMask(0b0000_1010'u8) - doAssert v == 0b0000_1011'u8 +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, mask) + v = bitor(v, toMask[T](slice)) - 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` operation. - runnableExamples: - var v = 0b0000_0011'u8 - v.setMask(2 .. 3) - doAssert v == 0b0000_1111'u8 +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 - v = bitor(v, toMask[T](slice)) + bitand(v, bitnot(mask)) - 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` operation with an *inverted mask.* - runnableExamples: - var v = 0b0000_0011'u8 - doAssert v.clearMasked(0b0000_1010'u8) == 0b0000_0001'u8 +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(mask)) + bitand(v, bitnot(toMask[T](slice))) - 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` operation with an *inverted mask.* - runnableExamples: - var v = 0b0000_0011'u8 - doAssert v.clearMasked(1 .. 3) == 0b0000_0001'u8 +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 - bitand(v, bitnot(toMask[T](slice))) + v = bitand(v, bitnot(mask)) - 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` operation with an *inverted mask.* - runnableExamples: - var v = 0b0000_0011'u8 - v.clearMask(0b0000_1010'u8) - doAssert v == 0b0000_0001'u8 +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(mask)) + v = bitand(v, bitnot(toMask[T](slice))) - 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` operation with an *inverted mask.* - runnableExamples: - var v = 0b0000_0011'u8 - v.clearMask(1 .. 3) - doAssert v == 0b0000_0001'u8 +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 - v = bitand(v, bitnot(toMask[T](slice))) + bitxor(v, mask) - 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` operation. - runnableExamples: - var v = 0b0000_0011'u8 - doAssert v.flipMasked(0b0000_1010'u8) == 0b0000_1001'u8 +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, mask) + bitxor(v, toMask[T](slice)) - 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` operation. - runnableExamples: - var v = 0b0000_0011'u8 - doAssert v.flipMasked(1 .. 3) == 0b0000_1101'u8 +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 - bitxor(v, toMask[T](slice)) + v = bitxor(v, mask) - 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` operation. - runnableExamples: - var v = 0b0000_0011'u8 - v.flipMask(0b0000_1010'u8) - doAssert v == 0b0000_1001'u8 +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, mask) + v = bitxor(v, toMask[T](slice)) - 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` operation. - runnableExamples: - var v = 0b0000_0011'u8 - v.flipMask(1 .. 3) - doAssert v == 0b0000_1101'u8 +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 = bitxor(v, toMask[T](slice)) + v.setMask(1.T shl bit) - 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 +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.setMask(1.T shl bit) + v.clearMask(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 +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.clearMask(1.T shl bit) + v = 0b0000_0011'u8 + v.flipBit(2'u8) + doAssert v == 0b0000_0111'u8 - 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.flipMask(1.T shl bit) - v = 0b0000_0011'u8 - v.flipBit(2'u8) - doAssert v == 0b0000_0111'u8 +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 - v.flipMask(1.T shl bit) + bits.expectKind(nnkBracket) + result = newStmtList() + for bit in bits: + result.add newCall("setBit", v, 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 +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("setBit", v, bit) + bits.expectKind(nnkBracket) + result = newStmtList() + for bit in bits: + result.add newCall("clearBit", 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 +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("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) + 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: - var v = 0b0000_1111'u8 - doAssert v.testBit(0) - doAssert not v.testBit(7) +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 + let mask = 1.T shl bit + return (v and mask) == mask # #### Pure Nim version #### -proc firstSetBitNim(x: uint32): int {.inline, noSideEffect.} = +func firstSetBitNim(x: uint32): int {.inline.} = ## 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] - var v = x.uint32 - var k = not v + 1 # get two's complement # cast[uint32](-cast[int32](v)) + let v = x.uint32 + let 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 -proc firstSetBitNim(x: uint64): int {.inline, noSideEffect.} = +func firstSetBitNim(x: uint64): int {.inline.} = ## 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 - var v = uint64(x) + let v = uint64(x) var k = uint32(v and 0xFFFFFFFF'u32) if k == 0: k = uint32(v shr 32'u32) and 0xFFFFFFFF'u32 @@ -399,7 +380,7 @@ proc firstSetBitNim(x: uint64): int {.inline, noSideEffect.} = result = 0 result += firstSetBitNim(k) -proc fastlog2Nim(x: uint32): int {.inline, noSideEffect.} = +func fastlog2Nim(x: uint32): int {.inline.} = ## 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 @@ -413,7 +394,7 @@ proc fastlog2Nim(x: uint32): int {.inline, noSideEffect.} = v = v or v shr 16 result = lookup[uint32(v * 0x07C4ACDD'u32) shr 27].int -proc fastlog2Nim(x: uint64): int {.inline, noSideEffect.} = +func fastlog2Nim(x: uint64): int {.inline.} = ## 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 @@ -430,13 +411,12 @@ proc fastlog2Nim(x: uint64): int {.inline, noSideEffect.} = v = v or v shr 32 result = lookup[(v * 0x03F6EAF2CD271461'u64) shr 58].int -# 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 +import system/countbits_impl -template countSetBitsNim(n: uint32): int = countBits32(n) -template countSetBitsNim(n: uint64): int = countBits64(n) +const arch64 = sizeof(int) == 8 +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 parityImpl[T](value: T): int = # formula id from: https://graphics.stanford.edu/%7Eseander/bithacks.html#ParityParallel @@ -453,11 +433,6 @@ 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.} @@ -475,25 +450,17 @@ 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). - proc bitScanReverse(index: ptr culong, mask: culong): cuchar {. - importc: "_BitScanReverse", header: "", noSideEffect.} - proc bitScanReverse64(index: ptr culong, mask: uint64): cuchar {. - importc: "_BitScanReverse64", header: "", noSideEffect.} + func bitScanReverse(index: ptr culong, mask: culong): cuchar {. + importc: "_BitScanReverse", header: "".} + func bitScanReverse64(index: ptr culong, mask: uint64): cuchar {. + importc: "_BitScanReverse64", header: "".} # Search the mask data from least significant bit (LSB) to the most significant bit (MSB) for a set bit (1). - proc bitScanForward(index: ptr culong, mask: culong): cuchar {. - importc: "_BitScanForward", header: "", noSideEffect.} - proc bitScanForward64(index: ptr culong, mask: uint64): cuchar {. - importc: "_BitScanForward64", header: "", noSideEffect.} + func bitScanForward(index: ptr culong, mask: culong): cuchar {. + importc: "_BitScanForward", header: "".} + func bitScanForward64(index: ptr culong, mask: uint64): cuchar {. + importc: "_BitScanForward64", header: "".} template vcc_scan_impl(fnc: untyped; v: untyped): int = var index: culong @@ -501,71 +468,38 @@ 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. - proc bitScanForward(p: ptr uint32, b: uint32): cuchar {. - importc: "_BitScanForward", header: "", noSideEffect.} - proc bitScanForward64(p: ptr uint32, b: uint64): cuchar {. - importc: "_BitScanForward64", header: "", noSideEffect.} + func bitScanForward(p: ptr uint32, b: uint32): cuchar {. + importc: "_BitScanForward", header: "".} + func bitScanForward64(p: ptr uint32, b: uint64): cuchar {. + importc: "_BitScanForward64", header: "".} # Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined. - proc bitScanReverse(p: ptr uint32, b: uint32): cuchar {. - importc: "_BitScanReverse", header: "", noSideEffect.} - proc bitScanReverse64(p: ptr uint32, b: uint64): cuchar {. - importc: "_BitScanReverse64", header: "", noSideEffect.} + func bitScanReverse(p: ptr uint32, b: uint32): cuchar {. + importc: "_BitScanReverse", header: "".} + func bitScanReverse64(p: ptr uint32, b: uint64): cuchar {. + importc: "_BitScanReverse64", header: "".} template icc_scan_impl(fnc: untyped; v: untyped): int = var index: uint32 discard fnc(index.addr, v) index.int - -proc countSetBits*(x: SomeInteger): int {.inline, noSideEffect.} = - ## Counts the set bits in integer. (also called `Hamming weight`:idx:.) +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 - # 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) + result = countSetBitsImpl(x) -proc popcount*(x: SomeInteger): int {.inline, noSideEffect.} = - ## Alias for for `countSetBits <#countSetBits,SomeInteger>`_. (Hamming weight.) +func popcount*(x: SomeInteger): int {.inline.} = + ## Alias for `countSetBits <#countSetBits,SomeInteger>`_ (Hamming weight). result = countSetBits(x) -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. +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 @@ -586,10 +520,10 @@ proc parityBits*(x: SomeInteger): int {.inline, noSideEffect.} = when sizeof(x) <= 4: result = parityImpl(x.uint32) else: result = parityImpl(x.uint64) -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. +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 @@ -630,10 +564,10 @@ proc firstSetBit*(x: SomeInteger): int {.inline, noSideEffect.} = when sizeof(x) <= 4: result = firstSetBitNim(x.uint32) else: result = firstSetBitNim(x.uint64) -proc fastLog2*(x: SomeInteger): int {.inline, noSideEffect.} = +func fastLog2*(x: SomeInteger): int {.inline.} = ## Quickly find the log base 2 of an integer. - ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is -1, - ## otherwise result is undefined. + ## 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 @@ -670,12 +604,12 @@ proc fastLog2*(x: SomeInteger): int {.inline, noSideEffect.} = when sizeof(x) <= 4: result = fastlog2Nim(x.uint32) else: result = fastlog2Nim(x.uint64) -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. +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: + ## **See also:** ## * `countTrailingZeroBits proc <#countTrailingZeroBits,SomeInteger>`_ runnableExamples: doAssert countLeadingZeroBits(0b0000_0001'u8) == 7 @@ -699,12 +633,12 @@ proc countLeadingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} = when sizeof(x) <= 4: result = sizeof(x)*8 - 1 - fastlog2Nim(x.uint32) else: result = sizeof(x)*8 - 1 - fastlog2Nim(x.uint64) -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. +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: + ## **See also:** ## * `countLeadingZeroBits proc <#countLeadingZeroBits,SomeInteger>`_ runnableExamples: doAssert countTrailingZeroBits(0b0000_0001'u8) == 0 @@ -727,99 +661,253 @@ proc countTrailingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} = 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: cuchar, shift: cint): cuchar + {.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: uint8; - amount: range[0..8]): uint8 {.inline, noSideEffect.} = + func builtin_rotr8(value: cuchar, shift: cint): cuchar + {.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: cuchar, shift: cuchar): cuchar + {.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.} + + func builtin_rotr8(value: cuchar, shift: cuchar): cuchar + {.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: cuchar, shift: cuchar): cuchar + {.importc: "_rotl8", header: "".} + func builtin_rotl16(value: cushort, shift: cuchar): 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: "".} + + func builtin_rotr8(value: cuchar, shift: cuchar): cuchar + {.importc: "_rotr8", header: "".} + func builtin_rotr16(value: cushort, shift: cuchar): 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: cuchar, shift: cint): cuchar + {.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: cuchar, shift: cint): cuchar + {.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: "".} + +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)) + +func shiftTypeToImpl(size: static int, shift: int): auto {.inline.} = + 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): + cuchar(shift) + elif defined(clang): + when size == 2: + cushort(shift) + elif size == 4: + cuint(shift) + elif size == 8: + culonglong(shift) + +template shiftTypeTo[T](value: T, shift: int): auto = + ## Returns the `shift` for the rotation according to the compiler and the size + ## of the` value`. + shiftTypeToImpl(sizeof(value), shift) + +func rotateLeftBits*(value: uint8, shift: range[0..8]): uint8 {.inline.} = ## Left-rotate bits in a 8-bits value. runnableExamples: - doAssert rotateLeftBits(0b0000_0001'u8, 1) == 0b0000_0010'u8 - doAssert rotateLeftBits(0b0000_0001'u8, 2) == 0b0000_0100'u8 - doAssert rotateLeftBits(0b0100_0001'u8, 1) == 0b1000_0010'u8 - doAssert rotateLeftBits(0b0100_0001'u8, 2) == 0b0000_0101'u8 + doAssert rotateLeftBits(0b0110_1001'u8, 4) == 0b1001_0110'u8 - # 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)) + when nimvm: + rotl(value, shift.int32) + else: + when useBuiltinsRotate: + builtin_rotl8(value.cuchar, shiftTypeTo(value, shift)).uint8 + else: + rotl(value, shift.int32) -proc rotateLeftBits*(value: uint16; - amount: range[0..16]): uint16 {.inline, noSideEffect.} = +func rotateLeftBits*(value: uint16, shift: range[0..16]): uint16 {.inline.} = ## Left-rotate bits in a 16-bits value. - ## - ## See also: - ## * `rotateLeftBits proc <#rotateLeftBits,uint8,range[]>`_ - let amount = amount and 15 - result = (value shl amount) or (value shr ( (-amount) and 15)) + runnableExamples: + doAssert rotateLeftBits(0b00111100_11000011'u16, 8) == + 0b11000011_00111100'u16 -proc rotateLeftBits*(value: uint32; - amount: range[0..32]): uint32 {.inline, noSideEffect.} = + when nimvm: + rotl(value, shift.int32) + else: + when useBuiltinsRotate: + builtin_rotl16(value.cushort, shiftTypeTo(value, shift)).uint16 + else: + rotl(value, shift.int32) + +func rotateLeftBits*(value: uint32, shift: range[0..32]): uint32 {.inline.} = ## Left-rotate bits in a 32-bits value. - ## - ## See also: - ## * `rotateLeftBits proc <#rotateLeftBits,uint8,range[]>`_ - let amount = amount and 31 - result = (value shl amount) or (value shr ( (-amount) and 31)) + runnableExamples: + doAssert rotateLeftBits(0b0000111111110000_1111000000001111'u32, 16) == + 0b1111000000001111_0000111111110000'u32 -proc rotateLeftBits*(value: uint64; - amount: range[0..64]): uint64 {.inline, noSideEffect.} = + when nimvm: + rotl(value, shift.int32) + else: + when useBuiltinsRotate: + builtin_rotl32(value.cuint, shiftTypeTo(value, shift)).uint32 + else: + rotl(value, shift.int32) + +func rotateLeftBits*(value: uint64, shift: range[0..64]): uint64 {.inline.} = ## Left-rotate bits in a 64-bits value. - ## - ## See also: - ## * `rotateLeftBits proc <#rotateLeftBits,uint8,range[]>`_ - let amount = amount and 63 - result = (value shl amount) or (value shr ( (-amount) and 63)) + runnableExamples: + doAssert rotateLeftBits(0b00000000111111111111111100000000_11111111000000000000000011111111'u64, 32) == + 0b11111111000000000000000011111111_00000000111111111111111100000000'u64 + when nimvm: + rotl(value, shift.int32) + else: + when useBuiltinsRotate and defined(amd64): + builtin_rotl64(value.culonglong, shiftTypeTo(value, shift)).uint64 + else: + rotl(value, shift.int32) -proc rotateRightBits*(value: uint8; - amount: range[0..8]): uint8 {.inline, noSideEffect.} = +func rotateRightBits*(value: uint8, shift: range[0..8]): uint8 {.inline.} = ## Right-rotate bits in a 8-bits value. runnableExamples: - doAssert rotateRightBits(0b0000_0001'u8, 1) == 0b1000_0000'u8 - doAssert rotateRightBits(0b0000_0001'u8, 2) == 0b0100_0000'u8 - doAssert rotateRightBits(0b0100_0001'u8, 1) == 0b1010_0000'u8 - doAssert rotateRightBits(0b0100_0001'u8, 2) == 0b0101_0000'u8 + doAssert rotateRightBits(0b0110_1001'u8, 4) == 0b1001_0110'u8 - let amount = amount and 7 - result = (value shr amount) or (value shl ( (-amount) and 7)) + when nimvm: + rotr(value, shift.int32) + else: + when useBuiltinsRotate: + builtin_rotr8(value.cuchar, shiftTypeTo(value, shift)).uint8 + else: + rotr(value, shift.int32) -proc rotateRightBits*(value: uint16; - amount: range[0..16]): uint16 {.inline, noSideEffect.} = +func rotateRightBits*(value: uint16, shift: range[0..16]): uint16 {.inline.} = ## Right-rotate bits in a 16-bits value. - ## - ## See also: - ## * `rotateRightBits proc <#rotateRightBits,uint8,range[]>`_ - let amount = amount and 15 - result = (value shr amount) or (value shl ( (-amount) and 15)) + runnableExamples: + doAssert rotateRightBits(0b00111100_11000011'u16, 8) == + 0b11000011_00111100'u16 -proc rotateRightBits*(value: uint32; - amount: range[0..32]): uint32 {.inline, noSideEffect.} = + when nimvm: + rotr(value, shift.int32) + else: + when useBuiltinsRotate: + builtin_rotr16(value.cushort, shiftTypeTo(value, shift)).uint16 + else: + rotr(value, shift.int32) + +func rotateRightBits*(value: uint32, shift: range[0..32]): uint32 {.inline.} = ## Right-rotate bits in a 32-bits value. - ## - ## See also: - ## * `rotateRightBits proc <#rotateRightBits,uint8,range[]>`_ - let amount = amount and 31 - result = (value shr amount) or (value shl ( (-amount) and 31)) + runnableExamples: + doAssert rotateRightBits(0b0000111111110000_1111000000001111'u32, 16) == + 0b1111000000001111_0000111111110000'u32 -proc rotateRightBits*(value: uint64; - amount: range[0..64]): uint64 {.inline, noSideEffect.} = + when nimvm: + rotr(value, shift.int32) + else: + when useBuiltinsRotate: + builtin_rotr32(value.cuint, shiftTypeTo(value, shift)).uint32 + else: + rotr(value, shift.int32) + +func rotateRightBits*(value: uint64, shift: range[0..64]): uint64 {.inline.} = ## Right-rotate bits in a 64-bits value. - ## - ## See also: - ## * `rotateRightBits proc <#rotateRightBits,uint8,range[]>`_ - let amount = amount and 63 - result = (value shr amount) or (value shl ( (-amount) and 63)) + runnableExamples: + doAssert rotateRightBits(0b00000000111111111111111100000000_11111111000000000000000011111111'u64, 32) == + 0b11111111000000000000000011111111_00000000111111111111111100000000'u64 -proc repeatBits[T: SomeUnsignedInt](x: SomeUnsignedInt; retType: type[T]): T {. - noSideEffect.} = + when nimvm: + rotr(value, shift.int32) + else: + when useBuiltinsRotate and defined(amd64): + builtin_rotr64(value.culonglong, shiftTypeTo(value, shift)).uint64 + else: + rotr(value, shift.int32) + +func repeatBits[T: SomeUnsignedInt](x: SomeUnsignedInt; retType: type[T]): T = result = x var i = 1 while i != (sizeof(T) div sizeof(x)): result = (result shl (sizeof(x)*8*i)) or result i *= 2 -proc reverseBits*[T: SomeUnsignedInt](x: T): T {.noSideEffect.} = +func reverseBits*[T: SomeUnsignedInt](x: T): T = ## 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 9b3b67104b..08f5208d29 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -20,12 +20,14 @@ when defined(windows): import winlean from os import absolutePath else: - import os, osproc + import os + when not defined(osx): + import 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. + ## `"open"` on OSX, MacOS and Windows, `"xdg-open"` on Linux, BSD, etc. proc prepare(s: string): string = if s.contains("://"): @@ -43,9 +45,9 @@ proc openDefaultBrowserImpl(url: string) = else: var u = quoteShell(prepare url) if execShellCmd(osOpenCmd & " " & u) == 0: return - for b in getEnv("BROWSER").string.split(PathSep): + for b in getEnv("BROWSER").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: @@ -55,9 +57,9 @@ 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 + ## 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. @@ -71,9 +73,9 @@ 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 + ## 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. diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index cb64a3b1ba..fd5089dbb4 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -11,7 +11,7 @@ ## ## .. code-block:: Nim ## -## import strtabs, cgi +## import std/[strtabs, cgi] ## ## # Fill the values when debugging: ## when debug: @@ -29,10 +29,9 @@ ## writeLine(stdout, "your password: " & myData["password"]) ## writeLine(stdout, "") -import strutils, os, strtabs, cookies, uri +import std/[strutils, os, strtabs, cookies, uri] export uri.encodeUrl, uri.decodeUrl -import std/private/decode_helpers proc addXmlChar(dest: var string, c: char) {.inline.} = case c @@ -44,34 +43,31 @@ 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 an ECgi exception with message `msg`. - var e: ref CgiError - new(e) - e.msg = msg - raise e + ## Raises a `CgiError` exception with message `msg`. + raise newException(CgiError, msg) proc getEncodedData(allowedMethods: set[RequestMethod]): string = - case getEnv("REQUEST_METHOD").string + case getEnv("REQUEST_METHOD") of "POST": if methodPost notin allowedMethods: cgiError("'REQUEST_METHOD' 'POST' is not supported") - var L = parseInt(getEnv("CONTENT_LENGTH").string) + var L = parseInt(getEnv("CONTENT_LENGTH")) if L == 0: return "" result = newString(L) @@ -80,200 +76,177 @@ proc getEncodedData(allowedMethods: set[RequestMethod]): string = of "GET": if methodGet notin allowedMethods: cgiError("'REQUEST_METHOD' 'GET' is not supported") - result = getEnv("QUERY_STRING").string + result = getEnv("QUERY_STRING") else: if methodNone notin allowedMethods: cgiError("'REQUEST_METHOD' must be 'POST' or 'GET'") -iterator decodeData*(data: string): tuple[key, value: TaintedString] = +iterator decodeData*(data: string): tuple[key, value: string] = ## Reads and decodes CGI data and yields the (name, value) pairs the ## data consists of. - proc parseData(data: string, i: int, field: var string): int = - result = i - while result < data.len: - case data[result] - of '%': add(field, decodePercent(data, result)) - of '+': add(field, ' ') - of '=', '&': 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 '=' - i = parseData(data, i, value) - yield (name.TaintedString, value.TaintedString) - if i < data.len: - if data[i] == '&': inc(i) - else: cgiError("'&' expected") + for (key, value) in uri.decodeQuery(data): + yield (key, value) iterator decodeData*(allowedMethods: set[RequestMethod] = - {methodNone, methodPost, methodGet}): tuple[key, value: TaintedString] = + {methodNone, methodPost, methodGet}): tuple[key, value: string] = ## 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, an `ECgi` exception is raised. + ## `allowedMethods` set, a `CgiError` exception is raised. let data = getEncodedData(allowedMethods) - for key, value in decodeData(data): + for (key, value) in uri.decodeQuery(data): yield (key, value) proc readData*(allowedMethods: set[RequestMethod] = {methodNone, methodPost, methodGet}): StringTableRef = - ## Read CGI data. If the client does not use a method listed in the - ## `allowedMethods` set, an `ECgi` exception is raised. + ## Reads CGI data. If the client does not use a method listed in the + ## `allowedMethods` set, a `CgiError` exception is raised. result = newStringTable() for name, value in decodeData(allowedMethods): - result[name.string] = value.string + result[name] = value proc readData*(data: string): StringTableRef = - ## Read CGI data from a string. + ## Reads CGI data from a string. result = newStringTable() for name, value in decodeData(data): - result[name.string] = value.string + result[name] = value proc validateData*(data: StringTableRef, validKeys: varargs[string]) = - ## validates data; raises `ECgi` if this fails. This checks that each variable + ## Validates data; raises `CgiError` 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").string + ## Returns contents of the `CONTENT_LENGTH` environment variable. + return getEnv("CONTENT_LENGTH") proc getContentType*(): string = - ## returns contents of the ``CONTENT_TYPE`` environment variable - return getEnv("CONTENT_Type").string + ## Returns contents of the `CONTENT_TYPE` environment variable. + return getEnv("CONTENT_Type") proc getDocumentRoot*(): string = - ## returns contents of the ``DOCUMENT_ROOT`` environment variable - return getEnv("DOCUMENT_ROOT").string + ## Returns contents of the `DOCUMENT_ROOT` environment variable. + return getEnv("DOCUMENT_ROOT") proc getGatewayInterface*(): string = - ## returns contents of the ``GATEWAY_INTERFACE`` environment variable - return getEnv("GATEWAY_INTERFACE").string + ## Returns contents of the `GATEWAY_INTERFACE` environment variable. + return getEnv("GATEWAY_INTERFACE") proc getHttpAccept*(): string = - ## returns contents of the ``HTTP_ACCEPT`` environment variable - return getEnv("HTTP_ACCEPT").string + ## Returns contents of the `HTTP_ACCEPT` environment variable. + return getEnv("HTTP_ACCEPT") proc getHttpAcceptCharset*(): string = - ## returns contents of the ``HTTP_ACCEPT_CHARSET`` environment variable - return getEnv("HTTP_ACCEPT_CHARSET").string + ## Returns contents of the `HTTP_ACCEPT_CHARSET` environment variable. + return getEnv("HTTP_ACCEPT_CHARSET") proc getHttpAcceptEncoding*(): string = - ## returns contents of the ``HTTP_ACCEPT_ENCODING`` environment variable - return getEnv("HTTP_ACCEPT_ENCODING").string + ## Returns contents of the `HTTP_ACCEPT_ENCODING` environment variable. + return getEnv("HTTP_ACCEPT_ENCODING") proc getHttpAcceptLanguage*(): string = - ## returns contents of the ``HTTP_ACCEPT_LANGUAGE`` environment variable - return getEnv("HTTP_ACCEPT_LANGUAGE").string + ## Returns contents of the `HTTP_ACCEPT_LANGUAGE` environment variable. + return getEnv("HTTP_ACCEPT_LANGUAGE") proc getHttpConnection*(): string = - ## returns contents of the ``HTTP_CONNECTION`` environment variable - return getEnv("HTTP_CONNECTION").string + ## Returns contents of the `HTTP_CONNECTION` environment variable. + return getEnv("HTTP_CONNECTION") proc getHttpCookie*(): string = - ## returns contents of the ``HTTP_COOKIE`` environment variable - return getEnv("HTTP_COOKIE").string + ## Returns contents of the `HTTP_COOKIE` environment variable. + return getEnv("HTTP_COOKIE") proc getHttpHost*(): string = - ## returns contents of the ``HTTP_HOST`` environment variable - return getEnv("HTTP_HOST").string + ## Returns contents of the `HTTP_HOST` environment variable. + return getEnv("HTTP_HOST") proc getHttpReferer*(): string = - ## returns contents of the ``HTTP_REFERER`` environment variable - return getEnv("HTTP_REFERER").string + ## Returns contents of the `HTTP_REFERER` environment variable. + return getEnv("HTTP_REFERER") proc getHttpUserAgent*(): string = - ## returns contents of the ``HTTP_USER_AGENT`` environment variable - return getEnv("HTTP_USER_AGENT").string + ## Returns contents of the `HTTP_USER_AGENT` environment variable. + return getEnv("HTTP_USER_AGENT") proc getPathInfo*(): string = - ## returns contents of the ``PATH_INFO`` environment variable - return getEnv("PATH_INFO").string + ## Returns contents of the `PATH_INFO` environment variable. + return getEnv("PATH_INFO") proc getPathTranslated*(): string = - ## returns contents of the ``PATH_TRANSLATED`` environment variable - return getEnv("PATH_TRANSLATED").string + ## Returns contents of the `PATH_TRANSLATED` environment variable. + return getEnv("PATH_TRANSLATED") proc getQueryString*(): string = - ## returns contents of the ``QUERY_STRING`` environment variable - return getEnv("QUERY_STRING").string + ## Returns contents of the `QUERY_STRING` environment variable. + return getEnv("QUERY_STRING") proc getRemoteAddr*(): string = - ## returns contents of the ``REMOTE_ADDR`` environment variable - return getEnv("REMOTE_ADDR").string + ## Returns contents of the `REMOTE_ADDR` environment variable. + return getEnv("REMOTE_ADDR") proc getRemoteHost*(): string = - ## returns contents of the ``REMOTE_HOST`` environment variable - return getEnv("REMOTE_HOST").string + ## Returns contents of the `REMOTE_HOST` environment variable. + return getEnv("REMOTE_HOST") proc getRemoteIdent*(): string = - ## returns contents of the ``REMOTE_IDENT`` environment variable - return getEnv("REMOTE_IDENT").string + ## Returns contents of the `REMOTE_IDENT` environment variable. + return getEnv("REMOTE_IDENT") proc getRemotePort*(): string = - ## returns contents of the ``REMOTE_PORT`` environment variable - return getEnv("REMOTE_PORT").string + ## Returns contents of the `REMOTE_PORT` environment variable. + return getEnv("REMOTE_PORT") proc getRemoteUser*(): string = - ## returns contents of the ``REMOTE_USER`` environment variable - return getEnv("REMOTE_USER").string + ## Returns contents of the `REMOTE_USER` environment variable. + return getEnv("REMOTE_USER") proc getRequestMethod*(): string = - ## returns contents of the ``REQUEST_METHOD`` environment variable - return getEnv("REQUEST_METHOD").string + ## Returns contents of the `REQUEST_METHOD` environment variable. + return getEnv("REQUEST_METHOD") proc getRequestURI*(): string = - ## returns contents of the ``REQUEST_URI`` environment variable - return getEnv("REQUEST_URI").string + ## Returns contents of the `REQUEST_URI` environment variable. + return getEnv("REQUEST_URI") proc getScriptFilename*(): string = - ## returns contents of the ``SCRIPT_FILENAME`` environment variable - return getEnv("SCRIPT_FILENAME").string + ## Returns contents of the `SCRIPT_FILENAME` environment variable. + return getEnv("SCRIPT_FILENAME") proc getScriptName*(): string = - ## returns contents of the ``SCRIPT_NAME`` environment variable - return getEnv("SCRIPT_NAME").string + ## Returns contents of the `SCRIPT_NAME` environment variable. + return getEnv("SCRIPT_NAME") proc getServerAddr*(): string = - ## returns contents of the ``SERVER_ADDR`` environment variable - return getEnv("SERVER_ADDR").string + ## Returns contents of the `SERVER_ADDR` environment variable. + return getEnv("SERVER_ADDR") proc getServerAdmin*(): string = - ## returns contents of the ``SERVER_ADMIN`` environment variable - return getEnv("SERVER_ADMIN").string + ## Returns contents of the `SERVER_ADMIN` environment variable. + return getEnv("SERVER_ADMIN") proc getServerName*(): string = - ## returns contents of the ``SERVER_NAME`` environment variable - return getEnv("SERVER_NAME").string + ## Returns contents of the `SERVER_NAME` environment variable. + return getEnv("SERVER_NAME") proc getServerPort*(): string = - ## returns contents of the ``SERVER_PORT`` environment variable - return getEnv("SERVER_PORT").string + ## Returns contents of the `SERVER_PORT` environment variable. + return getEnv("SERVER_PORT") proc getServerProtocol*(): string = - ## returns contents of the ``SERVER_PROTOCOL`` environment variable - return getEnv("SERVER_PROTOCOL").string + ## Returns contents of the `SERVER_PROTOCOL` environment variable. + return getEnv("SERVER_PROTOCOL") proc getServerSignature*(): string = - ## returns contents of the ``SERVER_SIGNATURE`` environment variable - return getEnv("SERVER_SIGNATURE").string + ## Returns contents of the `SERVER_SIGNATURE` environment variable. + return getEnv("SERVER_SIGNATURE") proc getServerSoftware*(): string = - ## returns contents of the ``SERVER_SOFTWARE`` environment variable - return getEnv("SERVER_SOFTWARE").string + ## Returns contents of the `SERVER_SOFTWARE` environment variable. + return getEnv("SERVER_SOFTWARE") 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: ## @@ -291,7 +264,7 @@ proc setTestData*(keysvalues: varargs[string]) = putEnv("QUERY_STRING", query) proc writeContentType*() = - ## call this before starting to send your HTML data to `stdout`. This + ## Calls this before starting to send your HTML data to `stdout`. This ## implements this part of the CGI protocol: ## ## .. code-block:: Nim @@ -328,10 +301,10 @@ proc setCookie*(name, value: string) = var gcookies {.threadvar.}: StringTableRef -proc getCookie*(name: string): TaintedString = +proc getCookie*(name: string): string = ## Gets a cookie. If no cookie of `name` exists, "" is returned. if gcookies == nil: gcookies = parseCookies(getHttpCookie()) - result = TaintedString(gcookies.getOrDefault(name)) + result = 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 695f446460..e129849954 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -8,10 +8,32 @@ # ## 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. +## 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). ## (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 type @@ -28,17 +50,15 @@ 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: - var c: CritBitTree[void] - incl(c, "key1") - incl(c, "key2") + let c = ["key1", "key2"].toCritBitTree doAssert c.len == 2 result = c.count @@ -144,7 +164,7 @@ proc excl*[T](c: var CritBitTree[T], key: string) = ## Removes `key` (and its associated value) from the set `c`. ## If the `key` does not exist, nothing happens. ## - ## See also: + ## **See also:** ## * `incl proc <#incl,CritBitTree[void],string>`_ ## * `incl proc <#incl,CritBitTree[T],string,T>`_ runnableExamples: @@ -157,9 +177,9 @@ proc excl*[T](c: var CritBitTree[T], key: string) = 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. + ## does exist, `c.excl(key)` is performed. ## - ## See also: + ## **See also:** ## * `excl proc <#excl,CritBitTree[T],string>`_ ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[T],string,T>`_ ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[void],string>`_ @@ -178,10 +198,10 @@ proc missingOrExcl*[T](c: var CritBitTree[T], key: string): bool = result = c.count == oldCount proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: T): bool = - ## Returns true if `c` contains the given `key`. If the key does not exist - ## ``c[key] = val`` is performed. + ## Returns true if `c` contains the given `key`. If the key does not exist, + ## `c[key] = val` is performed. ## - ## See also: + ## **See also:** ## * `incl proc <#incl,CritBitTree[void],string>`_ ## * `incl proc <#incl,CritBitTree[T],string,T>`_ ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[void],string>`_ @@ -204,10 +224,10 @@ proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: 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 if `c` contains the given `key`. If the key does not exist, ## it is inserted into `c`. ## - ## See also: + ## **See also:** ## * `incl proc <#incl,CritBitTree[void],string>`_ ## * `incl proc <#incl,CritBitTree[T],string,T>`_ ## * `containsOrIncl proc <#containsOrIncl,CritBitTree[T],string,T>`_ @@ -240,7 +260,7 @@ proc inc*(c: var CritBitTree[int]; key: string, val: int = 1) = proc incl*(c: var CritBitTree[void], key: string) = ## Includes `key` in `c`. ## - ## See also: + ## **See also:** ## * `excl proc <#excl,CritBitTree[T],string>`_ ## * `incl proc <#incl,CritBitTree[T],string,T>`_ runnableExamples: @@ -253,7 +273,7 @@ proc incl*(c: var CritBitTree[void], key: string) = proc incl*[T](c: var CritBitTree[T], key: string, val: T) = ## Inserts `key` with value `val` into `c`. ## - ## See also: + ## **See also:** ## * `excl proc <#excl,CritBitTree[T],string>`_ ## * `incl proc <#incl,CritBitTree[void],string>`_ runnableExamples: @@ -265,16 +285,11 @@ proc incl*[T](c: var CritBitTree[T], key: string, val: T) = n.val = val proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) = - ## Puts a (key, value)-pair into `t`. + ## Alias for `incl <#incl,CritBitTree[T],string,T>`_. ## - ## See also: + ## **See also:** ## * `[] proc <#[],CritBitTree[T],string>`_ ## * `[] proc <#[],CritBitTree[T],string_2>`_ - runnableExamples: - var c: CritBitTree[int] - c["key"] = 42 - doAssert c["key"] == 42 - var n = rawInsert(c, key) n.val = val @@ -286,20 +301,20 @@ template get[T](c: CritBitTree[T], key: string): T = n.val func `[]`*[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 + ## 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: + ## **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. + ## Retrieves the value at `c[key]`. The value can be modified. + ## If `key` is not in `t`, the `KeyError` exception is raised. ## - ## See also: + ## **See also:** ## * `[] proc <#[],CritBitTree[T],string>`_ ## * `[]= proc <#[]=,CritBitTree[T],string,T>`_ get(c, key) @@ -320,27 +335,24 @@ iterator leaves[T](n: Node[T]): Node[T] = iterator keys*[T](c: CritBitTree[T]): string = ## Yields all keys in lexicographical order. runnableExamples: - var c: CritBitTree[int] - c["key1"] = 1 - c["key2"] = 2 - var keys: seq[string] - for key in c.keys: - keys.add(key) - doAssert keys == @["key1", "key2"] + from std/sequtils import toSeq + + let c = {"key1": 1, "key2": 2}.toCritBitTree + doAssert toSeq(c.keys) == @["key1", "key2"] for x in leaves(c.root): yield x.key 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: - var c: CritBitTree[int] - c["key1"] = 1 - c["key2"] = 2 - var vals: seq[int] - for val in c.values: - vals.add(val) - doAssert vals == @[1, 2] + 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 @@ -348,45 +360,37 @@ iterator mvalues*[T](c: var CritBitTree[T]): var T = ## Yields all values of `c` in the lexicographical order of the ## corresponding keys. The values can be modified. ## - ## See also: + ## **See also:** ## * `values iterator <#values.i,CritBitTree[T]>`_ for x in leaves(c.root): yield x.val iterator items*[T](c: CritBitTree[T]): string = - ## Yields all keys in lexicographical order. - runnableExamples: - var c: CritBitTree[int] - c["key1"] = 1 - c["key2"] = 2 - var keys: seq[string] - for key in c.items: - keys.add(key) - doAssert keys == @["key1", "key2"] - + ## Alias for `keys <#keys.i,CritBitTree[T]>`_. 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`. + ## Yields all `(key, value)`-pairs of `c` in the lexicographical order of the + ## corresponding keys. + ## + ## **See also:** + ## * `mpairs iterator <#mpairs.i,CritBitTree[T]>`_ runnableExamples: - var c: CritBitTree[int] - c["key1"] = 1 - c["key2"] = 2 - var ps: seq[tuple[key: string, val: int]] - for p in c.pairs: - ps.add(p) - doAssert ps == @[(key: "key1", val: 1), (key: "key2", val: 2)] + from std/sequtils import toSeq + + let c = {"key1": 1, "key2": 2}.toCritBitTree + doAssert toSeq(c.pairs) == @[(key: "key1", val: 1), (key: "key2", val: 2)] 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`. The yielded values can be modified. + ## Yields all `(key, value)`-pairs of `c` in the lexicographical order of the + ## corresponding keys. The yielded values can be modified. ## - ## See also: + ## **See also:** ## * `pairs iterator <#pairs.i,CritBitTree[T]>`_ for x in leaves(c.root): yield (x.key, x.val) -proc allprefixedAux[T](c: CritBitTree[T], key: string; - longestMatch: bool): Node[T] = +proc allprefixedAux[T](c: CritBitTree[T], key: string): Node[T] = var p = c.root var top = p if p != nil: @@ -396,100 +400,83 @@ proc allprefixedAux[T](c: CritBitTree[T], key: string; let dir = (1 + (ch.ord or p.otherBits.ord)) shr 8 p = p.child[dir] if q.byte < key.len: top = p - if not longestMatch: - for i in 0 ..< key.len: - if i >= p.key.len or p.key[i] != key[i]: return + for i in 0 ..< key.len: + if i >= p.key.len or p.key[i] != key[i]: return result = top -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. - runnableExamples: - var c: CritBitTree[int] - c["key1"] = 42 - c["key2"] = 43 - var keys: seq[string] - for key in c.itemsWithPrefix("key"): - keys.add(key) - doAssert keys == @["key1", "key2"] - - let top = allprefixedAux(c, prefix, longestMatch) - for x in leaves(top): yield x.key - -iterator keysWithPrefix*[T](c: CritBitTree[T], prefix: string; - longestMatch = false): string = +iterator keysWithPrefix*[T](c: CritBitTree[T], prefix: string): string = ## Yields all keys starting with `prefix`. runnableExamples: - var c: CritBitTree[int] - c["key1"] = 42 - c["key2"] = 43 - var keys: seq[string] - for key in c.keysWithPrefix("key"): - keys.add(key) - doAssert keys == @["key1", "key2"] + from std/sequtils import toSeq - let top = allprefixedAux(c, prefix, longestMatch) + let c = {"key1": 42, "key2": 43}.toCritBitTree + doAssert toSeq(c.keysWithPrefix("key")) == @["key1", "key2"] + + let top = allprefixedAux(c, prefix) for x in leaves(top): yield x.key -iterator valuesWithPrefix*[T](c: CritBitTree[T], prefix: string; - longestMatch = false): T = +iterator valuesWithPrefix*[T](c: CritBitTree[T], prefix: string): T = ## Yields all values of `c` starting with `prefix` of the ## corresponding keys. + ## + ## **See also:** + ## * `mvaluesWithPrefix iterator <#mvaluesWithPrefix.i,CritBitTree[T],string>`_ runnableExamples: - var c: CritBitTree[int] - c["key1"] = 42 - c["key2"] = 43 - var vals: seq[int] - for val in c.valuesWithPrefix("key"): - vals.add(val) - doAssert vals == @[42, 43] + from std/sequtils import toSeq - let top = allprefixedAux(c, prefix, longestMatch) + let c = {"key1": 42, "key2": 43}.toCritBitTree + doAssert toSeq(c.valuesWithPrefix("key")) == @[42, 43] + + let top = allprefixedAux(c, prefix) for x in leaves(top): yield x.val -iterator mvaluesWithPrefix*[T](c: var CritBitTree[T], prefix: string; - longestMatch = false): var T = +iterator mvaluesWithPrefix*[T](c: var CritBitTree[T], prefix: string): var T = ## Yields all values of `c` starting with `prefix` of the ## corresponding keys. The values can be modified. ## - ## See also: + ## **See also:** ## * `valuesWithPrefix iterator <#valuesWithPrefix.i,CritBitTree[T],string>`_ - let top = allprefixedAux(c, prefix, longestMatch) + let top = allprefixedAux(c, prefix) for x in leaves(top): yield x.val -iterator pairsWithPrefix*[T](c: CritBitTree[T], - prefix: string; - longestMatch = false): tuple[key: string, val: T] = - ## Yields all (key, value)-pairs of `c` starting with `prefix`. - runnableExamples: - var c: CritBitTree[int] - c["key1"] = 42 - c["key2"] = 43 - var ps: seq[tuple[key: string, val: int]] - for p in c.pairsWithPrefix("key"): - ps.add(p) - doAssert ps == @[(key: "key1", val: 42), (key: "key2", val: 43)] +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 - let top = allprefixedAux(c, prefix, longestMatch) +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) for x in leaves(top): yield (x.key, x.val) iterator mpairsWithPrefix*[T](c: var CritBitTree[T], - prefix: string; - longestMatch = false): tuple[key: string, val: var T] = + prefix: string): tuple[key: string, val: var T] = ## Yields all (key, value)-pairs of `c` starting with `prefix`. ## The yielded values can be modified. ## - ## See also: + ## **See also:** ## * `pairsWithPrefix iterator <#pairsWithPrefix.i,CritBitTree[T],string>`_ - let top = allprefixedAux(c, prefix, longestMatch) + let top = allprefixedAux(c, prefix) for x in leaves(top): yield (x.key, x.val) func `$`*[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}``, ``{}``. + ## 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"}""" + if c.len == 0: when T is void: result = "{}" @@ -516,7 +503,7 @@ func `$`*[T](c: CritBitTree[T]): string = result.add("}") func commonPrefixLen*[T](c: CritBitTree[T]): int {.inline, since((1, 3)).} = - ## Returns longest common prefix length of all keys of `c`. + ## Returns the length of the longest common prefix of all keys in `c`. ## If `c` is empty, returns 0. runnableExamples: var c: CritBitTree[void] @@ -531,39 +518,17 @@ func commonPrefixLen*[T](c: CritBitTree[T]): int {.inline, since((1, 3)).} = else: c.root.byte else: 0 -func toCritBitTree*[A, B](pairs: openArray[(A, B)]): CritBitTree[A] {.since: (1, 3).} = +proc toCritBitTree*[T](pairs: 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] + for item in pairs: result.incl item[0], item[1] -func toCritBitTree*[T](items: openArray[T]): CritBitTree[void] {.since: (1, 3).} = +proc toCritBitTree*(items: 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] + for item in items: result.incl item - - -runnableExamples: - static: - block: - var critbitAsSet: CritBitTree[void] - doAssert critbitAsSet.len == 0 - incl critbitAsSet, "kitten" - doAssert critbitAsSet.len == 1 - incl critbitAsSet, "puppy" - doAssert critbitAsSet.len == 2 - incl critbitAsSet, "kitten" - doAssert critbitAsSet.len == 2 - incl critbitAsSet, "" - doAssert critbitAsSet.len == 3 - block: - var critbitAsDict: CritBitTree[int] - critbitAsDict["key"] = 42 - doAssert critbitAsDict["key"] == 42 - critbitAsDict["key"] = 0 - doAssert critbitAsDict["key"] == 0 - critbitAsDict["key"] = -int.high - doAssert critbitAsDict["key"] == -int.high - critbitAsDict["key"] = int.high - doAssert critbitAsDict["key"] == int.high diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index f6d0f945e7..c8bbb1cc67 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -7,25 +7,24 @@ # distribution, for details about the copyright. # -## Implementation of a `deque`:idx: (double-ended queue). -## The underlying implementation uses a ``seq``. +## An implementation of a `deque`:idx: (double-ended queue). +## The underlying implementation uses a `seq`. ## -## None of the procs that get an individual value from the deque can be used +## Note that none of the procs that get an individual value from the deque should be used ## on an empty deque. -## If compiled with `boundChecks` option, those procs will raise an `IndexDefect` +## 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 may return garbage or crash the program. +## disable those checks and then the procs 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 = initDeque[int]() + var a = [10, 20, 30, 40].toDeque - doAssertRaises(IndexDefect, echo a[0]) + doAssertRaises(IndexDefect, echo a[4]) - for i in 1 .. 5: - a.addLast(10*i) + a.addLast(50) assert $a == "[10, 20, 30, 40, 50]" assert a.peekFirst == 10 @@ -44,9 +43,10 @@ runnableExamples: a.shrink(fromFirst = 1, fromLast = 2) assert $a == "[22, 11, 20]" -## **See also:** +## See also +## ======== ## * `lists module `_ for singly and doubly linked lists and rings -## * `channels module `_ for inter-thread communication +## * `channels module `_ for inter-thread communication import std/private/since @@ -54,9 +54,10 @@ 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 `initDeque proc <#initDeque,int>`_. + ## To initialize an empty deque, + ## use the `initDeque proc <#initDeque,int>`_. data: seq[T] head, tail, count, mask: int @@ -65,7 +66,7 @@ const template initImpl(result: typed, initialSize: int) = let correctSize = nextPowerOfTwo(initialSize) - result.mask = correctSize-1 + result.mask = correctSize - 1 newSeq(result.data, correctSize) template checkIfInitialized(deq: typed) = @@ -73,27 +74,27 @@ template checkIfInitialized(deq: typed) = if deq.mask == 0: initImpl(deq, defaultInitialSize) -proc initDeque*[T](initialSize: int = 4): Deque[T] = +proc initDeque*[T](initialSize: int = defaultInitialSize): Deque[T] = ## Creates a new empty deque. ## ## Optionally, the initial capacity can be reserved via `initialSize` - ## as a performance optimization. + ## as a performance optimization + ## (default: `defaultInitialSize <#defaultInitialSize>`_). ## The length of a newly created deque will still be 0. ## - ## See also: + ## **See also:** ## * `toDeque proc <#toDeque,openArray[T]>`_ result.initImpl(initialSize) 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: + ## **See also:** ## * `initDeque proc <#initDeque,int>`_ runnableExamples: - var a = toDeque([7, 8, 9]) + let a = toDeque([7, 8, 9]) assert len(a) == 3 - assert a.popFirst == 7 - assert len(a) == 2 + assert $a == "[7, 8, 9]" result.initImpl(x.len) for item in items(x): @@ -120,11 +121,9 @@ template xBoundsCheck(deq, i) = "Out of bounds: " & $i & " < 0") proc `[]`*[T](deq: Deque[T], i: Natural): T {.inline.} = - ## Accesses the i-th element of `deq`. + ## Accesses the `i`-th element of `deq`. runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + let a = [10, 20, 30, 40, 50].toDeque assert a[0] == 10 assert a[3] == 40 doAssertRaises(IndexDefect, echo a[8]) @@ -133,25 +132,20 @@ proc `[]`*[T](deq: Deque[T], i: Natural): T {.inline.} = 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 return a mutable + ## Accesses the `i`-th element of `deq` and returns a mutable ## reference to it. runnableExamples: - 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]) + var a = [10, 20, 30, 40, 50].toDeque + inc(a[0]) + assert a[0] == 11 xBoundsCheck(deq, i) return deq.data[(deq.head + i) and deq.mask] proc `[]=`*[T](deq: var Deque[T], i: Natural, val: T) {.inline.} = - ## Changes the i-th element of `deq`. + ## Sets the `i`-th element of `deq` to `val`. runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + var a = [10, 20, 30, 40, 50].toDeque a[0] = 99 a[3] = 66 assert $a == "[99, 20, 30, 66, 50]" @@ -161,13 +155,11 @@ proc `[]=`*[T](deq: var Deque[T], i: Natural, val: T) {.inline.} = deq.data[(deq.head + i) and deq.mask] = val proc `[]`*[T](deq: Deque[T], i: BackwardsIndex): T {.inline.} = - ## Accesses the backwards indexed i-th element. + ## Accesses the backwards indexed `i`-th element. ## ## `deq[^1]` is the last element. runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + let a = [10, 20, 30, 40, 50].toDeque assert a[^1] == 50 assert a[^4] == 20 doAssertRaises(IndexDefect, echo a[^9]) @@ -176,28 +168,24 @@ proc `[]`*[T](deq: Deque[T], i: BackwardsIndex): T {.inline.} = return deq[deq.len - int(i)] proc `[]`*[T](deq: var Deque[T], i: BackwardsIndex): var T {.inline.} = - ## Accesses the backwards indexed i-th element. + ## Accesses the backwards indexed `i`-th element and returns a mutable + ## reference to it. ## ## `deq[^1]` is the last element. runnableExamples: - 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]) + var a = [10, 20, 30, 40, 50].toDeque + inc(a[^1]) + assert a[^1] == 51 xBoundsCheck(deq, deq.len - int(i)) return deq[deq.len - int(i)] proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: T) {.inline.} = - ## Changes the backwards indexed i-th element. + ## Sets the backwards indexed `i`-th element of `deq` to `x`. ## ## `deq[^1]` is the last element. runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + var a = [10, 20, 30, 40, 50].toDeque a[^1] = 99 a[^3] = 77 assert $a == "[10, 20, 77, 40, 99]" @@ -208,14 +196,15 @@ proc `[]=`*[T](deq: var Deque[T], i: BackwardsIndex, x: T) {.inline.} = iterator items*[T](deq: Deque[T]): T = ## Yields every element of `deq`. + ## + ## **See also:** + ## * `mitems iterator <#mitems,Deque[T]>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 3: - a.addLast(10*i) - from sugar import collect - doAssert collect(for x in a: x) == [10, 20, 30] - # same as above: - doAssert collect(for x in items(a): x) == [10, 20, 30] + 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] @@ -223,13 +212,14 @@ iterator items*[T](deq: Deque[T]): T = iterator mitems*[T](deq: var Deque[T]): var T = ## Yields every element of `deq`, which can be modified. + ## + ## **See also:** + ## * `items iterator <#items,Deque[T]>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + var a = [10, 20, 30, 40, 50].toDeque 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 @@ -238,13 +228,13 @@ 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) of `deq`. + ## Yields every `(position, value)`-pair of `deq`. runnableExamples: - var a = initDeque[int]() - for i in 1 .. 3: - a.addLast(10*i) - from sugar import collect - doAssert collect(for k, v in pairs(a): (k, v)) == @[(0, 10), (1, 20), (2, 30)] + from std/sequtils import toSeq + + let a = [10, 20, 30].toDeque + assert toSeq(a.pairs) == @[(0, 10), (1, 20), (2, 30)] + var i = deq.head for c in 0 ..< deq.count: yield (c, deq.data[i]) @@ -253,13 +243,14 @@ iterator pairs*[T](deq: Deque[T]): tuple[key: int, val: T] = proc contains*[T](deq: Deque[T], item: T): bool {.inline.} = ## Returns 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``. + ## Usually used via the `in` operator. + ## It is the equivalent of `deq.find(item) >= 0`. runnableExamples: - var q = [7, 9].toDeque + let q = [7, 9].toDeque assert 7 in q - assert q.contains 7 + assert q.contains(7) assert 8 notin q + for e in deq: if e == item: return true return false @@ -280,18 +271,14 @@ proc expandIfNeeded[T](deq: var Deque[T]) = deq.head = 0 proc addFirst*[T](deq: var Deque[T], item: T) = - ## Adds an `item` to the beginning of the `deq`. + ## Adds an `item` to the beginning of `deq`. ## - ## See also: + ## **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) @@ -300,18 +287,14 @@ proc addFirst*[T](deq: var Deque[T], item: T) = deq.data[deq.head] = item proc addLast*[T](deq: var Deque[T], item: T) = - ## Adds an `item` to the end of the `deq`. + ## Adds an `item` to the end of `deq`. ## - ## See also: + ## **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) @@ -322,16 +305,11 @@ proc addLast*[T](deq: var Deque[T], item: T) = proc peekFirst*[T](deq: Deque[T]): T {.inline.} = ## Returns the first element of `deq`, but does not remove it from the deque. ## - ## See also: - ## * `addFirst proc <#addFirst,Deque[T],T>`_ - ## * `addLast proc <#addLast,Deque[T],T>`_ + ## **See also:** + ## * `peekFirst proc <#peekFirst,Deque[T]_2>`_ which returns a mutable reference ## * `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) + let a = [10, 20, 30, 40, 50].toDeque assert $a == "[10, 20, 30, 40, 50]" assert a.peekFirst == 10 assert len(a) == 5 @@ -342,16 +320,11 @@ proc peekFirst*[T](deq: Deque[T]): 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: - ## * `addFirst proc <#addFirst,Deque[T],T>`_ - ## * `addLast proc <#addLast,Deque[T],T>`_ + ## **See also:** + ## * `peekLast proc <#peekLast,Deque[T]_2>`_ which returns a mutable reference ## * `peekFirst proc <#peekFirst,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) + let a = [10, 20, 30, 40, 50].toDeque assert $a == "[10, 20, 30, 40, 50]" assert a.peekLast == 50 assert len(a) == 5 @@ -360,41 +333,31 @@ proc peekLast*[T](deq: Deque[T]): T {.inline.} = result = deq.data[(deq.tail - 1) and deq.mask] proc peekFirst*[T](deq: var Deque[T]): var T {.inline, since: (1, 3).} = - ## Returns the first element of `deq`, but does not remove it from the deque. + ## Returns a mutable reference to the first element of `deq`, + ## but does not remove it from the deque. ## - ## 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]>`_ + ## **See also:** + ## * `peekFirst proc <#peekFirst,Deque[T]>`_ + ## * `peekLast proc <#peekLast,Deque[T]_2>`_ runnableExamples: - 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 + 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 the last element of `deq`, but does not remove it from the deque. + ## Returns a mutable reference to the last element of `deq`, + ## but does not remove it from the deque. ## - ## 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]>`_ + ## **See also:** + ## * `peekFirst proc <#peekFirst,Deque[T]_2>`_ + ## * `peekLast proc <#peekLast,Deque[T]>`_ runnableExamples: - 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 + 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] @@ -406,17 +369,10 @@ proc popFirst*[T](deq: var Deque[T]): T {.inline, discardable.} = ## Removes 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 = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + var a = [10, 20, 30, 40, 50].toDeque assert $a == "[10, 20, 30, 40, 50]" assert a.popFirst == 10 assert $a == "[20, 30, 40, 50]" @@ -430,18 +386,11 @@ proc popFirst*[T](deq: var Deque[T]): T {.inline, discardable.} = proc popLast*[T](deq: var Deque[T]): T {.inline, discardable.} = ## Removes and returns the last 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]>`_ + ## **See also:** ## * `popFirst proc <#popFirst,Deque[T]>`_ - ## * `clear proc <#clear,Deque[T]>`_ ## * `shrink proc <#shrink,Deque[T],int,int>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addLast(10*i) + var a = [10, 20, 30, 40, 50].toDeque assert $a == "[10, 20, 30, 40, 50]" assert a.popLast == 50 assert $a == "[10, 20, 30, 40]" @@ -455,14 +404,11 @@ proc popLast*[T](deq: var Deque[T]): T {.inline, discardable.} = proc clear*[T](deq: var Deque[T]) {.inline.} = ## Resets the deque so that it is empty. ## - ## See also: - ## * `clear proc <#clear,Deque[T]>`_ + ## **See also:** ## * `shrink proc <#shrink,Deque[T],int,int>`_ runnableExamples: - var a = initDeque[int]() - for i in 1 .. 5: - a.addFirst(10*i) - assert $a == "[50, 40, 30, 20, 10]" + var a = [10, 20, 30, 40, 50].toDeque + assert $a == "[10, 20, 30, 40, 50]" clear(a) assert len(a) == 0 @@ -477,15 +423,15 @@ proc shrink*[T](deq: var Deque[T], fromFirst = 0, fromLast = 0) = ## 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 = initDeque[int]() - for i in 1 .. 5: - a.addFirst(10*i) - assert $a == "[50, 40, 30, 20, 10]" + var a = [10, 20, 30, 40, 50].toDeque + assert $a == "[10, 20, 30, 40, 50]" a.shrink(fromFirst = 2, fromLast = 1) - assert $a == "[30, 20]" + assert $a == "[30, 40]" if fromFirst + fromLast > deq.count: clear(deq) @@ -503,6 +449,10 @@ proc shrink*[T](deq: var Deque[T], fromFirst = 0, fromLast = 0) = 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]" + result = "[" for x in deq: if result.len > 1: result.add(", ") diff --git a/lib/pure/collections/hashcommon.nim b/lib/pure/collections/hashcommon.nim index 336dbc07d7..0304461766 100644 --- a/lib/pure/collections/hashcommon.nim +++ b/lib/pure/collections/hashcommon.nim @@ -7,17 +7,12 @@ # 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. 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.} = @@ -42,7 +37,7 @@ proc rightSize*(count: Natural): int {.inline, deprecated: "Deprecated since 1.4 ## **Deprecated since Nim v1.4.0**, it is not needed anymore ## because picking the correct size is done internally. ## - ## Return the value of ``initialSize`` to support ``count`` items. + ## 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. diff --git a/lib/pure/collections/heapqueue.nim b/lib/pure/collections/heapqueue.nim index 30fa5dae8d..89e532951a 100644 --- a/lib/pure/collections/heapqueue.nim +++ b/lib/pure/collections/heapqueue.nim @@ -8,31 +8,27 @@ ## 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 +## `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 = initHeapQueue[int]() - heap.push(8) - heap.push(2) + var heap = [8, 2].toHeapQueue heap.push(5) - # The first element is the lowest element + # the first element is the lowest element assert heap[0] == 2 - # Remove and return the lowest element + # remove and return the lowest element assert heap.pop() == 2 - # The lowest element remaining is 5 + # the lowest element remaining is 5 assert heap[0] == 5 -## Usage with custom object -## ------------------------ +## Usage with custom objects +## ------------------------- ## To use a `HeapQueue` with a custom object, the `<` operator must be ## implemented. @@ -48,6 +44,7 @@ runnableExamples: assert jobs[0].priority == 1 + import std/private/since type HeapQueue*[T] = object @@ -57,27 +54,33 @@ type HeapQueue*[T] = object proc initHeapQueue*[T](): HeapQueue[T] = ## Creates a new empty heap. ## - ## See also: + ## Heaps are initialized by default, so it is not necessary to call + ## this function explicitly. + ## + ## **See also:** ## * `toHeapQueue proc <#toHeapQueue,openArray[T]>`_ 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 + heap.data.len proc `[]`*[T](heap: HeapQueue[T], i: Natural): lent T {.inline.} = ## Accesses the i-th element of `heap`. heap.data[i] -proc heapCmp[T](x, y: T): bool {.inline.} = - return (x < y) +proc heapCmp[T](x, y: T): bool {.inline.} = x < y -proc siftdown[T](heap: var HeapQueue[T], startpos, p: int) = - ## 'heap' is a heap at all indices >= startpos, except possibly for `pos`. `pos` +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 ## heap invariant. var pos = p - var newitem = heap[pos] + let newitem = heap[pos] # Follow the path to the root, moving parents down until finding a place # newitem fits. while pos > startpos: @@ -90,13 +93,14 @@ proc siftdown[T](heap: var HeapQueue[T], startpos, p: int) = break heap.data[pos] = newitem -proc siftup[T](heap: var HeapQueue[T], p: int) = +proc siftdownToBottom[T](heap: var HeapQueue[T], p: int) = + # This is faster when the element should be close to the bottom. 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 @@ -105,52 +109,71 @@ proc siftup[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 - siftdown(heap, startpos, pos) + siftup(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. + ## Pushes `item` onto `heap`, maintaining the heap invariant. heap.data.add(item) - siftdown(heap, 0, len(heap)-1) + 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: + ## **See also:** ## * `initHeapQueue proc <#initHeapQueue>`_ runnableExamples: - var heap = toHeapQueue([9, 5, 8]) + var heap = [9, 5, 8].toHeapQueue assert heap.pop() == 5 assert heap[0] == 8 - result = initHeapQueue[T]() - for item in items(x): - result.push(item) + # 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) proc pop*[T](heap: var HeapQueue[T]): T = ## Pops and returns the smallest item from `heap`, ## maintaining the heap invariant. runnableExamples: - var heap = toHeapQueue([9, 5, 8]) + 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 - siftup(heap, 0) + siftdownToBottom(heap, 0) else: result = lastelt proc find*[T](heap: HeapQueue[T], x: T): int {.since: (1, 3).} = - ## Linear scan to find index of item ``x`` or -1 if not found. + ## Linear scan to find the index of the item `x` or -1 if not found. runnableExamples: - var heap = toHeapQueue([9, 5, 8]) + 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 @@ -158,65 +181,69 @@ proc find*[T](heap: HeapQueue[T], x: T): int {.since: (1, 3).} = proc del*[T](heap: var HeapQueue[T], index: Natural) = ## Removes the element at `index` from `heap`, maintaining the heap invariant. runnableExamples: - var heap = toHeapQueue([9, 5, 8]) + 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: - heap.siftup(index) + siftdownToBottom(heap, 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 + ## 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 = initHeapQueue[int]() - heap.push(5) - heap.push(12) + var heap = [5, 12].toHeapQueue assert heap.replace(6) == 5 assert heap.len == 2 assert heap[0] == 6 assert heap.replace(4) == 6 + result = heap[0] heap.data[0] = item - siftup(heap, 0) + siftdown(heap, 0) proc pushpop*[T](heap: var HeapQueue[T], item: sink T): T = - ## Fast version of a push followed by a pop. + ## Fast version of a `push()` followed by a `pop()`. + ## + ## **See also:** + ## * `replace proc <#replace,HeapQueue[T],sinkT>`_ runnableExamples: - var heap = initHeapQueue[int]() - heap.push(5) - heap.push(12) + 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]) - siftup(heap, 0) + siftdown(heap, 0) proc clear*[T](heap: var HeapQueue[T]) = ## Removes all elements from `heap`, making it empty. runnableExamples: - var heap = initHeapQueue[int]() - heap.push(1) + var heap = [9, 5, 8].toHeapQueue heap.clear() assert heap.len == 0 + heap.data.setLen(0) proc `$`*[T](heap: HeapQueue[T]): string = ## Turns a heap into its string representation. runnableExamples: - var heap = initHeapQueue[int]() - heap.push(1) - heap.push(2) + let heap = [1, 2].toHeapQueue assert $heap == "[1, 2]" + result = "[" for x in heap.data: if result.len > 1: result.add(", ") diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index e4c216d08d..05e5addcc1 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -7,9 +7,8 @@ # distribution, for details about the copyright. # -## Deprecated by the generic `PackedSet` for ordinal sparse sets. -## **See also:** -## * `Ordinal packed sets module `_ for more general packed sets +## Specialization of the generic `packedsets module `_ +## for ordinal sparse sets. import std/private/since import std/packedsets diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 8af0ed826d..c1fcb07433 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -13,120 +13,91 @@ ## * `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 -## ----- -## -## .. 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 -## ======== -## +## ## Lists +runnableExamples: + var l = initDoublyLinkedList[int]() + let + a = newDoublyLinkedNode[int](3) + b = newDoublyLinkedNode[int](7) + c = newDoublyLinkedNode[int](9) + + l.add(a) + l.add(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 +runnableExamples: + var l = initSinglyLinkedRing[int]() + let + a = newSinglyLinkedNode[int](3) + b = newSinglyLinkedNode[int](7) + c = newSinglyLinkedNode[int](9) + + l.add(a) + l.add(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 not defined(nimhygiene): - {.pragma: dirty.} - when not defined(nimHasCursor): {.pragma: cursor.} type - DoublyLinkedNodeObj*[T] = object ## \ - ## A node a doubly linked list consists of. + DoublyLinkedNodeObj*[T] = object + ## A node of a doubly linked list. ## ## It consists of a `value` field, and pointers to `next` and `prev`. - next*: (ref DoublyLinkedNodeObj[T]) - prev* {.cursor.}: ref DoublyLinkedNodeObj[T] + next*: (DoublyLinkedNode[T]) + prev* {.cursor.}: DoublyLinkedNode[T] value*: T DoublyLinkedNode*[T] = ref DoublyLinkedNodeObj[T] - SinglyLinkedNodeObj*[T] = object ## \ - ## A node a singly linked list consists of. + SinglyLinkedNodeObj*[T] = object + ## A node of a singly linked list. ## ## It consists of a `value` field, and a pointer to `next`. - next*: (ref SinglyLinkedNodeObj[T]) + next*: (SinglyLinkedNode[T]) value*: T SinglyLinkedNode*[T] = ref SinglyLinkedNodeObj[T] - SinglyLinkedList*[T] = object ## \ + SinglyLinkedList*[T] = object ## A singly linked list. - ## - ## 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. - ## - ## 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. - ## - ## 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] @@ -139,32 +110,48 @@ 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: - var a = initSinglyLinkedList[int]() + let 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: - var a = initDoublyLinkedList[int]() + let 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: - var a = initSinglyLinkedRing[int]() + let 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: - var a = initDoublyLinkedRing[int]() + let a = initDoublyLinkedRing[int]() + discard proc newDoublyLinkedNode*[T](value: T): (DoublyLinkedNode[T]) = ## Creates a new doubly linked node with the given `value`. runnableExamples: - var n = newDoublyLinkedNode[int](5) + let n = newDoublyLinkedNode[int](5) assert n.value == 5 new(result) @@ -173,280 +160,320 @@ proc newDoublyLinkedNode*[T](value: T): (DoublyLinkedNode[T]) = proc newSinglyLinkedNode*[T](value: T): (SinglyLinkedNode[T]) = ## Creates a new singly linked node with the given `value`. runnableExamples: - var n = newSinglyLinkedNode[int](5) + let 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 members of `elems`. + ## Creates a new `SinglyLinkedList` from the members of `elems`. runnableExamples: - import sequtils + 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.append(elem) + result.add(elem) func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} = - ## Creates a new `DoublyLinkedList` from members of `elems`. + ## Creates a new `DoublyLinkedList` from the members of `elems`. runnableExamples: - import sequtils + 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.append(elem) + result.add(elem) template itemsListImpl() {.dirty.} = - var it = L.head + var it = list.head while it != nil: yield it.value it = it.next template itemsRingImpl() {.dirty.} = - var it = L.head + var it = ring.head if it != nil: while true: yield it.value it = it.next - if it == L.head: break + if it == ring.head: break -iterator items*[T](L: SomeLinkedList[T]): T = - ## Yields every value of `L`. +iterator items*[T](list: SomeLinkedList[T]): T = + ## Yields every value of `list`. ## - ## See also: + ## **See also:** ## * `mitems iterator <#mitems.i,SomeLinkedList[T]>`_ ## * `nodes iterator <#nodes.i,SomeLinkedList[T]>`_ - ## - ## **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 + 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] + itemsListImpl() -iterator items*[T](L: SomeLinkedRing[T]): T = - ## Yields every value of `L`. +iterator items*[T](ring: SomeLinkedRing[T]): T = + ## Yields every value of `ring`. ## - ## See also: + ## **See also:** ## * `mitems iterator <#mitems.i,SomeLinkedRing[T]>`_ ## * `nodes iterator <#nodes.i,SomeLinkedRing[T]>`_ - ## - ## **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 + 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] + itemsRingImpl() -iterator mitems*[T](L: var SomeLinkedList[T]): var T = - ## Yields every value of `L` so that you can modify it. +iterator mitems*[T](list: var SomeLinkedList[T]): var T = + ## Yields every value of `list` 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.append(10*i) + for i in 1..5: + a.add(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. +iterator mitems*[T](ring: var SomeLinkedRing[T]): var T = + ## Yields every value of `ring` 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.append(10*i) + for i in 1..5: + a.add(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] = +iterator nodes*[T](list: 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.append(10*i) + for i in 1..5: + a.add(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 + var it = list.head while it != nil: - var nxt = it.next + let nxt = it.next yield it it = nxt -iterator nodes*[T](L: SomeLinkedRing[T]): SomeLinkedNode[T] = +iterator nodes*[T](ring: 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.append(10*i) + for i in 1..5: + a.add(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 + var it = ring.head if it != nil: while true: - var nxt = it.next + let nxt = it.next yield it it = nxt - if it == L.head: break + if it == ring.head: break -proc `$`*[T](L: SomeLinkedCollection[T]): string = +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): + for x in nodes(l): if result.len > 1: result.add(", ") result.addQuoted(x.value) result.add("]") -proc find*[T](L: SomeLinkedCollection[T], value: T): SomeLinkedNode[T] = +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: - var a = initSinglyLinkedList[int]() - a.append(9) - a.append(8) + let a = [9, 8].toSinglyLinkedList assert a.find(9).value == 9 assert a.find(1) == nil - for x in nodes(L): + for x in nodes(l): if x.value == value: return x -proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} = +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. + ## exist, `true` otherwise. This allows the usage of the `in` and `notin` + ## operators. ## - ## See also: + ## **See also:** ## * `find proc <#find,SomeLinkedCollection[T],T>`_ runnableExamples: - var a = initSinglyLinkedList[int]() - a.append(9) - a.append(8) + let a = [9, 8].toSinglyLinkedList assert a.contains(9) assert 8 in a assert(not a.contains(1)) assert 2 notin a - result = find(L, value) != nil + result = find(l, value) != nil -proc append*[T](L: var SinglyLinkedList[T], - n: SinglyLinkedNode[T]) {.inline.} = - ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). +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: - ## * `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 + ## **See also:** + ## * `prependMoved proc <#prependMoved,T,T>`_ + ## for moving the second list instead of copying runnableExamples: - var - a = initSinglyLinkedList[int]() - n = newSinglyLinkedNode[int](9) - a.append(n) - assert a.contains(9) + 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] - n.next = nil - if L.tail != nil: - assert(L.tail.next == nil) - L.tail.next = n - L.tail = n - if L.head == nil: L.head = n + var tmp = b.copy + tmp.addMoved(a) + a = tmp -proc append*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = - ## Appends (adds to the end) a value to `L`. Efficiency: O(1). +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: - ## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value + ## **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](list: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) {.inline.} = + ## Appends (adds to the end) a node `n` to `list`. Efficiency: O(1). + ## + ## **See also:** + ## * `add proc <#add,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.append(9) - a.append(8) + let n = newSinglyLinkedNode[int](9) + a.add(n) assert a.contains(9) - 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). + n.next = nil + if list.tail != nil: + assert(list.tail.next == nil) + list.tail.next = n + list.tail = n + if list.head == nil: list.head = n + +proc add*[T](list: var SinglyLinkedList[T], value: T) {.inline.} = + ## Appends (adds to the end) a value to `list`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ - ## for appending a node - ## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value + ## **See also:** + ## * `add proc <#add,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]() - n = newSinglyLinkedNode[int](9) + var a = initSinglyLinkedList[int]() + a.add(9) + a.add(8) + assert a.contains(9) + + add(list, newSinglyLinkedNode(value)) + +proc prepend*[T](list: var SinglyLinkedList[T], + n: SinglyLinkedNode[T]) {.inline.} = + ## Prepends (adds to the beginning) a node to `list`. Efficiency: O(1). + ## + ## **See also:** + ## * `add proc <#add,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ + ## for appending a node + ## * `add proc <#add,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) a.prepend(n) assert a.contains(9) - n.next = L.head - L.head = n - if L.tail == nil: L.tail = n + n.next = list.head + list.head = n + if list.tail == nil: list.tail = n -proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = - ## Prepends (adds to the beginning) a node to `L`. Efficiency: O(1). +proc prepend*[T](list: var SinglyLinkedList[T], value: T) {.inline.} = + ## Prepends (adds to the beginning) a node to `list`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ + ## **See also:** + ## * `add proc <#add,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## for appending a node - ## * `append proc <#append,SinglyLinkedList[T],T>`_ for appending a value + ## * `add proc <#add,SinglyLinkedList[T],T>`_ for appending a value ## * `prepend proc <#prepend,SinglyLinkedList[T],SinglyLinkedNode[T]>`_ ## for prepending a node runnableExamples: @@ -454,19 +481,20 @@ proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = a.prepend(9) a.prepend(8) assert a.contains(9) - prepend(L, newSinglyLinkedNode(value)) + + prepend(list, newSinglyLinkedNode(value)) func copy*[T](a: SinglyLinkedList[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} = ## Creates a shallow copy of `a`. runnableExamples: - import sequtils + 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 + a.add([f].toSinglyLinkedList) assert a.toSeq == [f, f] assert b.toSeq == [f] # b isn't modified... f.x = 42 @@ -475,33 +503,34 @@ func copy*[T](a: SinglyLinkedList[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} let c = [1, 2, 3].toSinglyLinkedList assert $c == $c.copy + result = initSinglyLinkedList[T]() for x in a.items: - result.append(x) + 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 + ## **See also:** + ## * `add proc <#add,T,T>`_ for adding a copy of a list runnableExamples: - import sequtils, std/enumerate, std/sugar + import std/[sequtils, enumerate, sugar] var a = [1, 2, 3].toSinglyLinkedList b = [4, 5].toSinglyLinkedList c = [0, 1].toSinglyLinkedList - a.addMoved b + a.addMoved(b) assert a.toSeq == [1, 2, 3, 4, 5] assert b.toSeq == [] - c.addMoved c + 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 a.tail != nil: a.tail.next = b.head a.tail = b.tail @@ -511,36 +540,35 @@ proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} = b.head = nil b.tail = nil -proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = - ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). +proc add*[T](list: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = + ## Appends (adds to the end) a node `n` to `list`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,DoublyLinkedList[T],T>`_ for appending a value + ## **See also:** + ## * `add proc <#add,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]() - n = newDoublyLinkedNode[int](9) - a.append(n) + var a = initDoublyLinkedList[int]() + let n = newDoublyLinkedNode[int](9) + a.add(n) assert a.contains(9) n.next = nil - n.prev = L.tail - if L.tail != nil: - assert(L.tail.next == nil) - L.tail.next = n - L.tail = n - if L.head == nil: L.head = n + n.prev = list.tail + if list.tail != nil: + assert(list.tail.next == nil) + list.tail.next = n + list.tail = n + if list.head == nil: list.head = n -proc append*[T](L: var DoublyLinkedList[T], value: T) = - ## Appends (adds to the end) a value to `L`. Efficiency: O(1). +proc add*[T](list: var DoublyLinkedList[T], value: T) = + ## Appends (adds to the end) a value to `list`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ + ## **See also:** + ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for appending a node ## * `prepend proc <#prepend,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for prepending a node @@ -549,43 +577,43 @@ proc append*[T](L: var DoublyLinkedList[T], value: T) = ## for removing a node runnableExamples: var a = initDoublyLinkedList[int]() - a.append(9) - a.append(8) + a.add(9) + a.add(8) assert a.contains(9) - 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). + add(list, newDoublyLinkedNode(value)) + +proc prepend*[T](list: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = + ## Prepends (adds to the beginning) a node `n` to `list`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ + ## **See also:** + ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for appending a node - ## * `append proc <#append,DoublyLinkedList[T],T>`_ for appending a value + ## * `add proc <#add,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]() - n = newDoublyLinkedNode[int](9) + var a = initDoublyLinkedList[int]() + let n = newDoublyLinkedNode[int](9) a.prepend(n) assert a.contains(9) n.prev = nil - n.next = L.head - if L.head != nil: - assert(L.head.prev == nil) - L.head.prev = n - L.head = n - if L.tail == nil: L.tail = n + n.next = list.head + if list.head != nil: + assert(list.head.prev == nil) + list.head.prev = n + list.head = n + if list.tail == nil: list.tail = n -proc prepend*[T](L: var DoublyLinkedList[T], value: T) = - ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). +proc prepend*[T](list: var DoublyLinkedList[T], value: T) = + ## Prepends (adds to the beginning) a value to `list`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ + ## **See also:** + ## * `add proc <#add,DoublyLinkedList[T],DoublyLinkedNode[T]>`_ ## for appending a node - ## * `append proc <#append,DoublyLinkedList[T],T>`_ for appending a value + ## * `add proc <#add,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]>`_ @@ -595,50 +623,57 @@ proc prepend*[T](L: var DoublyLinkedList[T], value: T) = a.prepend(9) a.prepend(8) assert a.contains(9) - prepend(L, newDoublyLinkedNode(value)) + + prepend(list, 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) - let + var + f = Foo(x: 1) a = [f].toDoublyLinkedList - b = a.copy + 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 + 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.append(x) + 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: + ## **See also:** ## * `add proc <#add,T,T>`_ ## for adding a copy of a list runnableExamples: - import sequtils, std/enumerate, std/sugar + import std/[sequtils, enumerate, sugar] var a = [1, 2, 3].toDoublyLinkedList b = [4, 5].toDoublyLinkedList c = [0, 1].toDoublyLinkedList - a.addMoved b + a.addMoved(b) assert a.toSeq == [1, 2, 3, 4, 5] assert b.toSeq == [] - c.addMoved c + 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: b.head.prev = a.tail if a.tail != nil: @@ -653,112 +688,158 @@ proc addMoved*[T](a, b: var DoublyLinkedList[T]) {.since: (1, 5, 1).} = 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: + ## **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: - import sequtils + from std/sequtils import toSeq var a = [1, 2, 3].toSinglyLinkedList let b = [4, 5].toSinglyLinkedList - a.add b + a.add(b) assert a.toSeq == [1, 2, 3, 4, 5] assert b.toSeq == [4, 5] - a.add a + a.add(a) assert a.toSeq == [1, 2, 3, 4, 5, 1, 2, 3, 4, 5] + var tmp = b.copy - a.addMoved tmp + a.addMoved(tmp) -proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = - ## Removes a node `n` from `L`. Efficiency: O(1). +proc remove*[T](list: var SinglyLinkedList[T], n: SinglyLinkedNode[T]): bool {.discardable.} = + ## Removes a node `n` from `list`. + ## Returns `true` if `n` was found in `list`. + ## 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: - var - a = initDoublyLinkedList[int]() - n = newDoublyLinkedNode[int](5) - a.append(n) - assert 5 in a - a.remove(n) - assert 5 notin a + 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.tail: L.tail = n.prev - if n == L.head: L.head = n.next + if n == list.head: + list.head = n.next + if list.tail.next == n: + list.tail.next = list.head # restore cycle + else: + var prev = list.head + while prev.next != n and prev.next != nil: + prev = prev.next + if prev.next == nil: + return false + prev.next = n.next + true + +proc remove*[T](list: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = + ## Removes a node `n` from `list`. Efficiency: O(1). + ## This function assumes, for the sake of efficiency, that `n` is contained in `list`, + ## 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 + 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] + + if n == list.tail: list.tail = n.prev + if n == list.head: list.head = n.next if n.next != nil: n.next.prev = n.prev if n.prev != nil: n.prev.next = n.next -proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = - ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). +proc add*[T](ring: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = + ## Appends (adds to the end) a node `n` to `ring`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,SinglyLinkedRing[T],T>`_ for appending a value + ## **See also:** + ## * `add proc <#add,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]() - n = newSinglyLinkedNode[int](9) - a.append(n) + var a = initSinglyLinkedRing[int]() + let n = newSinglyLinkedNode[int](9) + a.add(n) assert a.contains(9) - if L.head != nil: - n.next = L.head - assert(L.tail != nil) - L.tail.next = n - L.tail = n + if ring.head != nil: + n.next = ring.head + assert(ring.tail != nil) + ring.tail.next = n else: n.next = n - L.head = n - L.tail = n + ring.head = n + ring.tail = n -proc append*[T](L: var SinglyLinkedRing[T], value: T) = - ## Appends (adds to the end) a value to `L`. Efficiency: O(1). +proc add*[T](ring: var SinglyLinkedRing[T], value: T) = + ## Appends (adds to the end) a value to `ring`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ + ## **See also:** + ## * `add proc <#add,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.append(9) - a.append(8) + a.add(9) + a.add(8) assert a.contains(9) - 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). + add(ring, newSinglyLinkedNode(value)) + +proc prepend*[T](ring: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = + ## Prepends (adds to the beginning) a node `n` to `ring`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ + ## **See also:** + ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## for appending a node - ## * `append proc <#append,SinglyLinkedRing[T],T>`_ for appending a value + ## * `add proc <#add,SinglyLinkedRing[T],T>`_ for appending a value ## * `prepend proc <#prepend,SinglyLinkedRing[T],T>`_ for prepending a value runnableExamples: - var - a = initSinglyLinkedRing[int]() - n = newSinglyLinkedNode[int](9) + var a = initSinglyLinkedRing[int]() + let n = newSinglyLinkedNode[int](9) a.prepend(n) assert a.contains(9) - if L.head != nil: - n.next = L.head - assert(L.tail != nil) - L.tail.next = n + if ring.head != nil: + n.next = ring.head + assert(ring.tail != nil) + ring.tail.next = n else: n.next = n - L.tail = n - L.head = n + ring.tail = n + ring.head = n -proc prepend*[T](L: var SinglyLinkedRing[T], value: T) = - ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). +proc prepend*[T](ring: var SinglyLinkedRing[T], value: T) = + ## Prepends (adds to the beginning) a value to `ring`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ + ## **See also:** + ## * `add proc <#add,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## for appending a node - ## * `append proc <#append,SinglyLinkedRing[T],T>`_ for appending a value + ## * `add proc <#add,SinglyLinkedRing[T],T>`_ for appending a value ## * `prepend proc <#prepend,SinglyLinkedRing[T],SinglyLinkedNode[T]>`_ ## for prepending a node runnableExamples: @@ -766,42 +847,42 @@ proc prepend*[T](L: var SinglyLinkedRing[T], value: T) = a.prepend(9) a.prepend(8) assert a.contains(9) - prepend(L, newSinglyLinkedNode(value)) + + prepend(ring, newSinglyLinkedNode(value)) -proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = - ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1). +proc add*[T](ring: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = + ## Appends (adds to the end) a node `n` to `ring`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,DoublyLinkedRing[T],T>`_ for appending a value + ## **See also:** + ## * `add proc <#add,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]() - n = newDoublyLinkedNode[int](9) - a.append(n) + var a = initDoublyLinkedRing[int]() + let n = newDoublyLinkedNode[int](9) + a.add(n) assert a.contains(9) - if L.head != nil: - n.next = L.head - n.prev = L.head.prev - L.head.prev.next = n - L.head.prev = n + if ring.head != nil: + n.next = ring.head + n.prev = ring.head.prev + ring.head.prev.next = n + ring.head.prev = n else: n.prev = n n.next = n - L.head = n + ring.head = n -proc append*[T](L: var DoublyLinkedRing[T], value: T) = - ## Appends (adds to the end) a value to `L`. Efficiency: O(1). +proc add*[T](ring: var DoublyLinkedRing[T], value: T) = + ## Appends (adds to the end) a value to `ring`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ + ## **See also:** + ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for appending a node ## * `prepend proc <#prepend,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for prepending a node @@ -810,45 +891,45 @@ proc append*[T](L: var DoublyLinkedRing[T], value: T) = ## for removing a node runnableExamples: var a = initDoublyLinkedRing[int]() - a.append(9) - a.append(8) + a.add(9) + a.add(8) assert a.contains(9) - 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). + add(ring, newDoublyLinkedNode(value)) + +proc prepend*[T](ring: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = + ## Prepends (adds to the beginning) a node `n` to `ring`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ + ## **See also:** + ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for appending a node - ## * `append proc <#append,DoublyLinkedRing[T],T>`_ for appending a value + ## * `add proc <#add,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]() - n = newDoublyLinkedNode[int](9) + var a = initDoublyLinkedRing[int]() + let n = newDoublyLinkedNode[int](9) a.prepend(n) assert a.contains(9) - if L.head != nil: - n.next = L.head - n.prev = L.head.prev - L.head.prev.next = n - L.head.prev = n + if ring.head != nil: + n.next = ring.head + n.prev = ring.head.prev + ring.head.prev.next = n + ring.head.prev = n else: n.prev = n n.next = n - L.head = n + ring.head = n -proc prepend*[T](L: var DoublyLinkedRing[T], value: T) = - ## Prepends (adds to the beginning) a value to `L`. Efficiency: O(1). +proc prepend*[T](ring: var DoublyLinkedRing[T], value: T) = + ## Prepends (adds to the beginning) a value to `ring`. Efficiency: O(1). ## - ## See also: - ## * `append proc <#append,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ + ## **See also:** + ## * `add proc <#add,DoublyLinkedRing[T],DoublyLinkedNode[T]>`_ ## for appending a node - ## * `append proc <#append,DoublyLinkedRing[T],T>`_ for appending a value + ## * `add proc <#add,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]>`_ @@ -858,25 +939,55 @@ 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). + prepend(ring, newDoublyLinkedNode(value)) + +proc remove*[T](ring: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = + ## Removes `n` from `ring`. Efficiency: O(1). + ## This function assumes, for the sake of efficiency, that `n` is contained in `ring`, + ## otherwise the effects are undefined. runnableExamples: - var - a = initDoublyLinkedRing[int]() - n = newDoublyLinkedNode[int](5) - a.append(n) + var a = initDoublyLinkedRing[int]() + let n = newDoublyLinkedNode[int](5) + a.add(n) assert 5 in a a.remove(n) assert 5 notin a n.next.prev = n.prev n.prev.next = n.next - if n == L.head: - var p = L.head.prev - if p == L.head: + if n == ring.head: + let p = ring.head.prev + if p == ring.head: # only one element left: - L.head = nil + ring.head = nil else: - L.head = L.head.prev + ring.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) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 7aa8857946..e937b83944 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -8,13 +8,13 @@ # ## 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: +## not only for the `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: +## 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 @@ -27,28 +27,28 @@ ## languages. ## ## For functional style programming you have different options at your disposal: -## * `sugar.collect macro`_ -## * pass `anonymous proc`_ -## * import `sugar module`_ and use -## `=> macro.m,untyped,untyped>`_ +## * the `sugar.collect macro`_ +## * pass an `anonymous proc`_ +## * import the `sugar module`_ and use +## the `=> macro.m,untyped,untyped>`_ ## * use `...It templates<#18>`_ ## (`mapIt<#mapIt.t,typed,untyped>`_, ## `filterIt<#filterIt.t,untyped,untyped>`_, etc.) ## -## The chaining of functions is possible thanks to the +## Chaining of functions is possible thanks to the ## `method call syntax`_. runnableExamples: - import sugar + 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) + 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 + let j = 2 * i if j mod 6 != 0: j @@ -62,7 +62,7 @@ runnableExamples: runnableExamples: - from strutils import join + from std/strutils import join let vowels = @"aeiou" @@ -71,7 +71,8 @@ runnableExamples: 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**: +## See also +## ======== ## * `strutils module`_ for common string functions ## * `sugar module`_ for syntactic sugar macros ## * `algorithm module`_ for common generic algorithms @@ -83,18 +84,14 @@ import std/private/since import macros -when not defined(nimhygiene): - {.pragma: dirty.} - - 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 + ## 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 + ## it just forwards `exp` unchanged. expectKind(expAlias, nnkIdent) var val = exp @@ -113,7 +110,7 @@ func 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: + ## **See also:** ## * `distribute func<#distribute,seq[T],Positive>`_ for a reverse ## operation ## @@ -183,7 +180,7 @@ func repeat*[T](x: T, n: Natural): seq[T] = func 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: @@ -210,7 +207,7 @@ func deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] = func 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] @@ -227,7 +224,7 @@ func minIndex*[T](s: openArray[T]): int {.since: (1, 1).} = func 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] @@ -251,9 +248,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 tuple 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 tuples 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] @@ -311,7 +308,7 @@ func distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = ## `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`` + ## func 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 @@ -329,7 +326,6 @@ 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) @@ -361,16 +357,16 @@ func distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): seq[S]{.inline.} = - ## Returns a new sequence with the results of `op` proc applied to every + ## Returns a new sequence with the results of the `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: + ## **See also:** ## * `sugar.collect macro`_ ## * `mapIt template<#mapIt.t,typed,untyped>`_ ## * `apply proc<#apply,openArray[T],proc(T)_2>`_ for the in-place version @@ -387,14 +383,13 @@ proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}): proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.}) {.inline.} = - ## Applies `op` to every item in `s` modifying it directly. + ## Applies `op` to every item in `s`, modifying it directly. ## - ## 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. + ## 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. ## - ## See also: + ## **See also:** ## * `applyIt template<#applyIt.t,untyped,untyped>`_ ## * `map proc<#map,openArray[T],proc(T)>`_ ## @@ -409,12 +404,12 @@ proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.}) {.inline.} = ## Applies `op` to every item in `s` modifying it directly. ## - ## Note that container `s` must be declared as a ``var`` + ## Note that the 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)>`_ ## @@ -426,7 +421,8 @@ 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).} = - ## Same as `apply` but for proc that do not return and do not mutate `s` directly. + ## 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) @@ -435,14 +431,14 @@ proc apply*[T](s: openArray[T], op: proc (x: T) {.closure.}) {.inline, since: (1 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` (function that returns a `bool`). + ## predicate `pred` (a function that returns a `bool`). ## ## Instead of using `map` and `filter`, consider using the `collect` macro ## from the `sugar` module. ## - ## See also: + ## **See also:** ## * `sugar.collect macro`_ - ## * `fliter proc<#filter,openArray[T],proc(T)>`_ + ## * `filter proc<#filter,openArray[T],proc(T)>`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## runnableExamples: @@ -458,13 +454,13 @@ iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T = proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] {.inline.} = - ## Returns a new sequence with all the items of `s` that fulfilled the - ## predicate `pred` (function that returns a `bool`). + ## Returns a new sequence with all the items of `s` that fulfill the + ## predicate `pred` (a function that returns a `bool`). ## ## Instead of using `map` and `filter`, consider using the `collect` macro ## from the `sugar` module. ## - ## See also: + ## **See also:** ## * `sugar.collect macro`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_ @@ -485,15 +481,15 @@ proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T] proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) {.inline.} = - ## Keeps the items in the passed sequence `s` if they fulfilled the - ## predicate `pred` (function that returns a `bool`). + ## Keeps the items in the passed sequence `s` if they fulfill the + ## predicate `pred` (a 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)>`_ ## @@ -514,8 +510,8 @@ proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) setLen(s, pos) func 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). + ## Deletes the items of a sequence `s` at positions `first..last` + ## (including both ends of the range). ## This modifies `s` itself, it does not return a copy. ## runnableExamples: @@ -527,8 +523,8 @@ func delete*[T](s: var seq[T]; first, last: Natural) = 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]) @@ -542,7 +538,7 @@ func 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. ## - ## Notice that `src` and `dest` must be of the same type. + ## Note that the elements of `src` and `dest` must be of the same type. ## runnableExamples: var dest = @[1, 1, 1, 1, 1, 1, 1, 1] @@ -573,7 +569,7 @@ 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 fulfilled the + ## Returns a new sequence with all the items of `s` that fulfill the ## predicate `pred`. ## ## Unlike the `filter proc<#filter,openArray[T],proc(T)>`_ and @@ -584,9 +580,9 @@ template filterIt*(s, pred: untyped): untyped = ## Instead of using `mapIt` and `filterIt`, consider using the `collect` macro ## from the `sugar` module. ## - ## See also: + ## **See also:** ## * `sugar.collect macro`_ - ## * `fliter proc<#filter,openArray[T],proc(T)>`_ + ## * `filter proc<#filter,openArray[T],proc(T)>`_ ## * `filter iterator<#filter.i,openArray[T],proc(T)>`_ ## runnableExamples: @@ -604,13 +600,13 @@ template filterIt*(s, pred: untyped): untyped = template keepItIf*(varSeq: seq, pred: untyped) = ## Keeps the items in the passed sequence (must be declared as a `var`) - ## if they fulfilled the predicate. + ## if they fulfill 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')`. ## - ## See also: + ## **See also:** ## * `keepIf proc<#keepIf,seq[T],proc(T)>`_ ## * `filterIt template<#filterIt.t,untyped,untyped>`_ ## @@ -633,7 +629,7 @@ template keepItIf*(varSeq: seq, pred: untyped) = since (1, 1): template countIt*(s, pred: untyped): int = - ## Returns a count of all the items that fulfilled the predicate. + ## 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)`. @@ -654,19 +650,19 @@ proc all*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool = ## Iterates through a container and checks if every item fulfills the ## predicate. ## - ## See also: + ## **See also:** ## * `allIt template<#allIt.t,untyped,untyped>`_ ## * `any proc<#any,openArray[T],proc(T)>`_ ## runnableExamples: let numbers = @[1, 4, 5, 8, 9, 7, 4] - assert all(numbers, proc (x: int): bool = return x < 10) == true - assert all(numbers, proc (x: int): bool = return x < 9) == false + assert all(numbers, proc (x: int): bool = x < 10) == true + assert all(numbers, proc (x: int): bool = x < 9) == false for i in s: if not pred(i): return false - return true + true template allIt*(s, pred: untyped): bool = ## Iterates through a container and checks if every item fulfills the @@ -676,7 +672,7 @@ template allIt*(s, pred: untyped): bool = ## the predicate needs to be an expression using ## 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>`_ ## @@ -693,32 +689,32 @@ template allIt*(s, pred: untyped): bool = result 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. + ## Iterates through a container and checks if at least one 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 = return x > 8) == true - assert any(numbers, proc (x: int): bool = return x > 9) == false + assert any(numbers, proc (x: int): bool = x > 8) == true + assert any(numbers, proc (x: int): bool = x > 9) == false for i in s: if pred(i): return true - return false + false template anyIt*(s, pred: untyped): bool = - ## Iterates through a container and checks if some item fulfills the - ## predicate. + ## Iterates through a container and checks if at least one 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')`. ## - ## See also: + ## **See also:** ## * `any proc<#any,openArray[T],proc(T)>`_ ## * `allIt template<#allIt.t,untyped,untyped>`_ ## @@ -827,7 +823,7 @@ template foldl*(sequence, operation: untyped): untyped = ## 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>`_ ## @@ -872,7 +868,7 @@ template foldl*(sequence, operation, first): untyped = ## `a` and `b` for each step of the fold. The `first` parameter is the ## start value (the first `a`) and therefor defines the type of the result. ## - ## See also: + ## **See also:** ## * `foldr template<#foldr.t,untyped,untyped>`_ ## runnableExamples: @@ -903,7 +899,7 @@ template foldr*(sequence, operation: untyped): untyped = ## 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 ## @@ -932,7 +928,7 @@ template foldr*(sequence, operation: untyped): untyped = result template mapIt*(s: typed, op: untyped): untyped = - ## Returns a new sequence with the results of `op` proc applied to every + ## Returns a new sequence with the results of the `op` proc applied to every ## item in the container `s`. ## ## Since the input is not modified you can use it to @@ -944,7 +940,7 @@ template mapIt*(s: typed, op: untyped): untyped = ## Instead of using `mapIt` and `filterIt`, consider using the `collect` macro ## from the `sugar` module. ## - ## See also: + ## **See also:** ## * `sugar.collect macro`_ ## * `map proc<#map,openArray[T],proc(T)>`_ ## * `applyIt template<#applyIt.t,untyped,untyped>`_ for the in-place version @@ -955,16 +951,10 @@ template mapIt*(s: typed, op: untyped): untyped = strings = nums.mapIt($(4 * it)) assert strings == @["4", "8", "12", "16"] - when defined(nimHasTypeof): - type OutType = typeof(( - block: - var it{.inject.}: typeof(items(s), typeOfIter); - op), typeOfProc) - else: - type OutType = typeof(( - block: - var it{.inject.}: typeof(items(s)); - op)) + 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 @@ -995,11 +985,7 @@ template mapIt*(s: typed, op: untyped): untyped = # 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`. - - when defined(nimHasTypeof): - type InType = typeof(items(s), typeOfIter) - else: - type InType = typeof(items(s)) + 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 @@ -1010,10 +996,10 @@ template applyIt*(varSeq, op: untyped) = ## 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 sequence you - ## are mutating. + ## expression. The expression has to return the same type as the elements + ## of the sequence you are mutating. ## - ## See also: + ## **See also:** ## * `apply proc<#apply,openArray[T],proc(T)_2>`_ ## * `mapIt template<#mapIt.t,typed,untyped>`_ ## @@ -1081,7 +1067,7 @@ macro mapLiterals*(constructor, op: untyped; 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")) diff --git a/lib/pure/collections/setimpl.nim b/lib/pure/collections/setimpl.nim index 20da6b6c2c..7ebd227604 100644 --- a/lib/pure/collections/setimpl.nim +++ b/lib/pure/collections/setimpl.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -# An ``include`` file for the different hash set implementations. +# An `include` file for the different hash set implementations. template maxHash(t): untyped = high(t.data) @@ -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(type(s.data[i].key)) + s.data[i].key = default(typeof(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 a9df9ded88..3f91d9030a 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 @@ -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 @@ -51,9 +51,6 @@ import hashes, math {.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. @@ -116,7 +113,7 @@ proc initHashSet*[A](initialSize = defaultInitialSize): HashSet[A] = ## Wrapper around `init proc <#init,HashSet[A]>`_ 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 +130,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,6 +164,27 @@ 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`. ## @@ -241,8 +259,11 @@ 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 + 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") proc containsOrIncl*[A](s: var HashSet[A], key: A): bool = ## Includes `key` in the set `s` and tells if `key` was already in `s`. @@ -355,28 +376,7 @@ 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(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 + s.data[i].key = default(typeof(s.data[i].key)) proc union*[A](s1, s2: HashSet[A]): HashSet[A] = @@ -652,7 +652,7 @@ proc initOrderedSet*[A](initialSize = defaultInitialSize): OrderedSet[A] = ## Wrapper around `init proc <#init,OrderedSet[A]>`_ 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 @@ -812,7 +812,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(type(s.data[i].key)) + s.data[i].key = default(typeof(s.data[i].key)) proc len*[A](s: OrderedSet[A]): int {.inline.} = ## Returns the number of elements in `s`. @@ -901,8 +901,10 @@ 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`. @@ -913,5 +915,7 @@ 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") diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index af498d70d4..4ac3befb63 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -60,13 +60,13 @@ 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. + ## 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`` + ## # block is executed only if `key` in `t` ## # value is threadsafe in block ## value.name = "username" ## value.uid = 1000 @@ -84,18 +84,18 @@ 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. + ## 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`` + ## # 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`` + ## # block is executed when `key` not in `t` ## raise newException(KeyError, "Key not found") ## acquire(t.lock) @@ -112,8 +112,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) @@ -126,10 +126,10 @@ 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) @@ -144,24 +144,24 @@ 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: @@ -196,7 +196,7 @@ proc `[]=`*[A, B](t: var SharedTable[A, B], key: A, val: B) = 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) diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index c66da513c5..27c3391775 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 @@ -117,8 +117,8 @@ template delImplIdx(t, i, makeEmpty, cellEmpty, cellHash) = 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(type(t.data[i].key)) - t.data[i].val = default(type(t.data[i].val)) + t.data[i].key = default(typeof(t.data[i].key)) + t.data[i].val = default(typeof(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 @@ -149,8 +149,8 @@ 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(type(t.data[i].key)) - t.data[i].val = default(type(t.data[i].val)) + t.data[i].key = default(typeof(t.data[i].key)) + t.data[i].val = default(typeof(t.data[i].val)) t.counter = 0 template ctAnd(a, b): bool = @@ -161,7 +161,7 @@ template ctAnd(a, b): bool = template initImpl(result: typed, size: int) = let correctSize = slotsNeeded(size) - when ctAnd(declared(SharedTable), type(result) is SharedTable): + when ctAnd(declared(SharedTable), typeof(result) is SharedTable): init(result, correctSize) else: result.counter = 0 diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index d7376b0657..f776423491 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -7,154 +7,131 @@ # 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: -## -## .. 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 +## 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 + ## ## ---- ## -## 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 -## ------------ -## + +## # 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 ## `OrderedTable<#OrderedTable>`_ is used when it is important to preserve ## the insertion order of keys. -## -## .. 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 -## ---------- -## + +runnableExamples: + let + a = [('z', 1), ('y', 2), ('x', 3)] + ot = a.toOrderedTable # ordered tables + + assert $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: -## -## .. code-block:: -## import tables -## -## let myString = "abracadabra" -## let letterFrequencies = toCountTable(myString) -## echo letterFrequencies -## # output: {'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2} -## + +runnableExamples: + let myString = "abracadabra" + let letterFrequencies = toCountTable(myString) + assert $letterFrequencies == "{'a': 5, 'd': 1, 'b': 2, 'r': 2, 'c': 1}" + ## 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>`_: -## -## .. 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} + +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}" + ## ## ---- ## + +## ## Hashing ## -## -## Hashing -## ------- -## -## If you are using simple standard types like ``int`` or ``string`` for the +## 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: @@ -167,47 +144,48 @@ ## … ## ## 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: -## -## .. 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 +## 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 + ## ## ---- ## -## See also -## ======== + +## # See also ## ## * `json module`_ for table-like structure which allows ## heterogeneous members @@ -218,8 +196,7 @@ import std/private/since - -import hashes, math, algorithm +import std/[hashes, math, algorithm] type KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B] @@ -251,8 +228,8 @@ template dataLen(t): untyped = len(t.data) include tableimpl 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) @@ -301,7 +278,7 @@ proc initTable*[A, B](initialSize = defaultInitialSize): Table[A, B] = initImpl(result, initialSize) proc `[]=`*[A, B](t: var Table[A, B], key: A, val: sink B) = - ## Inserts a ``(key, value)`` pair into ``t``. + ## Inserts a `(key, value)` pair into `t`. ## ## See also: ## * `[] proc<#[],Table[A,B],A>`_ for retrieving a value of a key @@ -317,9 +294,9 @@ 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>`_ @@ -333,9 +310,9 @@ proc toTable*[A, B](pairs: openArray[(A, B)]): Table[A, B] = 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. ## @@ -356,9 +333,9 @@ 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 @@ -372,7 +349,7 @@ proc `[]`*[A, B](t: var Table[A, B], key: A): var B = 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 @@ -391,7 +368,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 @@ -400,7 +377,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>`_ @@ -420,8 +397,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: @@ -439,8 +416,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 @@ -457,7 +434,7 @@ 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. ## ## @@ -495,7 +472,7 @@ proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B = 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 @@ -504,7 +481,7 @@ proc len*[A, B](t: Table[A, B]): int = 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. + ## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists. ## ## **This can introduce duplicate keys into the table!** ## @@ -517,7 +494,7 @@ 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. + ## Deletes `key` from hash table `t`. Does nothing if the key does not exist. ## ## See also: ## * `pop proc<#pop,Table[A,B],A,B>`_ @@ -532,9 +509,9 @@ proc del*[A, B](t: var Table[A, B], key: A) = delImpl(tabMakeEmpty, tabCellEmpty, tabCellHash) 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. ## ## See also: @@ -579,12 +556,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 @@ -604,17 +581,31 @@ 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]``. - ## - ## ``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 + ## Retrieves the value at `t[key]`. ## + ## `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) do: + # block is executed only if `key` in `t` + value.name = "Nim" + value.uid = 1314 + + t.withValue(2, value) do: + value.name = "No" + value.uid = 521 + + doAssert t[1].name == "Nim" + doAssert t[1].uid == 1314 + mixin rawGet var hc: Hash var index = rawGet(t, key, hc) @@ -625,20 +616,29 @@ 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]``. - ## - ## ``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") + ## Retrieves the value at `t[key]`. ## + ## `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) do: + # block is executed only if `key` in `t` + value.name = "Nim" + value.uid = 1314 + # do: + # # block is executed when `key` not in `t` + # raise newException(KeyError, "Key not found") + + doAssert t[1].name == "Nim" + doAssert t[1].uid == 1314 mixin rawGet var hc: Hash var index = rawGet(t, key, hc) @@ -651,7 +651,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]>`_ @@ -681,7 +681,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: @@ -703,7 +703,7 @@ iterator mpairs*[A, B](t: var Table[A, B]): (A, var B) = assert(len(t) == L, "the length of the table changed while iterating over it") iterator keys*[A, B](t: Table[A, B]): A = - ## Iterates over any key in the table ``t``. + ## Iterates over any key in the table `t`. ## ## See also: ## * `pairs iterator<#pairs.i,Table[A,B]>`_ @@ -724,7 +724,7 @@ iterator keys*[A, B](t: Table[A, B]): A = assert(len(t) == L, "the length of the table changed while iterating over it") iterator values*[A, B](t: Table[A, B]): B = - ## Iterates over any value in the table ``t``. + ## Iterates over any value in the table `t`. ## ## See also: ## * `pairs iterator<#pairs.i,Table[A,B]>`_ @@ -745,7 +745,7 @@ iterator values*[A, B](t: Table[A, B]): 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: @@ -768,13 +768,13 @@ iterator mvalues*[A, B](t: var Table[A, B]): var B = 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``. + ## 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>`_). ## runnableExamples: - import sequtils, algorithm + import std/[sequtils, algorithm] var a = {'a': 3, 'b': 5}.toTable for i in 1..3: a.add('z', 10*i) @@ -811,9 +811,9 @@ proc newTable*[A, B](initialSize = defaultInitialSize): TableRef[A, B] = 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``. + ## 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>`_ @@ -834,9 +834,9 @@ proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C 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. ## @@ -858,7 +858,7 @@ 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``. + ## Inserts a `(key, value)` pair into `t`. ## ## See also: ## * `[] proc<#[],TableRef[A,B],A>`_ for retrieving a value of a key @@ -874,7 +874,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` @@ -893,7 +893,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 @@ -902,7 +902,7 @@ proc contains*[A, B](t: TableRef[A, B], key: A): bool = return hasKey[A, B](t, key) 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``. + ## Returns true if `key` is in the table, otherwise inserts `value`. ## ## See also: ## * `hasKey proc<#hasKey,TableRef[A,B],A>`_ @@ -922,8 +922,8 @@ proc hasKeyOrPut*[A, B](t: var 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: @@ -941,8 +941,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 @@ -959,7 +959,7 @@ 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`, @@ -995,7 +995,7 @@ proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B = 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 @@ -1004,7 +1004,7 @@ proc len*[A, B](t: TableRef[A, B]): int = 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. + ## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists. ## ## **This can introduce duplicate keys into the table!** ## @@ -1013,7 +1013,7 @@ proc add*[A, B](t: TableRef[A, B], key: A, val: sink B) {.deprecated: 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. ## ## **If duplicate keys were added, this may need to be called multiple times.** ## @@ -1030,9 +1030,9 @@ 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. ## ## **If duplicate keys were added, this may need to be called multiple times.** @@ -1074,13 +1074,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 @@ -1095,7 +1095,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]>`_ @@ -1125,7 +1125,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: @@ -1147,7 +1147,7 @@ iterator mpairs*[A, B](t: TableRef[A, B]): (A, var B) = assert(len(t) == L, "the length of the table changed while iterating over it") iterator keys*[A, B](t: TableRef[A, B]): A = - ## Iterates over any key in the table ``t``. + ## Iterates over any key in the table `t`. ## ## See also: ## * `pairs iterator<#pairs.i,TableRef[A,B]>`_ @@ -1168,7 +1168,7 @@ iterator keys*[A, B](t: TableRef[A, B]): A = assert(len(t) == L, "the length of the table changed while iterating over it") iterator values*[A, B](t: TableRef[A, B]): B = - ## Iterates over any value in the table ``t``. + ## Iterates over any value in the table `t`. ## ## See also: ## * `pairs iterator<#pairs.i,TableRef[A,B]>`_ @@ -1189,7 +1189,7 @@ iterator values*[A, B](t: TableRef[A, B]): 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]>`_ @@ -1303,7 +1303,7 @@ proc initOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTable[A, initImpl(result, initialSize) proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: sink B) = - ## Inserts a ``(key, value)`` pair into ``t``. + ## Inserts a `(key, value)` pair into `t`. ## ## See also: ## * `[] proc<#[],OrderedTable[A,B],A>`_ for retrieving a value of a key @@ -1319,9 +1319,9 @@ 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>`_ @@ -1336,9 +1336,9 @@ proc toOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTable[A, B] = 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. ## @@ -1360,9 +1360,9 @@ 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 @@ -1376,7 +1376,7 @@ proc `[]`*[A, B](t: var OrderedTable[A, B], key: A): var B = 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` @@ -1396,7 +1396,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 @@ -1405,7 +1405,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>`_ @@ -1425,8 +1425,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: @@ -1444,8 +1444,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 @@ -1462,7 +1462,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: @@ -1482,7 +1482,7 @@ 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 @@ -1491,7 +1491,7 @@ proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} = 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. + ## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists. ## ## **This can introduce duplicate keys into the table!** ## @@ -1500,7 +1500,7 @@ proc add*[A, B](t: var OrderedTable[A, B], key: A, val: sink B) {.deprecated: 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. ## @@ -1533,9 +1533,9 @@ proc del*[A, B](t: var OrderedTable[A, B], key: A) = 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. @@ -1580,14 +1580,14 @@ proc clear*[A, B](t: var OrderedTable[A, B]) = proc sort*[A, B](t: var OrderedTable[A, B], cmp: proc (x, y: (A, B)): int, order = SortOrder.Ascending) = - ## Sorts ``t`` according to the function ``cmp``. + ## 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 algorithm + import std/[algorithm] var a = initOrderedTable[char, int]() for i, c in "cab": a[c] = 10*i @@ -1638,12 +1638,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 @@ -1670,7 +1670,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: @@ -1701,7 +1701,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: @@ -1723,7 +1723,7 @@ iterator mpairs*[A, B](t: var OrderedTable[A, B]): (A, var B) = assert(len(t) == L, "the length of the table changed while iterating over it") iterator keys*[A, B](t: OrderedTable[A, B]): A = - ## Iterates over any key in the table ``t`` in insertion order. + ## Iterates over any key in the table `t` in insertion order. ## ## See also: ## * `pairs iterator<#pairs.i,OrderedTable[A,B]>`_ @@ -1744,7 +1744,7 @@ iterator keys*[A, B](t: OrderedTable[A, B]): A = assert(len(t) == L, "the length of the table changed while iterating over it") iterator values*[A, B](t: OrderedTable[A, B]): B = - ## Iterates over any value in the table ``t`` in insertion order. + ## Iterates over any value in the table `t` in insertion order. ## ## See also: ## * `pairs iterator<#pairs.i,OrderedTable[A,B]>`_ @@ -1764,7 +1764,7 @@ iterator values*[A, B](t: OrderedTable[A, B]): 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. ## @@ -1806,9 +1806,9 @@ proc newOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTableR 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``. + ## 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>`_ @@ -1824,9 +1824,9 @@ proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] 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. ## @@ -1847,7 +1847,7 @@ proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B = result = t[][key] proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: sink B) = - ## Inserts a ``(key, value)`` pair into ``t``. + ## Inserts a `(key, value)` pair into `t`. ## ## See also: ## * `[] proc<#[],OrderedTableRef[A,B],A>`_ for retrieving a value of a key @@ -1863,7 +1863,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` @@ -1882,7 +1882,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 @@ -1891,7 +1891,7 @@ proc contains*[A, B](t: OrderedTableRef[A, B], key: A): bool = return hasKey[A, B](t, key) 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``. + ## Returns true if `key` is in the table, otherwise inserts `value`. ## ## See also: ## * `hasKey proc<#hasKey,OrderedTableRef[A,B],A>`_ @@ -1911,8 +1911,8 @@ proc hasKeyOrPut*[A, B](t: var 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: @@ -1930,8 +1930,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 @@ -1948,7 +1948,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: @@ -1968,7 +1968,7 @@ 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 @@ -1977,7 +1977,7 @@ proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} = 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. + ## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists. ## ## **This can introduce duplicate keys into the table!** ## @@ -1986,7 +1986,7 @@ proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: sink B) {.deprecated: 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 @@ -2000,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: @@ -2037,14 +2037,14 @@ proc clear*[A, B](t: OrderedTableRef[A, B]) = proc sort*[A, B](t: OrderedTableRef[A, B], cmp: proc (x, y: (A, B)): int, order = SortOrder.Ascending) = - ## Sorts ``t`` according to the function ``cmp``. + ## 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 algorithm + import std/[algorithm] var a = newOrderedTable[char, int]() for i, c in "cab": a[c] = 10*i @@ -2057,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 @@ -2078,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: @@ -2109,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: @@ -2131,7 +2131,7 @@ iterator mpairs*[A, B](t: OrderedTableRef[A, B]): (A, var B) = assert(len(t) == L, "the length of the table changed while iterating over it") iterator keys*[A, B](t: OrderedTableRef[A, B]): A = - ## Iterates over any key in the table ``t`` in insertion order. + ## Iterates over any key in the table `t` in insertion order. ## ## See also: ## * `pairs iterator<#pairs.i,OrderedTableRef[A,B]>`_ @@ -2152,7 +2152,7 @@ iterator keys*[A, B](t: OrderedTableRef[A, B]): A = assert(len(t) == L, "the length of the table changed while iterating over it") iterator values*[A, B](t: OrderedTableRef[A, B]): B = - ## Iterates over any value in the table ``t`` in insertion order. + ## Iterates over any value in the table `t` in insertion order. ## ## See also: ## * `pairs iterator<#pairs.i,OrderedTableRef[A,B]>`_ @@ -2172,7 +2172,7 @@ iterator values*[A, B](t: OrderedTableRef[A, B]): 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: @@ -2265,19 +2265,18 @@ proc initCountTable*[A](initialSize = defaultInitialSize): CountTable[A] = 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) 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 @@ -2290,7 +2289,7 @@ 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 @@ -2308,7 +2307,7 @@ proc `[]=`*[A](t: var CountTable[A], key: A, val: int) = insertImpl() proc inc*[A](t: var CountTable[A], key: A, val = 1) = - ## Increments ``t[key]`` by ``val`` (default: 1). + ## Increments `t[key]` by `val` (default: 1). runnableExamples: var a = toCountTable("aab") a.inc('a') @@ -2326,11 +2325,11 @@ proc inc*[A](t: var CountTable[A], key: A, val = 1) = insertImpl() proc len*[A](t: CountTable[A]): int = - ## Returns the number of keys in ``t``. + ## Returns the number of keys in `t`. result = t.counter 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]>`_ @@ -2343,7 +2342,7 @@ 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]>`_ @@ -2355,7 +2354,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` @@ -2368,12 +2367,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 @@ -2382,7 +2381,7 @@ proc getOrDefault*[A](t: CountTable[A], key: A; default: int = 0): int = ctget(t, key, default) 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. ## ## See also: ## * `pop proc<#pop,CountTable[A],A,int>`_ @@ -2399,9 +2398,9 @@ proc del*[A](t: var CountTable[A], key: A) {.since: (1, 1).} = delImplNoHCode(cntMakeEmpty, cntCellEmpty, cntCellHash) 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. ## ## See also: @@ -2438,13 +2437,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 algorithm, sequtils + import std/[algorithm, sequtils] var a = toCountTable("abracadabra") doAssert a == "aaaaabbrrcd".toCountTable a.sort() @@ -2482,18 +2481,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]>`_ @@ -2526,7 +2525,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: @@ -2545,7 +2544,7 @@ iterator mpairs*[A](t: var CountTable[A]): (A, var int) = assert(len(t) == L, "the length of the table changed while iterating over it") iterator keys*[A](t: CountTable[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]>`_ @@ -2563,7 +2562,7 @@ iterator keys*[A](t: CountTable[A]): 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]>`_ @@ -2581,7 +2580,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: @@ -2623,14 +2622,14 @@ proc newCountTable*[A](initialSize = defaultInitialSize): CountTableRef[A] = 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`` + ## 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) 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 @@ -2643,7 +2642,7 @@ 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 @@ -2653,7 +2652,7 @@ proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) = 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') @@ -2662,21 +2661,21 @@ proc inc*[A](t: CountTableRef[A], key: A, val = 1) = 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) + ## 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) + ## 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` @@ -2688,12 +2687,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 @@ -2702,11 +2701,11 @@ 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. ## ## See also: ## * `pop proc<#pop,CountTableRef[A],A,int>`_ @@ -2714,9 +2713,9 @@ 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. ## ## See also: @@ -2740,7 +2739,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]) = @@ -2755,13 +2754,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 @@ -2769,7 +2768,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]>`_ @@ -2802,7 +2801,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: @@ -2821,7 +2820,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]>`_ @@ -2839,7 +2838,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]>`_ @@ -2857,7 +2856,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]>`_ diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index 57b8541038..4a3f47e925 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -440,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: @@ -461,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 diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index 04e5e8e56d..b9371c1e17 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -7,106 +7,155 @@ # distribution, for details about the copyright. # -## This module implements complex numbers. -## Complex numbers are currently implemented as generic on a 64-bit or 32-bit float. +## 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) {.push checks: off, line_dir: off, stack_trace: off, debugger: off.} # the user does not want to trace a part of the standard library! -import math +import std/math type Complex*[T: SomeFloat] = object - re*, im*: T ## A complex number, consisting of a real and an imaginary part. + re*, im*: T Complex64* = Complex[float64] - ## Alias for a pair of 64-bit floats. + ## Alias for a complex number using 64-bit floats. Complex32* = Complex[float32] - ## Alias for a pair of 32-bit floats. + ## Alias for a complex number using 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`. result.re = re result.im = im -func complex32*(re: float32; im: float32 = 0.0): Complex[float32] = +func complex32*(re: float32; im: float32 = 0.0): Complex32 = + ## Returns a `Complex32` with real part `re` and imaginary part `im`. result.re = re result.im = im -func complex64*(re: float64; im: float64 = 0.0): Complex[float64] = +func complex64*(re: float64; im: float64 = 0.0): Complex64 = + ## Returns a `Complex64` with real part `re` and imaginary part `im`. result.re = re result.im = im -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) +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)`). func abs*[T](z: Complex[T]): T = - ## Returns the distance from (0,0) to ``z``. + ## Returns the absolute value of `z`, + ## that is the distance from (0, 0) to `z`. result = hypot(z.re, z.im) func abs2*[T](z: Complex[T]): T = - ## Returns the squared distance from (0,0) to ``z``. - result = z.re*z.re + z.im*z.im + ## 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 conjugate*[T](z: Complex[T]): Complex[T] = - ## Conjugates of complex number ``z``. + ## Returns the complex conjugate of `z` (`complex(z.re, -z.im)`). result.re = z.re result.im = -z.im func inv*[T](z: Complex[T]): Complex[T] = - ## Multiplicatives inverse of complex number ``z``. + ## Returns the multiplicative inverse of `z` (`1/z`). conjugate(z) / abs2(z) -func `==` *[T](x, y: Complex[T]): bool = - ## Compares two complex numbers ``x`` and ``y`` for equality. +func `==`*[T](x, y: Complex[T]): bool = + ## Compares two complex numbers for equality. result = x.re == y.re and x.im == y.im -func `+` *[T](x: T; y: Complex[T]): Complex[T] = +func `+`*[T](x: T; y: Complex[T]): Complex[T] = ## Adds 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] = +func `+`*[T](x: Complex[T]; y: T): Complex[T] = ## Adds a complex number to a real number. result.re = x.re + y result.im = x.im -func `+` *[T](x, y: Complex[T]): Complex[T] = +func `+`*[T](x, y: Complex[T]): Complex[T] = ## Adds two complex numbers. result.re = x.re + y.re result.im = x.im + y.im -func `-` *[T](z: Complex[T]): Complex[T] = +func `-`*[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] = +func `-`*[T](x: T; y: Complex[T]): Complex[T] = ## Subtracts a complex number from a real number. - x + (-y) + result.re = x - y.re + result.im = -y.im -func `-` *[T](x: Complex[T]; y: T): Complex[T] = +func `-`*[T](x: Complex[T]; y: T): Complex[T] = ## Subtracts a real number from a complex number. result.re = x.re - y result.im = x.im -func `-` *[T](x, y: Complex[T]): Complex[T] = +func `-`*[T](x, y: Complex[T]): Complex[T] = ## Subtracts two complex numbers. result.re = x.re - y.re result.im = x.im - y.im -func `/` *[T](x: Complex[T]; y: T): Complex[T] = - ## Divides complex number ``x`` by real number ``y``. +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. result.re = x.re / y result.im = x.im / y -func `/` *[T](x: T; y: Complex[T]): Complex[T] = - ## Divides real number ``x`` by complex number ``y``. +func `/`*[T](x: T; y: Complex[T]): Complex[T] = + ## Divides a real number by a complex number. result = x * inv(y) -func `/` *[T](x, y: Complex[T]): Complex[T] = - ## Divides ``x`` by ``y``. +func `/`*[T](x, y: Complex[T]): Complex[T] = + ## Divides two complex numbers. var r, den: T if abs(y.re) < abs(y.im): r = y.re / y.im @@ -119,45 +168,32 @@ func `/` *[T](x, y: Complex[T]): Complex[T] = result.re = (x.re + r * x.im) / den result.im = (x.im - r * x.re) / den -func `*` *[T](x: T; y: Complex[T]): Complex[T] = - ## Multiplies a real number and 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 ``x`` with ``y``. - result.re = x.re * y.re - x.im * y.im - result.im = x.im * y.re + x.re * y.im - - -func `+=` *[T](x: var Complex[T]; y: Complex[T]) = - ## Adds ``y`` to ``x``. +func `+=`*[T](x: var Complex[T]; y: Complex[T]) = + ## Adds `y` to `x`. x.re += y.re x.im += y.im -func `-=` *[T](x: var Complex[T]; y: Complex[T]) = - ## Subtracts ``y`` from ``x``. +func `-=`*[T](x: var Complex[T]; y: Complex[T]) = + ## Subtracts `y` from `x`. x.re -= y.re x.im -= y.im -func `*=` *[T](x: var Complex[T]; y: Complex[T]) = - ## Multiplies ``y`` to ``x``. +func `*=`*[T](x: var Complex[T]; y: Complex[T]) = + ## Multiplies `x` by `y`. 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. +func `/=`*[T](x: var Complex[T]; y: Complex[T]) = + ## Divides `x` by `y` in place. x = x / y func sqrt*[T](z: Complex[T]): Complex[T] = - ## Square root for a complex number ``z``. + ## Computes the + ## ([principal](https://en.wikipedia.org/wiki/Square_root#Principal_square_root_of_a_complex_number)) + ## square root of a complex number `z`. var x, y, w, r: T if z.re == 0.0 and z.im == 0.0: @@ -180,28 +216,36 @@ func sqrt*[T](z: Complex[T]): Complex[T] = result.re = z.im / (result.im + result.im) func exp*[T](z: Complex[T]): Complex[T] = - ## ``e`` raised to the power ``z``. - var + ## Computes the exponential function (`e^z`). + let 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 natural log of ``z``. + ## Returns the + ## ([principal value](https://en.wikipedia.org/wiki/Complex_logarithm#Principal_value) + ## of the) natural logarithm of `z`. result.re = ln(abs(z)) result.im = arctan2(z.im, z.re) func log10*[T](z: Complex[T]): Complex[T] = - ## Returns the log base 10 of ``z``. + ## Returns the logarithm base 10 of `z`. + ## + ## **See also:** + ## * `ln func<#ln,Complex[T]>`_ result = ln(z) / ln(10.0) func log2*[T](z: Complex[T]): Complex[T] = - ## Returns the log base 2 of ``z``. + ## Returns the logarithm base 2 of `z`. + ## + ## **See also:** + ## * `ln func<#ln,Complex[T]>`_ result = ln(z) / ln(2.0) func pow*[T](x, y: Complex[T]): Complex[T] = - ## ``x`` raised to the power ``y``. + ## `x` raised to the power of `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 @@ -214,7 +258,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: - var + let rho = abs(x) theta = arctan2(x.im, x.re) s = pow(rho, y.re) * exp(-y.im * theta) @@ -223,126 +267,140 @@ func pow*[T](x, y: Complex[T]): Complex[T] = result.im = s * sin(r) func pow*[T](x: Complex[T]; y: T): Complex[T] = - ## Complex number ``x`` raised to the power ``y``. + ## The complex number `x` raised to the power of the real number `y`. pow(x, complex[T](y)) func sin*[T](z: Complex[T]): Complex[T] = - ## Returns the sine of ``z``. + ## 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``. + ## 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``. + ## 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``. + ## 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``. + ## Returns the tangent of `z`. result = sin(z) / cos(z) func arctan*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse tangent of ``z``. + ## 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``. + ## Returns the cotangent of `z`. result = cos(z)/sin(z) func arccot*[T](z: Complex[T]): Complex[T] = - ## Returns the inverse cotangent of ``z``. + ## 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``. + ## 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``. + ## 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``. + ## 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``. + ## 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``. + ## 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``. + ## 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``. + ## 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``. + ## 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``. + ## 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``. + ## Returns the inverse hyperbolic tangent of `z`. result = T(0.5) * (ln((T(1.0)+z) / (T(1.0)-z))) -func 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``. - 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``. - result = T(2.0) / (exp(z) - exp(-z)) - -func 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 coth*[T](z: Complex[T]): Complex[T] = - ## Returns the hyperbolic cotangent of ``z``. + ## 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``. + ## 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`. + result = T(2.0) / (exp(z) + exp(-z)) + +func 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`. + result = T(2.0) / (exp(z) - exp(-z)) + +func 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 of ``z``. + ## Returns the phase (or argument) of `z`, that is the angle in polar representation. + ## + ## | `result = arctan2(z.im, z.re)` arctan2(z.im, z.re) func polar*[T](z: Complex[T]): tuple[r, phi: T] = - ## Returns ``z`` in polar coordinates. + ## Returns `z` in polar coordinates. + ## + ## | `result.r = abs(z)` + ## | `result.phi = phase(z)` + ## + ## **See also:** + ## * `rect func<#rect,T,T>`_ for the inverse operation (r: abs(z), phi: phase(z)) func rect*[T](r, phi: T): Complex[T] = - ## Returns the complex number with polar coordinates ``r`` and ``phi``. + ## Returns the complex number with polar coordinates `r` and `phi`. ## - ## | ``result.re = r * cos(phi)`` - ## | ``result.im = r * sin(phi)`` + ## | `result.re = r * cos(phi)` + ## | `result.im = r * sin(phi)` + ## + ## **See also:** + ## * `polar func<#polar,Complex[T]>`_ for the inverse operation complex(r * cos(phi), r * sin(phi)) func `$`*(z: Complex): string = - ## Returns ``z``'s string representation as ``"(re, im)"``. + ## Returns `z`'s string representation as `"(re, im)"`. + runnableExamples: + doAssert $complex(1.0, 2.0) == "(1.0, 2.0)" + result = "(" & $z.re & ", " & $z.im & ")" {.pop.} diff --git a/lib/pure/concurrency/atomics.nim b/lib/pure/concurrency/atomics.nim index 8959441773..bdf1e8cc21 100644 --- a/lib/pure/concurrency/atomics.nim +++ b/lib/pure/concurrency/atomics.nim @@ -51,8 +51,6 @@ runnableExamples: 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. @@ -338,7 +336,7 @@ else: {.pop.} proc load*[T: Trivial](location: var Atomic[T]; order: MemoryOrder = moSequentiallyConsistent): T {.inline.} = - cast[T](atomic_load_explicit[nonAtomicType(T), type(location.value)](addr(location.value), order)) + cast[T](atomic_load_explicit[nonAtomicType(T), typeof(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.} = diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index 3e5695360d..ee43b8e11f 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -7,23 +7,27 @@ # distribution, for details about the copyright. # -## This module implements procs to determine the number of CPUs / cores. +## This module implements a proc to determine the number of CPUs / cores. + +runnableExamples: + doAssert countProcessors() > 0 + include "system/inclrtl" -when not defined(windows): +when defined(posix) and not (defined(macosx) or defined(bsd)): import posix 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 @@ -47,7 +51,7 @@ 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 @@ -95,8 +99,3 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = else: result = sysconf(SC_NPROCESSORS_ONLN) if result <= 0: result = 0 - - -runnableExamples: - block: - doAssert countProcessors() > 0 diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index a4460165d7..905e668ce9 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -7,15 +7,16 @@ # distribution, for details about the copyright. # -## Implements Nim's `spawn `_. -## -## **See also:** -## * `threads module `_ -## * `channels module `_ -## * `locks module `_ -## * `asyncdispatch module `_ +## Implements Nim's `parallel & spawn statements `_. ## ## Unstable API. +## +## See also +## ======== +## * `threads module `_ for basic thread support +## * `channels module `_ for message passing support +## * `locks module `_ for locks and condition variables +## * `asyncdispatch module `_ for asynchronous IO when not compileOption("threads"): {.error: "Threadpool requires --threads:on option.".} @@ -101,7 +102,7 @@ type cv: Semaphore idx: int - FlowVarBase* = ref FlowVarBaseObj ## Untyped base class for ``FlowVar[T]``. + FlowVarBase* = ref FlowVarBaseObj ## Untyped base class for `FlowVar[T] <#FlowVar>`_. FlowVarBaseObj = object of RootObj ready, usesSemaphore, awaited: bool cv: Semaphore # for 'blockUntilAny' support @@ -114,7 +115,7 @@ type FlowVarObj[T] = object of FlowVarBaseObj blob: T - FlowVar*{.compilerproc.}[T] = ref FlowVarObj[T] ## A data flow variable. + FlowVar*[T] {.compilerproc.} = ref FlowVarObj[T] ## A data flow variable. ToFreeQueue = object len: int @@ -138,7 +139,7 @@ type const threadpoolWaitMs {.intdefine.}: int = 100 proc blockUntil*(fv: var FlowVarBaseObj) = - ## Waits until the value for the ``fv`` arrives. + ## Waits until the value for `fv` arrives. ## ## Usually it is not necessary to call this explicitly. if fv.usesSemaphore and not fv.awaited: @@ -230,12 +231,12 @@ proc nimFlowVarSignal(fv: FlowVarBase) {.compilerproc.} = signal(fv.cv) proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) = - ## Blocks until the ``fv`` is available and then passes its value - ## to ``action``. + ## Blocks until `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 `^ proc <#^,FlowVar[T]>`_. + ## 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) @@ -266,15 +267,15 @@ proc `^`*[T](fv: FlowVar[T]): T = 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 +296,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 @@ -315,7 +316,7 @@ const MaxDistinguishedThread* {.intdefine.} = 32 ## Maximum number of "distinguished" threads. type - ThreadId* = range[0..MaxDistinguishedThread-1] + ThreadId* = range[0..MaxDistinguishedThread-1] ## A thread identifier. var currentPoolSize: int @@ -402,7 +403,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`` (256). + ## is `MaxThreadPoolSize <#MaxThreadPoolSize>`_. maxPoolSize = size if currentPoolSize > maxPoolSize: for i in maxPoolSize..currentPoolSize-1: @@ -442,43 +443,43 @@ proc setup() = for i in 0..`_ instead. result = gSomeReady.counter > 0 proc spawn*(call: sink typed): void {.magic: "Spawn".} - ## Always spawns a new task, so that the ``call`` is never executed on + ## 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 a - ## return type that is either ``void`` or compatible with ``FlowVar[T]``. + ## `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]`. proc pinnedSpawn*(id: ThreadId; call: sink 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. + ## 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 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 a proc call `p(...)` where `p` is gcsafe and has a + ## return type that is either `void` or compatible with `FlowVar[T]`. template spawnX*(call) = ## 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 proc <#spawn,sinktyped>`_ in order to - ## not block the producer for an unknown amount of time. + ## Usually, it is advised to use the `spawn proc <#spawn,sinktyped>`_ + ## 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 a - ## return type that is either 'void' or compatible with ``FlowVar[T]``. + ## `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]`. (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. @@ -585,7 +586,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 7e686d44fa..8d9cc0c958 100644 --- a/lib/pure/cookies.nim +++ b/lib/pure/cookies.nim @@ -9,18 +9,25 @@ ## This module implements helper procs for parsing Cookies. -import strtabs, times +import std/[strtabs, times, options] + + +type + SameSite* {.pure.} = enum ## The SameSite cookie attribute. + ## `Default` means that `setCookie` + ## proc will not set `SameSite` attribute. + Default, None, Lax, Strict 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. - ## - ## Example: - ## - ## .. code-block::Nim - ## doAssert parseCookies("a=1; foo=bar") == {"a": 1, "foo": "bar"}.newStringTable + runnableExamples: + import std/strtabs + let cookieJar = parseCookies("a=1; foo=bar") + assert cookieJar["a"] == "1" + assert cookieJar["foo"] == "bar" result = newStringTable(modeCaseInsensitive) var i = 0 @@ -39,9 +46,10 @@ proc parseCookies*(s: string): StringTableRef = proc setCookie*(key, value: string, domain = "", path = "", expires = "", noName = false, - secure = false, httpOnly = false): string = + secure = false, httpOnly = false, + maxAge = none(int), sameSite = SameSite.Default): string = ## Creates a command in the format of - ## ``Set-Cookie: key=value; Domain=...; ...`` + ## `Set-Cookie: key=value; Domain=...; ...` result = "" if not noName: result.add("Set-Cookie: ") result.add key & "=" & value @@ -50,12 +58,19 @@ 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): string = + secure = false, httpOnly = false, + maxAge = none(int), sameSite = SameSite.Default): string = ## Creates a command in the format of - ## ``Set-Cookie: key=value; Domain=...; ...`` - return setCookie(key, value, domain, path, + ## `Set-Cookie: key=value; Domain=...; ...` + result = setCookie(key, value, domain, path, format(expires.utc, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"), - noname, secure, httpOnly) + noname, secure, httpOnly, maxAge, sameSite) diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index 2a702b65b0..21675928d6 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -32,6 +32,10 @@ import lists include system/timers 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.} @@ -59,7 +63,7 @@ else: const coroBackend = CORO_BACKEND_UCONTEXT when coroBackend == CORO_BACKEND_FIBERS: - import windows.winlean + import windows/winlean type Context = pointer @@ -185,7 +189,8 @@ proc initialize() = ctx.coroutines = initDoublyLinkedList[CoroutinePtr]() ctx.loop = Coroutine() ctx.loop.state = CORO_EXECUTING - ctx.ncbottom = GC_getActiveStack() + when not useOrcArc: + ctx.ncbottom = GC_getActiveStack() when coroBackend == CORO_BACKEND_FIBERS: ctx.loop.execContext = ConvertThreadToFiberEx(nil, FIBER_FLAG_FLOAT_SWITCH) @@ -195,7 +200,8 @@ 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. - GC_setActiveStack(current.stack.bottom) + when not useOrcArc: + GC_setActiveStack(current.stack.bottom) nimGC_setStackBottom(current.stack.bottom) var frame = getFrameState() block: @@ -218,11 +224,12 @@ proc switchTo(current, to: CoroutinePtr) = {.error: "Invalid coroutine backend set.".} # Execution was just resumed. Restore frame information and set active stack. setFrameState(frame) - GC_setActiveStack(current.stack.bottom) + when not useOrcArc: + GC_setActiveStack(current.stack.bottom) nimGC_setStackBottom(ctx.ncbottom) 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 @@ -241,9 +248,10 @@ proc runCurrentTask() = # 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. - GC_addStack(sp) - # Activate current stack because we are executing in a new coroutine. - GC_setActiveStack(sp) + when not useOrcArc: + 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 @@ -312,7 +320,8 @@ proc run*() = next = ctx.current.next current.reference.coro = nil ctx.coroutines.remove(ctx.current) - GC_removeStack(current.stack.bottom) + when not useOrcArc: + GC_removeStack(current.stack.bottom) when coroBackend == CORO_BACKEND_FIBERS: DeleteFiber(current.execContext) else: @@ -326,9 +335,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 601508e2e5..0eae00fbaa 100644 --- a/lib/pure/cstrutils.nim +++ b/lib/pure/cstrutils.nim @@ -7,95 +7,116 @@ # 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" +include system/inclrtl +import std/private/strimpl -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): - proc startsWith*(s, prefix: cstring): bool {.noSideEffect, - importjs: "#.startsWith(#)".} + func jsStartsWith(s, prefix: cstring): bool {.importjs: "#.startsWith(#)".} + func jsEndsWith(s, suffix: cstring): bool {.importjs: "#.endsWith(#)".} - proc endsWith*(s, suffix: cstring): bool {.noSideEffect, - importjs: "#.endsWith(#)".} - - # JS string has more operations that might warrant its own module: - # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String -else: - proc startsWith*(s, prefix: cstring): bool {.noSideEffect, - rtl, extern: "csuStartsWith".} = - ## Returns true if ``s`` starts with ``prefix``. - ## - ## If ``prefix == ""`` true is returned. - ## - ## JS backend uses native ``String.prototype.startsWith``. - var i = 0 - while true: - if prefix[i] == '\0': return true - if s[i] != prefix[i]: return false - inc(i) - proc endsWith*(s, suffix: cstring): bool {.noSideEffect, - rtl, extern: "csuEndsWith".} = - ## Returns true if ``s`` ends with ``suffix``. - ## - ## If ``suffix == ""`` true is returned. - ## - ## JS backend uses native ``String.prototype.endsWith``. - 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: +func startsWith*(s, prefix: cstring): bool {.rtl, extern: "csuStartsWith".} = + ## Returns true if `s` starts with `prefix`. ## - ## | 0 if a == b - ## | < 0 if a < b - ## | > 0 if a > b - ## - ## Not supported for JS backend, use `strutils.cmpIgnoreStyle - ## `_ instead. - 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) + ## 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"") -proc cmpIgnoreCase*(a, b: cstring): int {.noSideEffect, - rtl, extern: "csuCmpIgnoreCase".} = + 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`. + ## + ## 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"") + + 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 + +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".} = ## Compares two strings in a case insensitive manner. Returns: - ## - ## | 0 if a == b - ## | < 0 if a < b - ## | > 0 if a > b - ## - ## Not supported for JS backend, use `strutils.cmpIgnoreCase - ## `_ instead. - 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 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) diff --git a/lib/pure/db_common.nim b/lib/pure/db_common.nim index 96c13c003c..852c8e1c39 100644 --- a/lib/pure/db_common.nim +++ b/lib/pure/db_common.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -## Common datatypes and definitions for all ``db_*.nim`` ( +## Common datatypes and definitions for all `db_*.nim` ( ## `db_mysql `_, `db_postgres `_, ## and `db_sqlite `_) modules. @@ -86,7 +86,7 @@ type 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"`` + ## `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. diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index 8debbf9c8a..2b119b92cc 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 install libblas-dev +## sudo apt-get install 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 strutils import contains, toLowerAscii +from std/strutils import contains, toLowerAscii when not defined(nimscript): - from osproc import execProcess - from os import existsEnv + from std/osproc import execProcess + from std/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 @@ -133,8 +133,7 @@ type const - LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware, - Distribution.ArchLinux} + LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware, Distribution.ArchLinux} # we cache the result of the 'cmdRelease' # execution for faster platform detections. @@ -157,8 +156,7 @@ proc detectOsWithAllCmd(d: Distribution): bool = proc detectOsImpl(d: Distribution): bool = case d - of Distribution.Windows: ## some version of Windows - result = defined(windows) + of Distribution.Windows: result = defined(windows) of Distribution.Posix: result = defined(posix) of Distribution.MacOSX: result = defined(macosx) of Distribution.Linux: result = defined(linux) @@ -183,8 +181,8 @@ proc detectOsImpl(d: Distribution): bool = of Distribution.ArchLinux: result = "arch" in osReleaseID() of Distribution.NixOS: - result = existsEnv("NIX_BUILD_TOP") or existsEnv("__NIXOS_SET_ENVIRONMENT_DONE") # 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: @@ -200,8 +198,8 @@ proc detectOsImpl(d: Distribution): bool = result = false 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) @@ -209,7 +207,7 @@ when not defined(nimble): var foreignDeps: seq[string] = @[] proc foreignCmd*(cmd: string; requiresSudo = false) = - ## Registers a foreign command to the intern list of commands + ## Registers a foreign command to the internal list of commands ## that can be queried later. let c = (if requiresSudo: "sudo " else: "") & cmd when defined(nimble): @@ -218,11 +216,11 @@ proc foreignCmd*(cmd: string; requiresSudo = false) = foreignDeps.add(c) proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) = - ## Returns the distro's native command line to install 'foreignPackageName' + ## Returns the distro's native command to install `foreignPackageName` ## and whether it requires root/admin rights. let p = foreignPackageName when defined(windows): - result = ("Chocolatey install " & p, false) + result = ("choco install " & p, false) elif defined(bsd): result = ("ports install " & p, true) elif defined(linux): @@ -261,17 +259,12 @@ 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 the package name + ## Registers `foreignPackageName` to the internal list of foreign deps. + ## It is your job to ensure that the package name is correct. 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 42d13535f8..3e1d84729d 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 ## ======== @@ -24,7 +24,7 @@ ## ## .. code-block::nim ## -## import dynlib +## import std/dynlib ## ## type ## greetFunction = proc(): cstring {.gcsafe, stdcall.} @@ -99,7 +99,7 @@ proc libCandidates*(s: string, dest: var seq[string]) = proc loadLibPattern*(pattern: string, globalSymbols = false): LibHandle = ## loads a library with name matching `pattern`, similar to what `dynlib` ## 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: diff --git a/lib/pure/fenv.nim b/lib/pure/fenv.nim index abddaf4cbd..ddb6a1a0c3 100644 --- a/lib/pure/fenv.nim +++ b/lib/pure/fenv.nim @@ -9,8 +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): +when defined(posix) and not defined(genode): {.passl: "-lm".} var @@ -35,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 @@ -128,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 @@ -154,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 diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 667f27e95d..c526c976fe 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -10,51 +10,68 @@ ## 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): int = + 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 + +## **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 -## -## 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 +## See also +## ======== +## * `md5 module `_ for the MD5 checksum algorithm +## * `base64 module `_ for a Base64 encoder and decoder +## * `std/sha1 module `_ for a SHA-1 encoder and decoder ## * `tables module `_ for hash tables import std/private/since type Hash* = int ## A hash value. Hash tables using these values should - ## always have a size of a power of two and can use the ``and`` - ## operator instead of ``mod`` for truncation of the hash value. + ## 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. 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 @@ -65,7 +82,7 @@ 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) @@ -90,7 +107,7 @@ proc hiXorLoFallback64(a, b: uint64): uint64 {.inline.} = return hi xor lo proc hiXorLo(a, b: uint64): uint64 {.inline.} = - # Xor of high & low 8B of full 16B product + # XOR of the high & low 8 bytes of the full 16 byte product. when nimvm: result = hiXorLoFallback64(a, b) # `result =` is necessary here. else: @@ -106,10 +123,42 @@ proc hiXorLo(a, b: uint64): uint64 {.inline.} = 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 8B int. https://github.com/rurban/smhasher has 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))``. + ## 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 @@ -121,22 +170,10 @@ proc hashWangYi1*(x: int64|uint64|Hash): Hash {.inline.} = result = cast[Hash](h(x)) else: when defined(js): - asm """ - if (typeof BigInt == 'undefined') { - `result` = `x`; // For Node < 10.4, etc. we do the old identity hash - } else { // Otherwise we match the low 32-bits of C/C++ hash - function hi_xor_lo_js(a, b) { - const prod = BigInt(a) * BigInt(b); - const mask = (BigInt(1) << BigInt(64)) - BigInt(1); - return (prod >> BigInt(64)) ^ (prod & mask); - } - const P0 = BigInt(0xa0761d64)<`_ ## * `hashIgnoreCase <#hashIgnoreCase,string>`_ runnableExamples: @@ -322,17 +369,20 @@ proc hash*(x: cstring): Hash = inc i result = !$result else: - when not defined(js) and defined(nimToOpenArrayCString): - murmurHash(toOpenArrayByte(x, 0, x.high)) + when nimvm: + hashVmImpl(x, 0, high(x)) else: - let xx = $x - murmurHash(toOpenArrayByte(xx, 0, high(xx))) + when not defined(js) and defined(nimToOpenArrayCString): + murmurHash(toOpenArrayByte(x, 0, x.high)) + else: + let xx = $x + murmurHash(toOpenArrayByte(xx, 0, high(xx))) 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) @@ -348,9 +398,9 @@ proc hash*(sBuf: string, sPos, ePos: int): Hash = proc hashIgnoreStyle*(x: string): Hash = ## Efficient hashing of strings; style is ignored. ## - ## **Note:** This uses different hashing algorithm than `hash(string)`. + ## **Note:** This uses a different hashing algorithm than `hash(string)`. ## - ## See also: + ## **See also:** ## * `hashIgnoreCase <#hashIgnoreCase,string>`_ runnableExamples: doAssert hashIgnoreStyle("aBr_aCa_dAB_ra") == hashIgnoreStyle("abracadabra") @@ -374,10 +424,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 different hashing algorithm than `hash(string)`. + ## **Note:** This uses a 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) @@ -398,9 +448,9 @@ proc hashIgnoreStyle*(sBuf: string, sPos, ePos: int): Hash = proc hashIgnoreCase*(x: string): Hash = ## Efficient hashing of strings; case is ignored. ## - ## **Note:** This uses different hashing algorithm than `hash(string)`. + ## **Note:** This uses a different hashing algorithm than `hash(string)`. ## - ## See also: + ## **See also:** ## * `hashIgnoreStyle <#hashIgnoreStyle,string>`_ runnableExamples: doAssert hashIgnoreCase("ABRAcaDABRA") == hashIgnoreCase("abRACAdabra") @@ -418,10 +468,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 different hashing algorithm than `hash(string)`. + ## **Note:** This uses a 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) @@ -435,15 +485,27 @@ proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash = result = !$h -proc hash*[T: tuple](x: T): Hash = - ## Efficient hashing of tuples. +proc hash*[T: tuple | object](x: T): Hash = + ## Efficient hashing of tuples and objects. + ## There must be a `hash` proc defined for each of the field types. + runnableExamples: + 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")) 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: @@ -459,8 +521,9 @@ 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) @@ -482,6 +545,7 @@ 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`. for it in items(x): result = result !& hash(it) result = !$result diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index acec058323..04b1c5202d 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. ## @@ -113,236 +113,233 @@ proc xmlCheckedTag*(argsList: NimNode, tag: string, optAttr = "", reqAttr = "", result.add(newStrLitNode("")) - when compiles(nestList(ident"&", result)): - result = nestList(ident"&", result) - else: - result = nestList(!"&", result) + result = nestList(ident"&", 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. + ## 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. + ## Generates the HTML `iframe` element. result = xmlCheckedTag(e, "iframe", "src srcdoc name sandbox width height loading" & commonAttr) macro img*(e: varargs[untyped]): untyped = - ## Generates the HTML ``img`` element. + ## Generates the HTML `img` element. result = xmlCheckedTag(e, "img", "crossorigin usemap ismap height width loading" & 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 " & @@ -350,397 +347,401 @@ 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 " & @@ -748,38 +749,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 4b305cfd63..c572146a70 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 htmlparser -## import xmltree # To use '$' for XmlNode -## import strtabs # To access XmlAttributes -## import os # To use splitFile -## import strutils # To use cmpIgnoreCase +## 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 ## ## proc transformHyperlinks() = ## let html = loadHtml("input.html") @@ -55,129 +55,129 @@ 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* = [ @@ -351,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) @@ -365,7 +365,7 @@ proc htmlTag*(s: string): HtmlTag = proc runeToEntity*(rune: Rune): string = ## converts a Rune to its numeric HTML entity equivalent. runnableExamples: - import unicode + import std/unicode doAssert runeToEntity(Rune(0)) == "" doAssert runeToEntity(Rune(-1)) == "" doAssert runeToEntity("Ü".runeAt(0)) == "#220" @@ -374,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 unicode + import std/unicode doAssert entityToRune("") == Rune(0) doAssert entityToRune("a") == Rune(0) doAssert entityToRune("gt") == ">".runeAt(0) @@ -395,7 +395,7 @@ proc entityToRune*(entity: string): Rune = of 'x', 'X': # not case sensitive here try: runeValue = parseHexInt(entity[2..^1]) except: discard - else: discard # other entities are not defined with prefix ``#`` + 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 @@ -1867,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: @@ -1905,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 @@ -1914,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)) @@ -2012,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, @@ -2036,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 3093f55648..14bcfd2fb8 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -14,18 +14,18 @@ ## ==================== ## ## This example uses HTTP GET to retrieve -## ``http://google.com``: +## `http://google.com`: ## ## .. code-block:: Nim -## import httpclient +## import std/httpclient ## var client = newHttpClient() ## echo client.getContent("http://google.com") ## ## The same action can also be performed asynchronously, simply use the -## ``AsyncHttpClient``: +## `AsyncHttpClient`: ## ## .. code-block:: Nim -## import asyncdispatch, httpclient +## import std/[asyncdispatch, httpclient] ## ## proc asyncProc(): Future[string] {.async.} = ## var client = newAsyncHttpClient() @@ -33,18 +33,18 @@ ## ## 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. +## 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 @@ -56,10 +56,10 @@ ## ## echo client.postContent("http://validator.w3.org/check", multipart=data) ## -## To stream files from disk when performing the request, use ``addFiles``. +## 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. +## **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() @@ -70,11 +70,11 @@ ## 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 httpclient, json +## import std/[httpclient, json] ## ## let client = newHttpClient() ## client.headers = newHttpHeaders({ "Content-Type": "application/json" }) @@ -92,7 +92,7 @@ ## progress of the HTTP request. ## ## .. code-block:: Nim -## import asyncdispatch, httpclient +## import std/[asyncdispatch, httpclient] ## ## proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} = ## echo("Downloaded ", progress, " of ", total) @@ -105,26 +105,26 @@ ## ## 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 ## 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 ...``. +## You will also have to compile with `ssl` defined like so: +## `nim c -d:ssl ...`. ## ## Certificate validation is NOT performed by default. -## This will change in future. +## This will change in the future. ## ## A set of directories and files from the `ssl_certs `_ ## module are scanned to locate CA certificates. @@ -144,12 +144,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 httpclient +## import std/httpclient ## ## let client = newHttpClient(timeout = 42) ## @@ -157,13 +157,13 @@ ## ===== ## ## 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 httpclient +## import std/httpclient ## ## let myProxy = newProxy("http://myproxy.network") ## let client = newHttpClient(proxy = myProxy) @@ -171,7 +171,7 @@ ## Get Proxy URL from environment variables: ## ## .. code-block:: Nim -## import httpclient +## import std/httpclient ## ## var url = "" ## try: @@ -188,26 +188,27 @@ ## 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 httpclient +## import std/httpclient ## ## let client = newHttpClient(maxRedirects = 0) ## import std/private/since -import net, strutils, uri, parseutils, base64, os, mimetypes, streams, - math, random, httpcore, times, tables, streams, std/monotimes -import asyncnet, asyncdispatch, asyncfile -import nativesockets +import std/[ + net, strutils, uri, parseutils, base64, os, mimetypes, + math, random, httpcore, times, tables, streams, monotimes, + asyncnet, asyncdispatch, asyncfile, nativesockets, +] -export httpcore except parseHeader # TODO: The ``except`` doesn't work +export httpcore except parseHeader # TODO: The `except` doesn't work type Response* = ref object @@ -226,10 +227,10 @@ type proc code*(response: Response | AsyncResponse): HttpCode {.raises: [ValueError, OverflowDefect].} = - ## Retrieves the specified response's ``HttpCode``. + ## 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.} = @@ -243,7 +244,7 @@ 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. + ## A `ValueError` exception will be raised if the value is not an integer. var contentLengthHeader = response.headers.getOrDefault("Content-Length") result = contentLengthHeader.parseInt() doAssert(result >= 0 and result <= high(int32)) @@ -253,7 +254,7 @@ proc lastModified*(response: Response | AsyncResponse): DateTime = ## ## 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()) @@ -295,8 +296,8 @@ type ## 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 @@ -321,16 +322,20 @@ proc getDefaultSSL(): SslContext = result = defaultSslContext when defined(ssl): if result == nil: - defaultSslContext = newContext(verifyMode = CVerifyNone) + defaultSslContext = newContext(verifyMode = CVerifyPeer) 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 {.inline.} = - ## Constructs a new ``MultipartData`` object. + ## Constructs a new `MultipartData` object. MultipartData() proc `$`*(data: MultipartData): string {.since: (1, 1).} = @@ -349,10 +354,10 @@ 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. + ## When `useStream` is `false`, the file will be read into memory. ## - ## Raises a ``ValueError`` exception if - ## ``name``, ``filename`` or ``contentType`` contain newline characters. + ## 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: @@ -375,7 +380,7 @@ proc add*(p: MultipartData, name, content: string, filename: string = "", proc add*(p: MultipartData, xs: MultipartEntries): MultipartData {.discardable.} = - ## Add a list of multipart entries to the multipart data ``p``. All values are + ## Add a list of multipart entries to the multipart data `p`. All values are ## added without a filename and without a content type. ## ## .. code-block:: Nim @@ -385,7 +390,7 @@ proc add*(p: MultipartData, xs: MultipartEntries): MultipartData result = p proc newMultipartData*(xs: MultipartEntries): MultipartData = - ## Create a new multipart data object and fill it with the entries ``xs`` + ## Create a new multipart data object and fill it with the entries `xs` ## directly. ## ## .. code-block:: Nim @@ -398,11 +403,11 @@ 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 + ## 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. + ## 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"}) @@ -411,12 +416,12 @@ proc addFiles*(p: MultipartData, xs: openArray[tuple[name, file: 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).string + let content = if useStream: file else: readFile(file) p.add(name, content, fName & ext, contentType, useStream = useStream) result = p proc `[]=`*(p: MultipartData, name, content: string) {.inline.} = - ## Add a multipart entry to the multipart data ``p``. The value is added + ## Add a multipart entry to the multipart data `p`. The value is added ## without a filename and without a content type. ## ## .. code-block:: Nim @@ -425,7 +430,7 @@ proc `[]=`*(p: MultipartData, name, content: string) {.inline.} = proc `[]=`*(p: MultipartData, name: string, file: tuple[name, contentType, content: string]) {.inline.} = - ## Add a file to the multipart data ``p``, specifying filename, contentType + ## Add a file to the multipart data `p`, specifying filename, contentType ## and content manually. ## ## .. code-block:: Nim @@ -451,35 +456,29 @@ proc sendFile(socket: Socket | AsyncSocket, var buffer: string while true: buffer = - when socket is AsyncSocket: (await read(file, chunkSize)).string - else: readStr(file, chunkSize).string + 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", "308"] - for i in items(redirectionNRs): - if status.startsWith(i): - return true - -proc getNewLocation(lastURL: string, headers: HttpHeaders): string = - result = headers.getOrDefault"Location" - if result == "": httpError("location header expected") +proc getNewLocation(lastURL: Uri, headers: HttpHeaders): Uri = + let newLocation = headers.getOrDefault"Location" + if newLocation == "": httpError("location header expected") # Relative URLs. (Not part of the spec, but soon will be.) - 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 + 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 -proc generateHeaders(requestUrl: Uri, httpMethod: string, headers: HttpHeaders, +proc generateHeaders(requestUrl: Uri, httpMethod: HttpMethod, headers: HttpHeaders, proxy: Proxy): string = # GET - let upperMethod = httpMethod.toUpperAscii() - result = upperMethod + result = $httpMethod result.add ' ' if proxy.isNil or requestUrl.scheme == "https": @@ -528,11 +527,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: @@ -558,24 +557,24 @@ proc newHttpClient*(userAgent = defUserAgent, maxRedirects = 5, 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. + ## `sslContext` specifies the SSL context to use for HTTPS requests. ## See `SSL/TLS support <#sslslashtls-support>`_ ## - ## ``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. + ## `headers` specifies the HTTP Headers. runnableExamples: - import asyncdispatch, httpclient, strutils + import std/[asyncdispatch, httpclient, strutils] proc asyncProc(): Future[string] {.async.} = var client = newAsyncHttpClient() @@ -605,18 +604,18 @@ proc newAsyncHttpClient*(userAgent = defUserAgent, maxRedirects = 5, 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. + ## `headers` specifies the HTTP Headers. new result result.headers = headers result.userAgent = userAgent @@ -692,7 +691,7 @@ proc parseChunks(client: HttpClient | AsyncHttpClient): Future[void] {.multisync.} = while true: var chunkSize = 0 - var chunkSizeStr = (await client.socket.recvLine()).string + var chunkSizeStr = await client.socket.recvLine() var i = 0 if chunkSizeStr == "": httpError("Server terminated connection prematurely") @@ -791,9 +790,9 @@ proc parseResponse(client: HttpClient | AsyncHttpClient, while true: linei = 0 when client is HttpClient: - line = (await client.socket.recvLine(client.timeout)).string + line = await client.socket.recvLine(client.timeout) else: - line = (await client.socket.recvLine()).string + line = await client.socket.recvLine() if line == "": # We've been disconnected. client.close() @@ -834,17 +833,22 @@ 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 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) - # do not wait here for the body request to complete + client.parseBodyFut.addCallback do(): + if client.parseBodyFut.failed: + client.bodyStream.fail(client.parseBodyFut.error) proc newConnection(client: HttpClient | AsyncHttpClient, url: Uri) {.multisync.} = @@ -898,7 +902,7 @@ proc newConnection(client: HttpClient | AsyncHttpClient, connectUrl.hostname = url.hostname connectUrl.port = if url.port != "": url.port else: "443" - let proxyHeaderString = generateHeaders(connectUrl, $HttpConnect, + let proxyHeaderString = generateHeaders(connectUrl, HttpConnect, newHttpHeaders(), client.proxy) await client.socket.send(proxyHeaderString) let proxyResp = await parseResponse(client, false) @@ -967,35 +971,39 @@ proc override(fallback, override: HttpHeaders): HttpHeaders = for k, vs in override.table: result[k] = vs -proc requestAux(client: HttpClient | AsyncHttpClient, url, httpMethod: string, - body = "", headers: HttpHeaders = nil, +proc requestAux(client: HttpClient | AsyncHttpClient, url: Uri, + httpMethod: HttpMethod, body = "", headers: HttpHeaders = nil, multipart: MultipartData = nil): Future[Response | AsyncResponse] {.multisync.} = # Helper that actually makes the request. Does not handle redirects. - let requestUrl = parseUri(url) - - if requestUrl.scheme == "": + if url.scheme == "": raise newException(ValueError, "No uri scheme supplied.") - var data: seq[string] - if multipart != nil and multipart.content.len > 0: - data = await client.format(multipart) - elif httpMethod in ["POST", "PATCH", "PUT"] or body.len != 0: - client.headers["Content-Length"] = $body.len - when client is AsyncHttpClient: if not client.parseBodyFut.isNil: # let the current operation finish before making another request await client.parseBodyFut client.parseBodyFut = nil - await newConnection(client, requestUrl) + await newConnection(client, url) let newHeaders = client.headers.override(headers) + + var data: seq[string] + if multipart != nil and multipart.content.len > 0: + data = await client.format(multipart) + else: + # 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 newHeaders.hasKey("user-agent") and client.userAgent.len > 0: newHeaders["User-Agent"] = client.userAgent - let headerString = generateHeaders(requestUrl, httpMethod, newHeaders, + let headerString = generateHeaders(url, httpMethod, newHeaders, client.proxy) await client.socket.send(headerString) @@ -1017,58 +1025,116 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url, httpMethod: string, elif body.len > 0: await client.socket.send(body) - let getBody = httpMethod.toLowerAscii() notin ["head", "connect"] and + let getBody = httpMethod notin {HttpHead, HttpConnect} and client.getBody result = await parseResponse(client, getBody) -proc request*(client: HttpClient | AsyncHttpClient, url: string, - httpMethod: string, body = "", headers: HttpHeaders = nil, +proc request*(client: HttpClient | AsyncHttpClient, url: Uri | string, + httpMethod: HttpMethod | string = HttpGet, body = "", + headers: HttpHeaders = nil, multipart: MultipartData = 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``. + ## 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``. - doAssert(not url.contains({'\c', '\L'}), "url shouldn't contain any newline characters") + ## 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) var lastURL = url for i in 1..client.maxRedirects: - 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, multipart) - lastURL = redirectTo + let statusCode = result.code -proc request*(client: HttpClient | AsyncHttpClient, url: string, - httpMethod = HttpGet, body = "", headers: HttpHeaders = nil, - multipart: MultipartData = 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, multipart) + 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 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) @@ -1076,84 +1142,87 @@ proc responseContent(resp: Response | AsyncResponse): Future[string] {.multisync return await resp.bodyStream.readAll() proc head*(client: HttpClient | AsyncHttpClient, - url: string): Future[Response | AsyncResponse] {.multisync.} = + url: Uri | 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: string): Future[Response | AsyncResponse] {.multisync.} = + url: Uri | 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: string): Future[string] {.multisync.} = + url: Uri | 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: string): Future[Response | AsyncResponse] {.multisync.} = + url: Uri | 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: string): Future[string] {.multisync.} = + url: Uri | 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: string, body = "", +proc post*(client: HttpClient | AsyncHttpClient, url: Uri | 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`. + result = await client.request(url, HttpPost, body, multipart=multipart) -proc postContent*(client: HttpClient | AsyncHttpClient, url: string, body = "", +proc postContent*(client: HttpClient | AsyncHttpClient, url: Uri | 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: string, body = "", +proc put*(client: HttpClient | AsyncHttpClient, url: Uri | 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`. + result = await client.request(url, HttpPut, body, multipart=multipart) -proc putContent*(client: HttpClient | AsyncHttpClient, url: string, body = "", +proc putContent*(client: HttpClient | AsyncHttpClient, url: Uri | 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: string, body = "", +proc patch*(client: HttpClient | AsyncHttpClient, url: Uri | 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`. + result = await client.request(url, HttpPatch, body, multipart=multipart) -proc patchContent*(client: HttpClient | AsyncHttpClient, url: string, body = "", +proc patchContent*(client: HttpClient | AsyncHttpClient, url: Uri | 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: string, filename: string) = - ## Downloads ``url`` and saves it to ``filename``. +proc downloadFile*(client: HttpClient, url: Uri | 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: @@ -1161,30 +1230,30 @@ proc downloadFile*(client: HttpClient, url: 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) -proc downloadFile*(client: AsyncHttpClient, url: string, + 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, 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 9287e9864d..fdd5926f72 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -7,8 +7,8 @@ # 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 @@ -29,24 +29,26 @@ type HttpVer11, HttpVer10 - 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. + 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. const @@ -128,7 +130,7 @@ 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, + ## Returns a new `HttpHeaders` object. if `titleCase` is set to true, ## headers are passed to the server in title case (e.g. "Content-Length") new result result.table = newTable[string, seq[string]]() @@ -136,7 +138,7 @@ func newHttpHeaders*(titleCase=false): HttpHeaders = 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, + ## 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") new result result.table = newTable[string, seq[string]]() @@ -150,7 +152,6 @@ func newHttpHeaders*(keyValuePairs: else: result.table[key] = @[pair.val] - func `$`*(headers: HttpHeaders): string {.inline.} = $headers.table @@ -158,13 +159,13 @@ proc clear*(headers: HttpHeaders) {.inline.} = 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 + ## 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. + ## 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 @@ -172,21 +173,21 @@ 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, + ## 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] 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] 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``. + ## 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: @@ -201,7 +202,7 @@ proc add*(headers: HttpHeaders, key, value: string) = headers.table[headers.toCaseInsensitive(key)].add(value) proc del*(headers: HttpHeaders, key: string) = - ## Deletes the header entries associated with ``key`` + ## Deletes the header entries associated with `key` headers.table.del(headers.toCaseInsensitive(key)) iterator pairs*(headers: HttpHeaders): tuple[key, value: string] = @@ -211,7 +212,7 @@ iterator pairs*(headers: HttpHeaders): tuple[key, value: string] = yield (k, value) func contains*(values: HttpHeaderValues, value: string): bool = - ## Determines if ``value`` is one of the values inside ``values``. Comparison + ## 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 @@ -221,8 +222,8 @@ func hasKey*(headers: HttpHeaders, key: string): bool = func 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: @@ -244,7 +245,7 @@ func parseList(line: string, list: var seq[string], start: int): int = func 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 @@ -276,7 +277,7 @@ func 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. + ## Converts the specified `HttpCode` into a HTTP status. runnableExamples: doAssert($Http404 == "404 Not Found") case code.int @@ -352,47 +353,29 @@ proc `==`*(rawCode: string, code: HttpCode): bool ## ## **Note**: According to HTTP/1.1 specification, the reason phrase is ## optional and should be ignored by the client, making this - ## proc only suitable for comparing the ``HttpCode`` against the + ## proc only suitable for comparing the `HttpCode` against the ## string form of itself. return cmpIgnoreCase(rawCode, $code) == 0 func is1xx*(code: HttpCode): bool {.inline, since: (1, 5).} = - ## Determines whether ``code`` is a 1xx HTTP status code. + ## Determines whether `code` is a 1xx HTTP status code. runnableExamples: doAssert is1xx(HttpCode(103)) code.int in {100 .. 199} func is2xx*(code: HttpCode): bool {.inline.} = - ## Determines whether ``code`` is a 2xx HTTP status code. + ## Determines whether `code` is a 2xx HTTP status code. code.int in {200 .. 299} func is3xx*(code: HttpCode): bool {.inline.} = - ## Determines whether ``code`` is a 3xx HTTP status code. + ## Determines whether `code` is a 3xx HTTP status code. code.int in {300 .. 399} func is4xx*(code: HttpCode): bool {.inline.} = - ## Determines whether ``code`` is a 4xx HTTP status code. + ## Determines whether `code` is a 4xx HTTP status code. code.int in {400 .. 499} func is5xx*(code: HttpCode): bool {.inline.} = - ## Determines whether ``code`` is a 5xx HTTP status code. + ## Determines whether `code` is a 5xx HTTP status code. code.int in {500 .. 599} - -func `$`*(httpMethod: HttpMethod): string {.inline.} = - runnableExamples: - doAssert $HttpHead == "HEAD" - doAssert $HttpPatch == "PATCH" - doAssert $HttpGet == "GET" - doAssert $HttpPost == "POST" - - result = case httpMethod - of HttpHead: "HEAD" - of HttpGet: "GET" - of HttpPost: "POST" - of HttpPut: "PUT" - of HttpDelete: "DELETE" - of HttpTrace: "TRACE" - of HttpOptions: "OPTIONS" - of HttpConnect: "CONNECT" - of HttpPatch: "PATCH" diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim index 55ace92f2a..d0c92d5661 100644 --- a/lib/pure/includes/osenv.nim +++ b/lib/pure/includes/osenv.nim @@ -4,10 +4,11 @@ when not declared(os) and not declared(ospaths): {.error: "This is an include file for os.nim!".} when defined(nodejs): - proc getEnv*(key: string, default = ""): TaintedString {.tags: [ReadEnvEffect].} = - var ret: cstring + proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} = + var ret = default.cstring let key2 = key.cstring - {.emit: "`ret` = process.env[`key2`];".} + {.emit: "const value = process.env[`key2`];".} + {.emit: "if (value !== undefined) { `ret` = value };".} result = $ret proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = @@ -25,7 +26,7 @@ when defined(nodejs): var key2 = key.cstring {.emit: "delete process.env[`key2`];".} - iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} = + iterator envPairs*(): tuple[key, value: string] {.tags: [ReadEnvEffect].} = var num: int var keys: RootObj {.emit: "`keys` = Object.keys(process.env); `num` = `keys`.length;".} @@ -49,8 +50,8 @@ else: proc c_unsetenv(env: cstring): cint {. importc: "unsetenv", header: "".} - # Environment handling cannot be put into RTL, because the ``envPairs`` - # iterator depends on ``environment``. + # Environment handling cannot be put into RTL, because the `envPairs` + # iterator depends on `environment`. var envComputed {.threadvar.}: bool @@ -144,7 +145,7 @@ else: if startsWith(environment[i], temp): return i return -1 - proc getEnv*(key: string, default = ""): TaintedString {.tags: [ReadEnvEffect].} = + 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 @@ -165,11 +166,11 @@ else: else: var i = findEnvVar(key) if i >= 0: - return TaintedString(substr(environment[i], find(environment[i], '=')+1)) + return substr(environment[i], find(environment[i], '=')+1) else: var env = c_getenv(key) - if env == nil: return TaintedString(default) - result = TaintedString($env) + if env == nil: return default + result = $env proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = ## Checks whether the environment variable named `key` exists. @@ -248,7 +249,7 @@ else: raiseOSError(osLastError()) environment.delete(indx) - iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} = + 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, @@ -262,5 +263,5 @@ else: 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))) + yield (substr(environment[i], 0, p-1), + substr(environment[i], p+1)) diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim index 6734229737..b0740cbe60 100644 --- a/lib/pure/includes/oserr.nim +++ b/lib/pure/includes/oserr.nim @@ -20,10 +20,10 @@ proc osErrorMsg*(errorCode: OSErrorCode): string = ## ## The error code can be retrieved using the `osLastError proc <#osLastError>`_. ## - ## If conversion fails, or ``errorCode`` is ``0`` then ``""`` will be + ## If conversion fails, or `errorCode` is `0` then `""` will be ## returned. ## - ## On Windows, the ``-d:useWinAnsi`` compilation flag can be used to + ## 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. ## @@ -39,7 +39,7 @@ proc osErrorMsg*(errorCode: OSErrorCode): string = result = "" when defined(nimscript): discard - elif defined(Windows): + elif defined(windows): if errorCode != OSErrorCode(0'i32): when useWinUnicode: var msgbuf: WideCString @@ -62,15 +62,15 @@ proc newOSError*( ): owned(ref OSError) {.noinline.} = ## Creates a new `OSError exception `_. ## - ## The ``errorCode`` will determine the + ## 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. + ## 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>`_ @@ -99,14 +99,13 @@ proc osLastError*(): OSErrorCode {.sideEffect.} = ## ## 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 + ## 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. + ## .. 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>`_ diff --git a/lib/pure/includes/osseps.nim b/lib/pure/includes/osseps.nim index bafef686d5..10c85047bc 100644 --- a/lib/pure/includes/osseps.nim +++ b/lib/pure/includes/osseps.nim @@ -1,5 +1,5 @@ # 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' @@ -47,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 patch components (as in PATH), such as `':'` for POSIX + ## search path components (as in PATH), such as `':'` for POSIX ## or `';'` for Windows. FileSystemCaseSensitive* = @@ -88,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/json.nim b/lib/pure/json.nim index 063fad8b45..13cd3fb854 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -14,27 +14,35 @@ ## 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 json +## import std/json ## ## let jsonNode = parseJson("""{"key": 3.14}""") ## @@ -44,35 +52,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 json +## import std/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 json +## import std/json ## ## let jsonNode = parseJson("{}") ## @@ -84,11 +92,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 json +## import std/json ## ## let jsonNode = parseJson("""{"key": 3.14, "key2": null}""") ## @@ -100,14 +108,14 @@ ## ------------- ## ## In addition to reading dynamic data, Nim can also unmarshal JSON directly -## into a type with the ``to`` macro. +## 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. ## ## .. code-block:: Nim -## import json -## import options +## import std/json +## import std/options ## ## type ## User = object @@ -123,11 +131,11 @@ ## 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 json +## import std/json ## ## var hisName = "John" ## let herAge = 31 @@ -152,9 +160,9 @@ runnableExamples: doAssert $(%* Foo()) == """{"a1":0,"a2":0,"a0":0,"a3":0,"a4":0}""" import - hashes, tables, strutils, lexbase, streams, macros, parsejson + std/[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/options # xxx remove this dependency using same approach as https://github.com/nim-lang/Nim/pull/14563 import std/private/since export @@ -201,7 +209,7 @@ proc newJString*(s: string): JsonNode = 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` + ## 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) @@ -237,28 +245,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 @@ -268,7 +276,7 @@ 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 @@ -277,14 +285,14 @@ proc getFields*(n: JsonNode, 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 @@ -304,7 +312,10 @@ proc `%`*(s: string): JsonNode = proc `%`*(n: uint): JsonNode = ## Generic constructor for JSON data. Creates a new `JInt JsonNode`. - result = JsonNode(kind: JInt, num: BiggestInt(n)) + if n > cast[uint](int.high): + result = newJRawNumber($n) + else: + result = JsonNode(kind: JInt, num: BiggestInt(n)) proc `%`*(n: int): JsonNode = ## Generic constructor for JSON data. Creates a new `JInt JsonNode`. @@ -312,7 +323,10 @@ proc `%`*(n: int): JsonNode = proc `%`*(n: BiggestUInt): JsonNode = ## Generic constructor for JSON data. Creates a new `JInt JsonNode`. - result = JsonNode(kind: JInt, num: BiggestInt(n)) + if n > cast[BiggestUInt](BiggestInt.high): + result = newJRawNumber($n) + else: + result = JsonNode(kind: JInt, num: BiggestInt(n)) proc `%`*(n: BiggestInt): JsonNode = ## Generic constructor for JSON data. Creates a new `JInt JsonNode`. @@ -340,13 +354,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: @@ -355,8 +369,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" @@ -381,7 +395,7 @@ 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 {.compileTime.} = @@ -496,6 +510,19 @@ 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 hasKey*(node: JsonNode, key: string): bool = ## Checks if `key` exists in `node`. assert(node.kind == JObject) @@ -513,7 +540,7 @@ proc contains*(node: JsonNode, val: JsonNode): bool = proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode = ## Traverses the node and gets the given value. If any of the - ## keys do not exist, returns ``nil``. Also returns ``nil`` if one of the + ## keys do not exist, returns `nil`. Also returns `nil` if one of the ## intermediate data structures is not an object. ## ## This proc can be used to create tree structures on the @@ -531,7 +558,7 @@ proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode = proc `{}`*(node: JsonNode, index: varargs[int]): JsonNode = ## Traverses the node and gets the given value. If any of the - ## indexes do not exist, returns ``nil``. Also returns ``nil`` if one of the + ## indexes do not exist, returns `nil`. Also returns `nil` if one of the ## intermediate data structures is not an array. result = node for i in index: @@ -552,7 +579,7 @@ proc `{}`*(node: JsonNode, key: string): JsonNode = proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) = ## Traverses the node and tries to set the value at the given location - ## to ``value``. If any of the keys are missing, they are added. + ## to `value`. If any of the keys are missing, they are added. var node = node for i in 0..(keys.len-2): if not node.hasKey(keys[i]): @@ -561,7 +588,7 @@ proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) = node[keys[keys.len-1]] = value proc delete*(obj: JsonNode, key: string) = - ## Deletes ``obj[key]``. + ## Deletes `obj[key]`. assert(obj.kind == JObject) if not obj.fields.hasKey(key): raise newException(KeyError, "key not in object") @@ -604,7 +631,7 @@ proc nl(s: var string, ml: bool) = proc escapeJsonUnquoted*(s: string; result: var string) = ## Converts a string `s` to its JSON representation without quotes. - ## Appends to ``result``. + ## Appends to `result`. for c in s: case c of '\L': result.add("\\n") @@ -626,7 +653,7 @@ proc escapeJsonUnquoted*(s: string): string = proc escapeJson*(s: string; result: var string) = ## Converts a string `s` to its JSON representation with quotes. - ## Appends to ``result``. + ## Appends to `result`. result.add("\"") escapeJsonUnquoted(s, result) result.add("\"") @@ -669,13 +696,10 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true, escapeJson(node.str, result) of JInt: if lstArr: result.indent(currIndent) - when defined(js): result.add($node.num) - else: result.addInt(node.num) + result.addInt(node.num) of JFloat: if lstArr: result.indent(currIndent) - # Fixme: implement new system.add ops for the JS target - when defined(js): result.add($node.fnum) - else: result.addFloat(node.fnum) + result.addFloat(node.fnum) of JBool: if lstArr: result.indent(currIndent) result.add(if node.bval: "true" else: "false") @@ -722,12 +746,12 @@ proc pretty*(node: JsonNode, indent = 2): string = proc toUgly*(result: var string, node: JsonNode) = ## Converts `node` to its JSON Representation, without - ## regard for human readability. Meant to improve ``$`` string + ## regard for human readability. Meant to improve `$` string ## conversion performance. ## ## JSON representation is stored in the passed `result` ## - ## This provides higher efficiency than the ``pretty`` procedure as it + ## This provides higher efficiency than the `pretty` procedure as it ## does **not** attempt to format the resulting JSON to make it human readable. var comma = false case node.kind: @@ -753,11 +777,9 @@ proc toUgly*(result: var string, node: JsonNode) = else: node.str.escapeJson(result) of JInt: - when defined(js): result.add($node.num) - else: result.addInt(node.num) + result.addInt(node.num) of JFloat: - when defined(js): result.add($node.fnum) - else: result.addFloat(node.fnum) + result.addFloat(node.fnum) of JBool: result.add(if node.bval: "true" else: "false") of JNull: @@ -865,7 +887,7 @@ iterator parseJsonFragments*(s: Stream, filename: string = ""; rawIntegers = fal ## 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`. @@ -899,22 +921,23 @@ proc parseJson*(s: Stream, filename: string = ""; rawIntegers = false, rawFloats p.close() when defined(js): - from math import `mod` - type - JSObject = object + from std/math import `mod` + from std/jsffi import JSObject, `[]`, to + from std/private/jsutils import getProtoName, isInteger, isSafeInteger - proc parseNativeJson(x: cstring): JSObject {.importc: "JSON.parse".} + proc parseNativeJson(x: cstring): JSObject {.importjs: "JSON.parse(#)".} 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 cast[float](x) mod 1.0 == 0: - return JInt + if isInteger(x): + if isSafeInteger(x): + return JInt + else: + return JString else: return JFloat of "[object Boolean]": return JBool @@ -928,18 +951,6 @@ when defined(js): `result` = `x`.length; """ - 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: @@ -957,14 +968,14 @@ when defined(js): result[$nimProperty] = nimValue.convertObject() asm "}}" of JInt: - result = newJInt(cast[int](x)) + result = newJInt(x.to(int)) of JFloat: - result = newJFloat(cast[float](x)) + result = newJFloat(x.to(float)) of JString: # Dunno what to do with isUnquoted here - result = newJString($cast[cstring](x)) + result = newJString($x.to(cstring)) of JBool: - result = newJBool(cast[bool](x)) + result = newJBool(x.to(bool)) of JNull: result = newJNull() @@ -1058,8 +1069,16 @@ when defined(nimFixedForwardGeneric): dst = jsonNode.copy proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) = - verifyJsonKind(jsonNode, {JInt}, jsonPath) - dst = T(jsonNode.num) + when T is uint|uint64: + case jsonNode.kind + of JString: + dst = T(parseBiggestUInt(jsonNode.str)) + else: + verifyJsonKind(jsonNode, {JInt}, jsonPath) + dst = T(jsonNode.num) + else: + verifyJsonKind(jsonNode, {JInt}, jsonPath) + dst = cast[T](jsonNode.num) proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) = verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath) @@ -1090,7 +1109,7 @@ when defined(nimFixedForwardGeneric): jsonPath.add '[' jsonPath.addInt i jsonPath.add ']' - initFromJson(dst[i], jsonNode[i], jsonPath) + initFromJson(dst[i.S], jsonNode[i], jsonPath) # `.S` for enum indexed arrays jsonPath.setLen originalJsonPathLen proc initFromJson[T](dst: var Table[string,T]; jsonNode: JsonNode; jsonPath: var string) = diff --git a/lib/pure/lenientops.nim b/lib/pure/lenientops.nim index f73df5e5f6..a8fc78e391 100644 --- a/lib/pure/lenientops.nim +++ b/lib/pure/lenientops.nim @@ -8,49 +8,49 @@ # ## 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. -proc `+`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.noSideEffect, inline.} = +func `+`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.inline.} = F(i) + f -proc `+`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.noSideEffect, inline.} = +func `+`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.inline.} = f + F(i) -proc `-`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.noSideEffect, inline.} = +func `-`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.inline.} = F(i) - f -proc `-`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.noSideEffect, inline.} = +func `-`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.inline.} = f - F(i) -proc `*`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.noSideEffect, inline.} = +func `*`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.inline.} = F(i) * f -proc `*`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.noSideEffect, inline.} = +func `*`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.inline.} = f * F(i) -proc `/`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.noSideEffect, inline.} = +func `/`*[I: SomeInteger, F: SomeFloat](i: I, f: F): F {.inline.} = F(i) / f -proc `/`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.noSideEffect, inline.} = +func `/`*[I: SomeInteger, F: SomeFloat](f: F, i: I): F {.inline.} = f / F(i) -proc `<`*[I: SomeInteger, F: SomeFloat](i: I, f: F): bool {.noSideEffect, inline.} = +func `<`*[I: SomeInteger, F: SomeFloat](i: I, f: F): bool {.inline.} = F(i) < f -proc `<`*[I: SomeInteger, F: SomeFloat](f: F, i: I): bool {.noSideEffect, inline.} = +func `<`*[I: SomeInteger, F: SomeFloat](f: F, i: I): bool {.inline.} = f < F(i) -proc `<=`*[I: SomeInteger, F: SomeFloat](i: I, f: F): bool {.noSideEffect, inline.} = +func `<=`*[I: SomeInteger, F: SomeFloat](i: I, f: F): bool {.inline.} = F(i) <= f -proc `<=`*[I: SomeInteger, F: SomeFloat](f: F, i: I): bool {.noSideEffect, inline.} = +func `<=`*[I: SomeInteger, F: SomeFloat](f: F, i: I): bool {.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 27225ab8db..166d8286b6 100644 --- a/lib/pure/lexbase.nim +++ b/lib/pure/lexbase.nim @@ -33,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) = diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 06987d3958..b2ace79ab7 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 logging +## import std/logging ## ## var logger = newConsoleLogger() ## @@ -45,8 +45,8 @@ ## ``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 +## .. 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. @@ -60,7 +60,7 @@ ## in the following example: ## ## .. code-block:: -## import logging +## import std/logging ## ## var consoleLog = newConsoleLogger() ## var fileLog = newFileLogger("errors.log", levelThreshold=lvlError) @@ -118,7 +118,7 @@ ## The following example illustrates how to use format strings: ## ## .. code-block:: -## import logging +## import std/logging ## ## var logger = newConsoleLogger(fmtStr="[$time] - $levelname: ") ## logger.log(lvlInfo, "this is a message") @@ -794,9 +794,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>`_ @@ -820,10 +820,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 e74e68b05b..936b8fe94d 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,31 +18,24 @@ ## Basic usage ## =========== ## -## .. 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! +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! ## ## ## See also @@ -61,7 +54,7 @@ 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 +import std/[streams, typeinfo, json, intsets, tables, unicode] proc ptrToInt(x: pointer): int {.inline.} = result = cast[int](x) # don't skip alignment @@ -279,7 +272,8 @@ 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 marshal, streams + import std/streams + var s = newStringStream("[1, 3, 5]") var a: array[3, int] load(s, a) @@ -291,7 +285,8 @@ proc load*[T](s: Stream, data: var T) = proc store*[T](s: Stream, data: T) = ## Stores `data` into the stream `s`. Raises `IOError` in case of an error. runnableExamples: - import marshal, streams + import std/streams + var s = newStringStream("") var a = [1, 3, 5] store(s, a) @@ -306,7 +301,8 @@ proc store*[T](s: Stream, data: T) = 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. + ## **Note:** to serialize `x` to JSON use `%x` from the `json` module + ## or `jsonutils.toJson(x)`. runnableExamples: type Foo = object @@ -325,7 +321,7 @@ proc `$$`*[T](x: T): string = 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 @@ -341,77 +337,3 @@ proc to*[T](data: string): T = var tab = initTable[BiggestInt, pointer]() loadAny(newStringStream(data), toAny(result), tab) - - -when not defined(testing) and isMainModule: - template testit(x: untyped) = echo($$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"]] - 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 5b19a8ec00..74a98e655b 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -12,65 +12,83 @@ ## 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. -## -## .. 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) -## + +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() + ## 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 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. +## * `random module `_ for a fast and tiny random number generator +## * `mersenne module `_ for the Mersenne Twister 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.) import std/private/since {.push debugger: off.} # the user does not want to trace a part # of the standard library! -import bitops, fenv +import std/[bitops, fenv] 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: "".} + + func c_frexp*(x: cfloat, exponent: var cint): cfloat {. + importc: "frexpf", header: "", deprecated: "Use `frexp` instead".} + func c_frexp*(x: cdouble, exponent: var cint): cdouble {. + importc: "frexp", header: "", deprecated: "Use `frexp` instead".} + + # 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 `_. + ## Computes the [binomial coefficient](https://en.wikipedia.org/wiki/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 @@ -81,15 +99,16 @@ func createFactTable[N: static[int]]: array[N, int] = result[i] = result[i - 1] * i func fac*(n: int): int = - ## Computes the `factorial `_ of - ## a non-negative integer ``n``. + ## Computes the [factorial](https://en.wikipedia.org/wiki/Factorial) of + ## a non-negative integer `n`. ## - ## See also: + ## **See also:** ## * `prod func <#prod,openArray[T]>`_ runnableExamples: - doAssert fac(3) == 6 + doAssert fac(0) == 1 doAssert fac(4) == 24 doAssert fac(10) == 3628800 + const factTable = when sizeof(int) == 2: createFactTable[5]() @@ -103,49 +122,47 @@ 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 + ## This is the type that is returned by the ## `classify func <#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`. + ## Works even with `--passc:-ffast-math`. runnableExamples: doAssert NaN.isNaN doAssert not Inf.isNaN - doAssert isNaN(Inf - Inf) doAssert not isNaN(3.1415926) - doAssert not isNaN(0'f32) template fn: untyped = result = x != x when nimvm: fn() @@ -153,25 +170,88 @@ func isNaN*(x: SomeFloat): bool {.inline, since: (1,5,1).} = 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 = ## Classifies a floating point value. ## - ## Returns ``x``'s class as specified by `FloatClass enum<#FloatClass>`_. - ## Doesn't work with: `--passc:-ffast-math`. + ## Returns `x`'s class as specified by the `FloatClass enum<#FloatClass>`_. + ## Doesn't work with `--passc:-ffast-math`. 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 @@ -181,13 +261,13 @@ func classify*(x: float): FloatClass = func almostEqual*[T: SomeFloat](x, y: T; unitsInLastPlace: Natural = 4): bool {. since: (1, 5), inline.} = - ## Checks if two float values are almost equal, using - ## `machine epsilon `_. + ## 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 last place `_ + ## [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 + ## 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 @@ -196,14 +276,9 @@ func almostEqual*[T: SomeFloat](x, y: T; unitsInLastPlace: Natural = 4): bool {. ## # taken from: https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon runnableExamples: - doAssert almostEqual(3.141592653589793, 3.1415926535897936) - doAssert almostEqual(1.6777215e7'f32, 1.6777216e7'f32) + doAssert almostEqual(PI, 3.14159265358979) doAssert almostEqual(Inf, Inf) - doAssert almostEqual(-Inf, -Inf) - doAssert almostEqual(Inf, -Inf) == false - doAssert almostEqual(-Inf, Inf) == false - doAssert almostEqual(Inf, NaN) == false - doAssert almostEqual(NaN, NaN) == false + doAssert not almostEqual(NaN, NaN) if x == y: # short circuit exact equality -- needed to catch two infinities of @@ -214,31 +289,33 @@ func almostEqual*[T: SomeFloat](x, y: T; unitsInLastPlace: Natural = 4): bool {. diff < minimumPositiveValue(T) func isPowerOfTwo*(x: int): bool = - ## Returns ``true``, if ``x`` is a power of two, ``false`` otherwise. + ## 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 func <#nextPowerOfTwo,int>`_ runnableExamples: - doAssert isPowerOfTwo(16) == true - doAssert isPowerOfTwo(5) == false - doAssert isPowerOfTwo(0) == false - doAssert isPowerOfTwo(-16) == false + doAssert isPowerOfTwo(16) + doAssert not isPowerOfTwo(5) + doAssert not isPowerOfTwo(0) + doAssert not isPowerOfTwo(-16) + return (x > 0) and ((x and (x - 1)) == 0) func nextPowerOfTwo*(x: int): int = - ## Returns ``x`` rounded up to the nearest power of two. + ## 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 func <#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) @@ -252,99 +329,103 @@ func nextPowerOfTwo*(x: int): int = result += 1 + ord(x <= 0) func sum*[T](x: openArray[T]): T = - ## Computes the sum of the elements in ``x``. + ## Computes the sum of the elements in `x`. ## - ## If ``x`` is empty, 0 is returned. + ## If `x` is empty, 0 is returned. ## - ## See also: + ## **See also:** ## * `prod func <#prod,openArray[T]>`_ ## * `cumsum func <#cumsum,openArray[T]>`_ ## * `cumsummed func <#cumsummed,openArray[T]>`_ runnableExamples: doAssert sum([1, 2, 3, 4]) == 10 - doAssert sum([-1.5, 2.7, -0.1]) == 1.1 + doAssert sum([-4, 3, 5]) == 4 + for i in items(x): result = result + i func prod*[T](x: openArray[T]): T = - ## Computes the product of the elements in ``x``. + ## Computes the product of the elements in `x`. ## - ## If ``x`` is empty, 1 is returned. + ## If `x` is empty, 1 is returned. ## - ## See also: + ## **See also:** ## * `sum func <#sum,openArray[T]>`_ ## * `fac func <#fac,int>`_ runnableExamples: doAssert prod([1, 2, 3, 4]) == 24 doAssert prod([-4, 3, 5]) == -60 - result = 1.T + + result = T(1) for i in items(x): result = result * i func cumsummed*[T](x: openArray[T]): seq[T] = - ## Return cumulative (aka prefix) summation of ``x``. + ## Returns the cumulative (aka prefix) summation of `x`. ## - ## See also: + ## If `x` is empty, `@[]` is returned. + ## + ## **See also:** ## * `sum func <#sum,openArray[T]>`_ ## * `cumsum func <#cumsum,openArray[T]>`_ for the in-place version runnableExamples: - let a = [1, 2, 3, 4] - doAssert cumsummed(a) == @[1, 3, 6, 10] - result.setLen(x.len) + doAssert cumsummed([1, 2, 3, 4]) == @[1, 3, 6, 10] + + let xLen = x.len + if xLen == 0: + return @[] + result.setLen(xLen) result[0] = x[0] - for i in 1 ..< x.len: result[i] = result[i-1] + x[i] + for i in 1 ..< xLen: 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 + ## Transforms `x` in-place (must be declared as `var`) into its ## cumulative (aka prefix) summation. ## - ## See also: + ## **See also:** ## * `sum func <#sum,openArray[T]>`_ ## * `cumsummed func <#cumsummed,openArray[T]>`_ for a version which - ## returns cumsummed sequence + ## returns a 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] 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``. + func sqrt*(x: float64): float64 {.importc: "sqrt", header: "".} = + ## Computes the square root of `x`. ## - ## See also: - ## * `cbrt func <#cbrt,float64>`_ for cubic root - ## - ## .. code-block:: nim - ## echo sqrt(4.0) ## 2.0 - ## echo sqrt(1.44) ## 1.2 - ## echo sqrt(-4.0) ## nan + ## **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 cubic root of ``x``. + func cbrt*(x: float64): float64 {.importc: "cbrt", header: "".} = + ## Computes the cube root of `x`. ## - ## See also: - ## * `sqrt func <#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 + ## **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 `_ - ## of ``x``. + func ln*(x: float64): float64 {.importc: "log", header: "".} = + ## Computes the [natural logarithm](https://en.wikipedia.org/wiki/Natural_logarithm) + ## of `x`. ## - ## See also: + ## **See also:** ## * `log func <#log,T,T>`_ ## * `log10 func <#log10,float64>`_ ## * `log2 func <#log2,float64>`_ ## * `exp func <#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 + 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 else: # JS func sqrt*(x: float32): float32 {.importc: "Math.sqrt", nodecl.} func sqrt*(x: float64): float64 {.importc: "Math.sqrt", nodecl.} @@ -356,199 +437,155 @@ else: # JS func ln*(x: float64): float64 {.importc: "Math.log", nodecl.} func log*[T: SomeFloat](x, base: T): T = - ## Computes the logarithm of ``x`` to base ``base``. + ## Computes the logarithm of `x` to base `base`. ## - ## See also: + ## **See also:** ## * `ln func <#ln,float64>`_ ## * `log10 func <#log10,float64>`_ ## * `log2 func <#log2,float64>`_ - ## * `exp func <#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 + 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 + 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``. + func log10*(x: float64): float64 {.importc: "log10", header: "".} = + ## Computes the common logarithm (base 10) of `x`. ## - ## See also: + ## **See also:** ## * `ln func <#ln,float64>`_ ## * `log func <#log,T,T>`_ ## * `log2 func <#log2,float64>`_ - ## * `exp func <#exp,float64>`_ - ## - ## .. code-block:: nim - ## echo log10(100.0) ## 2.0 - ## echo log10(0.0) ## nan - ## echo log10(-100.0) ## -inf + 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). + func exp*(x: float64): float64 {.importc: "exp", header: "".} = + ## Computes the exponential function of `x` (`e^x`). ## - ## See also: + ## **See also:** ## * `ln func <#ln,float64>`_ - ## * `log func <#log,T,T>`_ - ## * `log10 func <#log10,float64>`_ - ## * `log2 func <#log2,float64>`_ - ## - ## .. 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 + 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``. + func sin*(x: float64): float64 {.importc: "sin", header: "".} = + ## Computes the sine of `x`. ## - ## See also: - ## * `cos func <#cos,float64>`_ - ## * `tan func <#tan,float64>`_ + ## **See also:** ## * `arcsin func <#arcsin,float64>`_ - ## * `sinh func <#sinh,float64>`_ - ## - ## .. code-block:: nim - ## echo sin(PI / 6) ## 0.4999999999999999 - ## echo sin(degToRad(90.0)) ## 1.0 + 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``. + func cos*(x: float64): float64 {.importc: "cos", header: "".} = + ## Computes the cosine of `x`. ## - ## See also: - ## * `sin func <#sin,float64>`_ - ## * `tan func <#tan,float64>`_ + ## **See also:** ## * `arccos func <#arccos,float64>`_ - ## * `cosh func <#cosh,float64>`_ - ## - ## .. code-block:: nim - ## echo cos(2 * PI) ## 1.0 - ## echo cos(degToRad(60.0)) ## 0.5000000000000001 + 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``. + func tan*(x: float64): float64 {.importc: "tan", header: "".} = + ## Computes the tangent of `x`. ## - ## See also: - ## * `sin func <#sin,float64>`_ - ## * `cos func <#cos,float64>`_ + ## **See also:** ## * `arctan func <#arctan,float64>`_ - ## * `tanh func <#tanh,float64>`_ - ## - ## .. code-block:: nim - ## echo tan(degToRad(45.0)) ## 0.9999999999999999 - ## echo tan(PI / 4) ## 0.9999999999999999 + 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 `_ of ``x``. + func sinh*(x: float64): float64 {.importc: "sinh", header: "".} = + ## Computes the [hyperbolic sine](https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions) of `x`. ## - ## See also: - ## * `cosh func <#cosh,float64>`_ - ## * `tanh func <#tanh,float64>`_ + ## **See also:** ## * `arcsinh func <#arcsinh,float64>`_ - ## * `sin func <#sin,float64>`_ - ## - ## .. code-block:: nim - ## echo sinh(0.0) ## 0.0 - ## echo sinh(1.0) ## 1.175201193643801 - ## echo sinh(degToRad(90.0)) ## 2.301298902307295 + 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 `_ of ``x``. + func cosh*(x: float64): float64 {.importc: "cosh", header: "".} = + ## Computes the [hyperbolic cosine](https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions) of `x`. ## - ## See also: - ## * `sinh func <#sinh,float64>`_ - ## * `tanh func <#tanh,float64>`_ + ## **See also:** ## * `arccosh func <#arccosh,float64>`_ - ## * `cos func <#cos,float64>`_ - ## - ## .. code-block:: nim - ## echo cosh(0.0) ## 1.0 - ## echo cosh(1.0) ## 1.543080634815244 - ## echo cosh(degToRad(90.0)) ## 2.509178478658057 + 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 `_ of ``x``. + func tanh*(x: float64): float64 {.importc: "tanh", header: "".} = + ## Computes the [hyperbolic tangent](https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions) of `x`. ## - ## See also: - ## * `sinh func <#sinh,float64>`_ - ## * `cosh func <#cosh,float64>`_ + ## **See also:** ## * `arctanh func <#arctanh,float64>`_ - ## * `tan func <#tan,float64>`_ - ## - ## .. code-block:: nim - ## echo tanh(0.0) ## 0.0 - ## echo tanh(1.0) ## 0.7615941559557649 - ## echo tanh(degToRad(90.0)) ## 0.9171523356672744 - - func arccos*(x: float32): float32 {.importc: "acosf", header: "".} - func arccos*(x: float64): float64 {.importc: "acos", header: "".} - ## Computes the arc cosine of ``x``. - ## - ## See also: - ## * `arcsin func <#arcsin,float64>`_ - ## * `arctan func <#arctan,float64>`_ - ## * `arctan2 func <#arctan2,float64,float64>`_ - ## * `cos func <#cos,float64>`_ - ## - ## .. code-block:: nim - ## echo radToDeg(arccos(0.0)) ## 90.0 - ## echo radToDeg(arccos(1.0)) ## 0.0 + 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``. + func arcsin*(x: float64): float64 {.importc: "asin", header: "".} = + ## Computes the arc sine of `x`. ## - ## See also: - ## * `arccos func <#arccos,float64>`_ - ## * `arctan func <#arctan,float64>`_ - ## * `arctan2 func <#arctan2,float64,float64>`_ + ## **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`. ## - ## .. code-block:: nim - ## echo radToDeg(arcsin(0.0)) ## 0.0 - ## echo radToDeg(arcsin(1.0)) ## 90.0 + ## **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``. + func arctan*(x: float64): float64 {.importc: "atan", header: "".} = + ## Calculate the arc tangent of `x`. ## - ## See also: - ## * `arcsin func <#arcsin,float64>`_ - ## * `arccos func <#arccos,float64>`_ + ## **See also:** ## * `arctan2 func <#arctan2,float64,float64>`_ ## * `tan func <#tan,float64>`_ - ## - ## .. code-block:: nim - ## echo arctan(1.0) ## 0.7853981633974483 - ## echo 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``. + 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`. ## ## 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: - ## * `arcsin func <#arcsin,float64>`_ - ## * `arccos func <#arccos,float64>`_ + ## **See also:** ## * `arctan func <#arctan,float64>`_ - ## * `tan func <#tan,float64>`_ - ## - ## .. code-block:: nim - ## echo arctan2(1.0, 0.0) ## 1.570796326794897 - ## echo radToDeg(arctan2(1.0, 0.0)) ## 90.0 + 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``. + ## Computes the inverse hyperbolic sine of `x`. + ## + ## **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``. + ## 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``. + ## Computes the inverse hyperbolic tangent of `x`. + ## + ## **See also:** + ## * `tanh func <#tanh,float64>`_ else: # JS func log10*(x: float32): float32 {.importc: "Math.log10", nodecl.} @@ -578,127 +615,116 @@ else: # JS func 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)). + ## 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)). + ## 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)). + ## 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)). + ## 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)). + ## 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)). + ## 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``. + ## 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``. + ## 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``. + ## Computes the inverse cosecant of `x` (`arcsin(1/x)`). func arccoth*[T: float32|float64](x: T): T = arctanh(1.0 / x) - ## Computes the inverse hyperbolic cotangent of ``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``. + ## 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``. + ## Computes the inverse hyperbolic cosecant of `x` (`arcsinh(1/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 hypotenuse of a right-angle triangle with ``x`` and - ## ``y`` as its base and height. Equivalent to ``sqrt(x*x + y*y)``. - ## - ## .. code-block:: nim - ## echo hypot(4.0, 3.0) ## 5.0 + 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 to power raised of y. + func pow*(x, y: float64): float64 {.importc: "pow", header: "".} = + ## Computes `x` raised to the power of `y`. ## - ## To compute power between integers (e.g. 2^6), use `^ func<#^,T,Natural>`_. + ## To compute the power between integers (e.g. 2^6), + ## use the `^ func <#^,T,Natural>`_. ## - ## See also: - ## * `^ func<#^,T,Natural>`_ + ## **See also:** + ## * `^ func <#^,T,Natural>`_ ## * `sqrt func <#sqrt,float64>`_ ## * `cbrt func <#cbrt,float64>`_ - ## - ## .. code-block:: nim - ## echo pow(100, 1.5) ## 1000.0 - ## echo pow(16.0, 0.5) ## 4.0 + runnableExamples: + doAssert almostEqual(pow(100, 1.5), 1000.0) + doAssert almostEqual(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 `_ for ``x``. + ## Computes the [error function](https://en.wikipedia.org/wiki/Error_function) for `x`. ## - ## Note: Not available for JS backend. + ## **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 `_ for ``x``. + ## Computes the [complementary error function](https://en.wikipedia.org/wiki/Error_function#Complementary_error_function) for `x`. ## - ## Note: Not available for JS backend. + ## **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 `_ for ``x``. + 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. + ## **Note:** Not available for the JS backend. ## - ## See also: - ## * `lgamma func <#lgamma,float64>`_ for a natural log of gamma function - ## - ## .. 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 + ## **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 log of the gamma function for ``x``. + func lgamma*(x: float64): float64 {.importc: "lgamma", header: "".} = + ## Computes the natural logarithm of the gamma function for `x`. ## - ## Note: Not available for JS backend. + ## **Note:** Not available for the JS backend. ## - ## See also: + ## **See also:** ## * `gamma func <#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``). + func floor*(x: float64): float64 {.importc: "floor", header: "".} = + ## Computes the floor function (i.e. the largest integer not greater than `x`). ## - ## See also: + ## **See also:** ## * `ceil func <#ceil,float64>`_ ## * `round func <#round,float64>`_ ## * `trunc func <#trunc,float64>`_ - ## - ## .. code-block:: nim - ## echo floor(2.1) ## 2.0 - ## echo floor(2.9) ## 2.0 - ## echo floor(-3.5) ## -4.0 + runnableExamples: + doAssert floor(2.1) == 2.0 + doAssert floor(2.9) == 2.0 + doAssert 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``). + func ceil*(x: float64): float64 {.importc: "ceil", header: "".} = + ## Computes the ceiling function (i.e. the smallest integer not smaller + ## than `x`). ## - ## See also: + ## **See also:** ## * `floor func <#floor,float64>`_ ## * `round func <#round,float64>`_ ## * `trunc func <#trunc,float64>`_ - ## - ## .. code-block:: nim - ## echo ceil(2.1) ## 3.0 - ## echo ceil(2.9) ## 3.0 - ## echo ceil(-2.1) ## -2.0 + runnableExamples: + doAssert ceil(2.1) == 3.0 + doAssert ceil(2.9) == 3.0 + doAssert ceil(-2.1) == -2.0 when windowsCC89: # MSVC 2010 don't have trunc/truncf @@ -718,8 +744,8 @@ 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) @@ -738,8 +764,8 @@ 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) @@ -757,49 +783,46 @@ when not defined(js): # C 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: "".} + func round*(x: float64): float64 {.importc: "round", header: "".} = ## Rounds a float to zero decimal places. ## ## Used internally by the `round func <#round,T,int>`_ ## when the specified number of places is 0. ## - ## See also: + ## **See also:** ## * `round func <#round,T,int>`_ for rounding to the specific ## number of decimal places ## * `floor func <#floor,float64>`_ ## * `ceil func <#ceil,float64>`_ ## * `trunc func <#trunc,float64>`_ - ## - ## .. code-block:: nim - ## echo round(3.4) ## 3.0 - ## echo round(3.5) ## 4.0 - ## echo round(4.5) ## 5.0 + 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. + func trunc*(x: float64): float64 {.importc: "trunc", header: "".} = + ## Truncates `x` to the decimal point. ## - ## See also: + ## **See also:** ## * `floor func <#floor,float64>`_ ## * `ceil func <#ceil,float64>`_ ## * `round func <#round,float64>`_ - ## - ## .. code-block:: nim - ## echo trunc(PI) # 3.0 - ## echo trunc(-1.85) # -1.0 + runnableExamples: + doAssert trunc(PI) == 3.0 + doAssert trunc(-1.85) == -1.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``). + func `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 - ## - ## .. 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 + ## **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 else: # JS func hypot*(x, y: float32): float32 {.importc: "Math.hypot", varargs, nodecl.} @@ -810,85 +833,94 @@ else: # JS 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.} - func round*(x: float): float {.importc: "Math.round", 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.} - func `mod`*(x, y: float32): float32 {.importcpp: "# % #".} - func `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 = ## 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`` - ## - ## .. code-block:: Nim - ## echo round(PI, 2) ## 3.14 - ## echo 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`. + runnableExamples: + doAssert round(PI, 2) == 3.14 + doAssert round(PI, 4) == 3.1416 + if places == 0: result = round(x) else: - var mult = pow(10.0, places.T) - result = round(x*mult)/mult + var mult = pow(10.0, T(places)) + result = round(x * mult) / mult func floorDiv*[T: SomeInteger](x, y: T): T = - ## Floor division is conceptually defined as ``floor(x / y)``. + ## 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 - ## - ## .. code-block:: nim - ## echo floorDiv( 13, 3) # 4 - ## echo floorDiv(-13, 3) # -5 - ## echo floorDiv( 13, -3) # -5 - ## echo floorDiv(-13, -3) # 4 + ## * `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 + 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 modulus is conceptually defined as ``x - (floorDiv(x, y) * y)``. + ## Floor modulo is conceptually defined as `x - (floorDiv(x, y) * y)`. ## - ## This func behaves the same as the ``%`` operator in Python. + ## This func behaves the same as the `%` operator in Python. ## - ## See also: + ## **See also:** ## * `mod func <#mod,float64,float64>`_ ## * `floorDiv func <#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 + runnableExamples: + doAssert floorMod( 13, 3) == 1 + doAssert floorMod(-13, 3) == 2 + doAssert floorMod( 13, -3) == -2 + doAssert 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: - assert euclDiv(13, 3) == 4 - assert euclDiv(-13, 3) == -5 - assert euclDiv(13, -3) == -4 - assert euclDiv(-13, -3) == 5 + 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: @@ -900,35 +932,58 @@ 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: - assert euclMod(13, 3) == 1 - assert euclMod(-13, 3) == 2 - assert euclMod(13, -3) == 1 - assert euclMod(-13, -3) == 2 + 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) -when not defined(js): - func c_frexp*(x: float32, exponent: var int32): float32 {. - importc: "frexp", header: "".} - func c_frexp*(x: float64, exponent: var int32): float64 {. - importc: "frexp", header: "".} - func 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. - ## - runnableExamples: - var x: int - doAssert frexp(5.0, x) == 0.625 - doAssert x == 3 - var exp: int32 - result = c_frexp(x, exp) - exponent = exp +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 not defined(windows): + doAssert frexp(-0.0) == (-0.0, 0) # 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: + 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): when windowsCC89: # taken from Go-lang Math.Log2 const ln2 = 0.693147180559945309417232121458176568075500134360255254120680009 @@ -938,7 +993,7 @@ when not defined(js): # 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) @@ -947,50 +1002,31 @@ when not defined(js): 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``. + func log2*(x: float64): float64 {.importc: "log2", header: "".} = + ## Computes the binary logarithm (base 2) of `x`. ## - ## See also: + ## **See also:** ## * `log func <#log,T,T>`_ ## * `log10 func <#log10,float64>`_ ## * `ln func <#ln,float64>`_ - ## * `exp func <#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 - -else: - func 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 + 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 func splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] = - ## Breaks ``x`` into an integer and a fractional part. + ## 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) + var absolute: T absolute = abs(x) @@ -1002,60 +1038,57 @@ func splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] = func degToRad*[T: float32|float64](d: T): T {.inline.} = - ## Convert from degrees to radians. + ## Converts from degrees to radians. ## - ## See also: + ## **See also:** ## * `radToDeg func <#radToDeg,T>`_ - ## runnableExamples: - doAssert degToRad(180.0) == 3.141592653589793 - result = T(d) * RadPerDeg + doAssert almostEqual(degToRad(180.0), PI) + + result = d * T(RadPerDeg) func radToDeg*[T: float32|float64](d: T): T {.inline.} = - ## Convert from radians to degrees. + ## Converts from radians to degrees. ## - ## See also: + ## **See also:** ## * `degToRad func <#degToRad,T>`_ - ## runnableExamples: - doAssert radToDeg(2 * PI) == 360.0 - result = T(d) / RadPerDeg + doAssert almostEqual(radToDeg(2 * PI), 360.0) + + result = d / T(RadPerDeg) func 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`` - ## + ## * `-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 + ord(T(0) < x) - ord(x < T(0)) {.pop.} {.pop.} func `^`*[T: SomeNumber](x: T, y: Natural): T = - ## Computes ``x`` to the power ``y``. + ## Computes `x` to the power of `y`. ## - ## Exponent ``y`` must be non-negative, use - ## `pow func <#pow,float64,float64>`_ for negative exponents. + ## The exponent `y` must be non-negative, use + ## `pow <#pow,float64,float64>`_ for negative exponents. ## - ## See also: + ## **See also:** ## * `pow func <#pow,float64,float64>`_ for negative exponent or ## floats ## * `sqrt func <#sqrt,float64>`_ ## * `cbrt func <#cbrt,float64>`_ - ## runnableExamples: - 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 + doAssert -3 ^ 0 == 1 + doAssert -3 ^ 1 == -3 + doAssert -3 ^ 2 == 9 case y of 0: result = 1 @@ -1074,17 +1107,18 @@ func `^`*[T: SomeNumber](x: T, y: Natural): T = x *= x func gcd*[T](x, y: T): T = - ## Computes the greatest common (positive) divisor of ``x`` and ``y``. + ## 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 integer version + ## **See also:** + ## * `gcd func <#gcd,SomeInteger,SomeInteger>`_ for an integer version ## * `lcm func <#lcm,T,T>`_ runnableExamples: doAssert gcd(13.5, 9.0) == 4.5 + var (x, y) = (x, y) while y != 0: x = x mod y @@ -1092,15 +1126,16 @@ func gcd*[T](x, y: T): T = abs x func gcd*(x, y: SomeInteger): SomeInteger = - ## Computes the greatest common (positive) divisor of ``x`` and ``y``, - ## using binary GCD (aka Stein's) algorithm. + ## Computes the greatest common (positive) divisor of `x` and `y`, + ## using the binary GCD (aka Stein's) algorithm. ## - ## See also: - ## * `gcd func <#gcd,T,T>`_ for floats version + ## **See also:** + ## * `gcd func <#gcd,T,T>`_ for a float version ## * `lcm func <#lcm,T,T>`_ runnableExamples: doAssert gcd(12, 8) == 4 doAssert gcd(17, 63) == 1 + when x is SomeSignedInt: var x = abs(x) else: @@ -1125,37 +1160,48 @@ func gcd*(x, y: SomeInteger): SomeInteger = y shl shift func gcd*[T](x: openArray[T]): T {.since: (1, 1).} = - ## Computes the greatest common (positive) divisor of the elements of ``x``. + ## Computes the greatest common (positive) divisor of the elements of `x`. ## - ## See also: - ## * `gcd func <#gcd,T,T>`_ for integer version + ## **See also:** + ## * `gcd func <#gcd,T,T>`_ for a version with two arguments runnableExamples: doAssert gcd(@[13.5, 9.0]) == 4.5 + result = x[0] - var i = 1 - while i < x.len: + for i in 1 ..< 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``. + ## Computes the least common multiple of `x` and `y`. ## - ## See also: + ## **See also:** ## * `gcd func <#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``. + ## Computes the least common multiple of the elements of `x`. ## - ## See also: - ## * `gcd func <#gcd,T,T>`_ for integer version + ## **See also:** + ## * `lcm func <#lcm,T,T>`_ for a version with two arguments runnableExamples: doAssert lcm(@[24, 30]) == 120 + result = x[0] - var i = 1 - while i < x.len: + for i in 1 ..< x.len: result = lcm(result, x[i]) - inc(i) diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim index ba944ba813..11c3245484 100644 --- a/lib/pure/md5.nim +++ b/lib/pure/md5.nim @@ -7,11 +7,14 @@ # distribution, for details about the copyright. # -## Module for computing `MD5 checksums `_. +## Module for computing [MD5 checksums](https://en.wikipedia.org/wiki/MD5). ## -## **See also:** -## * `base64 module`_ implements a base64 encoder and decoder -## * `std/sha1 module `_ for a sha1 encoder and decoder +## **Note:** The procs in this module can be used at compile time. +## +## See also +## ======== +## * `base64 module`_ implements a Base64 encoder and decoder +## * `std/sha1 module `_ for a SHA-1 encoder and decoder ## * `hashes module`_ for efficient computations of hash values ## for diverse Nim types @@ -22,8 +25,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 `toMD5 proc <#toMD5,string>`_. + MD5Digest* = array[0..15, uint8] + ## MD5 checksum of a string, obtained with the `toMD5 proc <#toMD5,string>`_. MD5Buffer = array[0..63, uint8] MD5Context* {.final.} = object state: MD5State @@ -180,7 +183,7 @@ proc md5Final*(c: var MD5Context, digest: var MD5Digest) {.raises: [], tags: [], 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 @@ -202,10 +205,8 @@ 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" @@ -226,9 +227,9 @@ proc `==`*(D1, D2: MD5Digest): bool = proc md5Init*(c: var MD5Context) = - ## Initializes a `MD5Context`. + ## Initializes an `MD5Context`. ## - ## If you use `toMD5 proc <#toMD5,string>`_ there's no need to call this + ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this ## function explicitly. c.state[0] = 0x67452301'u32 c.state[1] = 0xEFCDAB89'u32 @@ -241,7 +242,7 @@ proc md5Init*(c: var MD5Context) = proc md5Update*(c: var MD5Context, input: cstring, len: int) = ## Updates the `MD5Context` with the `input` data of length `len`. ## - ## If you use `toMD5 proc <#toMD5,string>`_ there's no need to call this + ## If you use the `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) @@ -263,7 +264,7 @@ proc md5Update*(c: var MD5Context, input: cstring, len: int) = proc md5Final*(c: var MD5Context, digest: var MD5Digest) = ## Finishes the `MD5Context` and stores the result in `digest`. ## - ## If you use `toMD5 proc <#toMD5,string>`_ there's no need to call this + ## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this ## function explicitly. var Bits: MD5CBits diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 5e6571e115..407a358faa 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -48,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.") @@ -83,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, `_. + ## `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: TaintedString = "" + ## var buffer: string = "" ## for line in lines(memfiles.open("foo"), buffer): ## echo line for ms in memSlices(mfile, delim, eat): - setLen(buf.string, ms.size) + setLen(buf, ms.size) if ms.size > 0: - copyMem(addr string(buf)[0], ms.data, ms.size) + copyMem(addr buf[0], ms.data, ms.size) yield buf -iterator lines*(mfile: MemFile, delim = '\l', eat = '\r'): TaintedString {.inline.} = +iterator lines*(mfile: MemFile, delim = '\l', eat = '\r'): string {.inline.} = ## Return each line in a file as a Nim string, like ## `lines(File) `_. ## `delim`, `eat`, and delimiting logic is exactly as for `memSlices @@ -460,7 +460,7 @@ iterator lines*(mfile: MemFile, delim = '\l', eat = '\r'): TaintedString {.inlin ## for line in lines(memfiles.open("foo")): ## echo line - var buf = TaintedString(newStringOfCap(80)) + var buf = newStringOfCap(80) for line in lines(mfile, buf, delim, eat): yield buf @@ -514,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/pure/mersenne.nim b/lib/pure/mersenne.nim index 8128935083..6778e2d627 100644 --- a/lib/pure/mersenne.nim +++ b/lib/pure/mersenne.nim @@ -7,12 +7,27 @@ # 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. + +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: @@ -28,7 +43,7 @@ proc generateNumbers(m: var MersenneTwister) = m.mt[i] = m.mt[i] xor 0x9908b0df'u32 proc getNum*(m: var MersenneTwister): uint32 = - ## Returns the next pseudo random number ranging from 0 to high(uint32) + ## Returns the next pseudorandom `uint32`. if m.index == 0: generateNumbers(m) result = m.mt[m.index] @@ -38,18 +53,3 @@ proc getNum*(m: var MersenneTwister): uint32 = 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) - - -runnableExamples: - static: - block: - var rando: MersenneTwister = newMersenneTwister(uint32.high) ## Must be "var". - doAssert rando.getNum() != rando.getNum() ## Pseudo random number. Works at compile-time. - - -# 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 2067839291..c10739fecb 100644 --- a/lib/pure/mimetypes.nim +++ b/lib/pure/mimetypes.nim @@ -8,6 +8,24 @@ # ## 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 strtabs from strutils import startsWith, toLowerAscii, strip @@ -1888,9 +1906,9 @@ func newMimetypes*(): MimeDB = 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: @@ -1899,9 +1917,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: @@ -1910,28 +1928,9 @@ 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() - -runnableExamples: - static: - block: - 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" diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index f1445fca55..605f623212 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -8,7 +8,7 @@ # ## 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. @@ -19,7 +19,7 @@ import std/private/since when hostOS == "solaris": {.passl: "-lsocket -lnsl".} -const useWinVersion = defined(Windows) or defined(nimdoc) +const useWinVersion = defined(windows) or defined(nimdoc) when useWinVersion: import winlean @@ -112,19 +112,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 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 = @@ -135,8 +135,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) @@ -165,8 +165,8 @@ else: 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) @@ -202,12 +202,12 @@ proc toSockType*(protocol: Protocol): SockType = SOCK_RAW proc getProtoByName*(name: string): int {.since: (1, 3, 5).} = - ## Returns a protocol code from the database that matches the protocol ``name``. + ## 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) - + if protoent == nil: raise newException(OSError, "protocol not found") @@ -267,8 +267,8 @@ proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, 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)) @@ -280,7 +280,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) @@ -333,10 +333,10 @@ template htons*(x: uint16): untyped = 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. + ## 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. + ## On posix this will search through the `/etc/services` file. when useWinVersion: var s = winlean.getservbyname(name, proto) else: @@ -349,10 +349,10 @@ proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} = 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. + ## 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. + ## On posix this will search through the `/etc/services` file. when useWinVersion: var s = winlean.getservbyport(ze(int16(port)).cint, proto) else: @@ -490,11 +490,11 @@ proc getAddrString*(sockAddr: ptr SockAddr): string = raise newException(IOError, "Unknown socket family in getAddrString") proc getAddrString*(sockAddr: ptr SockAddr, strAddress: var string) = - ## Stores in ``strAddress`` the string representation of the address inside - ## ``sockAddr`` - ## + ## Stores in `strAddress` the string representation of the address inside + ## `sockAddr` + ## ## **Note** - ## * ``strAddress`` must be initialized to 46 in length. + ## * `strAddress` must be initialized to 46 in length. assert(46 == len(strAddress), "`strAddress` was not initialized correctly. 46 != `len(strAddress)`") if sockAddr.sa_family.cint == nativeAfInet: @@ -682,12 +682,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``. + ## 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) @@ -704,12 +704,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``. + ## 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) @@ -748,6 +748,6 @@ proc accept*(fd: SocketHandle, inheritable = defined(nimInheritHandles)): (Socke else: 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 7b92a5e0da..37e6e8f5a5 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -9,28 +9,39 @@ ## 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 +## 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. +## +## ## Examples ## ======== ## ## 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. ## @@ -38,7 +49,7 @@ ## var socket = newSocket() ## socket.connect("google.com", Port(80)) ## -## For SSL, use the following example (and make sure to compile with ``-d:ssl``): +## For SSL, use the following example (and make sure to compile with `-d:ssl`): ## ## .. code-block:: Nim ## var socket = newSocket() @@ -57,15 +68,15 @@ ## 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. +## You can then begin accepting connections using the `accept` procedure. ## ## .. code-block:: Nim ## var client: Socket @@ -77,12 +88,11 @@ import std/private/since import nativesockets, os, strutils, times, sets, options, std/monotimes -from ssl_certs import scanSSLCertificates import ssl_config export nativesockets.Port, nativesockets.`$`, nativesockets.`==` export Domain, SockType, Protocol -const useWinVersion = defined(Windows) or defined(nimdoc) +const useWinVersion = defined(windows) or defined(nimdoc) const defineSsl = defined(ssl) or defined(nimdoc) when useWinVersion: @@ -90,6 +100,8 @@ when useWinVersion: when defineSsl: import openssl + when not defined(nimDisableCertificateValidation): + from ssl_certs import scanSSLCertificates # Note: The enumerations are mapped to Window's constants. @@ -192,8 +204,8 @@ proc socketError*(socket: Socket, err: int = -1, async = false, 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 @@ -446,14 +458,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 = type(s.sin_family)(toInt(AF_INET)) + s.sin_family = typeof(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 = type(s.sin6_family)(toInt(AF_INET6)) + s.sin6_family = typeof(s.sin6_family)(toInt(AF_INET6)) s.sin6_port = port copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0], sizeof(s.sin6_addr)) @@ -555,13 +567,13 @@ when defineSsl: ## Creates an SSL context. ## ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 - ## are available with the addition of ``protSSLv23`` which allows for + ## 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 + ## `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 ## @@ -571,7 +583,7 @@ when defineSsl: ## CA certificates will be loaded, in the following order, from: ## ## - caFile, caDir, parameters, if set - ## - if `verifyMode` is set to ``CVerifyPeerUseEnvVars``, + ## - 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. ## @@ -579,10 +591,10 @@ when defineSsl: ## 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`` + ## - `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: @@ -611,7 +623,7 @@ when defineSsl: if newCTX.SSL_CTX_set_ecdh_auto(1) != 1: raiseSSLError() - when defined(nimDisableCertificateValidation) or defined(windows): + when defined(nimDisableCertificateValidation): newCTX.SSL_CTX_set_verify(SSL_VERIFY_NONE, nil) else: case verifyMode @@ -626,11 +638,13 @@ when defineSsl: discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY) newCTX.loadCertificates(certFile, keyFile) - when not defined(nimDisableCertificateValidation) and not defined(windows): + 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(caFile, caDir) != 0: + if newCTX.SSL_CTX_load_verify_locations(caFile, caDir) != VerifySuccess: raise newException(IOError, "Failed to load SSL/TLS CA certificate(s).") else: @@ -638,7 +652,7 @@ when defineSsl: # the SSL_CERT_FILE and SSL_CERT_DIR env vars var found = false for fn in scanSSLCertificates(): - if newCTX.SSL_CTX_load_verify_locations(fn, "") == 0: + if newCTX.SSL_CTX_load_verify_locations(fn, nil) == VerifySuccess: found = true break if not found: @@ -657,7 +671,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).RootRef) + GC_unref(getExtraData(ctx, i)) ctx.context.SSL_CTX_free() proc `pskIdentityHint=`*(ctx: SslContext, hint: string) = @@ -723,7 +737,7 @@ 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. @@ -767,8 +781,8 @@ when defineSsl: 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 @@ -797,7 +811,7 @@ when defineSsl: 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``. + ## 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. @@ -840,9 +854,9 @@ when defineSsl: 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: @@ -853,15 +867,15 @@ proc getSocketError*(socket: Socket): OSErrorCode = 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. + ## 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 `err` is not lower than 0 no exception will be raised. ## - ## If ``flags`` contains ``SafeDisconn``, no exception will be raised + ## If `flags` contains `SafeDisconn`, no exception will be raised ## when the error was caused by a peer disconnection. when defineSsl: if socket.isSsl: @@ -916,8 +930,8 @@ proc socketError*(socket: Socket, err: int = -1, async = false, 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. @@ -926,9 +940,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 @@ -949,7 +963,7 @@ proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, inheritable = defined(nimInheritHandles)) {. 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. ## @@ -960,8 +974,8 @@ proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string, ## 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: @@ -997,16 +1011,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: @@ -1047,15 +1061,15 @@ 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 + ## 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 = "" @@ -1181,7 +1195,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 @@ -1195,7 +1209,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 @@ -1213,7 +1227,7 @@ proc getPeerAddr*(socket: Socket): (string, Port) = proc setSockOpt*(socket: Socket, 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`. ## ## .. code-block:: Nim ## var socket = newSocket() @@ -1244,10 +1258,10 @@ when defined(posix) or defined(nimdoc): 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: @@ -1315,7 +1329,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: @@ -1358,11 +1372,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 @@ -1392,7 +1406,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 @@ -1410,12 +1424,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 ``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 @@ -1429,9 +1443,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. ## - ## **Note**: ``data`` must be initialised. + ## **Note**: `data` must be initialised. ## - ## **Warning**: Only the ``SafeDisconn`` flag is currently supported. + ## .. warning:: Only the `SafeDisconn` flag is currently supported. data.setLen(size) result = if timeout == -1: @@ -1447,18 +1461,18 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1, 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 ``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 ## 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. ## @@ -1466,7 +1480,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) @@ -1490,46 +1504,46 @@ 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 TaintedString, timeout = -1, +proc readLine*(socket: Socket, line: var string, 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.string.add("\c\L") + line.add("\c\L") template raiseSockError() {.dirty.} = let lastError = getSocketError(socket) if flags.isDisconnectionError(lastError): - setLen(line.string, 0) + setLen(line, 0) socket.socketError(n, lastError = lastError, flags = flags) var waited: Duration - setLen(line.string, 0) + setLen(line, 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.string, 0); return + elif n == 0: setLen(line, 0); return if c == '\r': discard waitFor(socket, waited, timeout, 1, "readLine") n = peekChar(socket, c) @@ -1541,47 +1555,47 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1, elif c == '\L': addNLIfEmpty() return - add(line.string, c) + add(line, c) # Verify that this isn't a DOS attack: #3847. - if line.string.len > maxLength: break + if line.len > maxLength: break proc recvLine*(socket: Socket, timeout = -1, flags = {SocketFlag.SafeDisconn}, - maxLength = MaxLineLength): TaintedString = - ## Reads a line of data from ``socket``. + maxLength = MaxLineLength): string = + ## 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 = "".TaintedString + ## .. warning:: Only the `SafeDisconn` flag is currently supported. + result = "" readLine(socket, result, timeout, flags, maxLength) 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 + ## 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. + ## .. 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(domain: Domain) = var addrLen = sizeof(sockAddress).SockLen result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint, @@ -1611,7 +1625,7 @@ proc recvFrom*(socket: Socket, data: var string, length: int, raise newException(ValueError, "Unknown socket address family") 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. @@ -1629,7 +1643,7 @@ 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: @@ -1660,14 +1674,14 @@ template `&=`*(socket: Socket; data: typed) = 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. ## @@ -1700,18 +1714,18 @@ proc sendTo*(socket: Socket, address: string, port: Port, data: pointer, 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. ## ## 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 isSsl*(socket: Socket): bool = - ## Determines whether ``socket`` is a SSL socket. + ## Determines whether `socket` is a SSL socket. when defineSsl: result = socket.isSsl else: @@ -1836,9 +1850,9 @@ proc `$`*(address: IpAddress): string = 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() @@ -1893,12 +1907,12 @@ proc dial*(address: string, port: Port, proc connect*(socket: Socket, address: string, 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 + ## 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 @@ -1931,13 +1945,13 @@ proc connect*(socket: Socket, address: string, 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: @@ -1968,14 +1982,10 @@ proc connectAsync(socket: Socket, name: string, port = Port(0), proc connect*(socket: Socket, address: string, port = Port(0), timeout: int) {.tags: [ReadIOEffect, WriteIOEffect].} = - ## Connects to server as specified by ``address`` on port specified by ``port``. + ## 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. - ## - ## **Warning:** This procedure appears to be broken for SSL connections as of - ## Nim v1.0.2. Consider using the other `connect` procedure. See - ## https://github.com/nim-lang/Nim/issues/15215 for more info. socket.fd.setBlocking(false) socket.connectAsync(address, port, socket.domain) @@ -1989,7 +1999,18 @@ proc connect*(socket: Socket, address: string, port = Port(0), when defineSsl and not defined(nimdoc): if socket.isSsl: socket.fd.setBlocking(true) - doAssert socket.gotHandshake() + # 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) socket.fd.setBlocking(true) proc getPrimaryIPAddr*(dest = parseIpAddress("8.8.8.8")): IpAddress = diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim index 57ea466e56..721ae35c3a 100644 --- a/lib/pure/nimprof.nim +++ b/lib/pure/nimprof.nim @@ -8,7 +8,7 @@ # ## Profiling support for Nim. This is an embedded profiler that requires -## ``--profiler:on``. You only need to import this module to get a profiling +## `--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): @@ -222,8 +222,9 @@ proc enableProfiling*() = system.profilingRequestedHook = requestedHook when declared(system.StackTrace): + import std/exitprocs system.profilingRequestedHook = requestedHook system.profilerHook = hook - addQuitProc(writeProfile) + addExitProc(writeProfile) {.pop.} diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index d3a7c4fb64..fb70047b6d 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -10,91 +10,103 @@ ## 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. This implementation was extracted -## from the Mongodb interface and it thus binary compatible with a Mongo OID. +## from the MongoDB interface and is thus binary compatible with a MongoDB OID. ## -## This implementation calls ``math.randomize()`` for the first call of -## ``genOid``. +## This implementation calls `initRand()` for the first call of +## `genOid`. -import hashes, times, endians +import std/[hashes, times, endians, random] +from std/private/decode_helpers import handleHexChar type - Oid* = object ## an OID - time: int32 ## - fuzz: int32 ## - count: int32 ## + Oid* = object ## An OID. + time: int32 + fuzz: int32 + count: int32 -proc `==`*(oid1: Oid, oid2: Oid): bool = - ## Compare two Mongo Object IDs for equality - return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and +proc `==`*(oid1: Oid, oid2: Oid): bool {.inline.} = + ## Compares two OIDs for equality. + result = (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and (oid1.count == oid2.count) proc hash*(oid: Oid): Hash = - ## Generate hash of Oid for use in hashtables + ## Generates the hash of an 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 = - 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 hexbyte*(hex: char): int {.inline.} = + result = handleHexChar(hex) proc parseOid*(str: cstring): Oid = - ## parses an OID. + ## 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 oidToString*(oid: Oid, str: cstring) = +template toStringImpl[T: string | cstring](result: var T, oid: Oid) = + ## Stringifies `oid`. const hex = "0123456789abcdef" - # work around a compiler bug: - var str = str + const N = 24 + + when T is string: + result.setLen N + var o = oid var bytes = cast[cstring](addr(o)) var i = 0 while i < 12: let b = bytes[i].ord - str[2 * i] = hex[(b and 0xF0) shr 4] - str[2 * i + 1] = hex[b and 0xF] + result[2 * i] = hex[(b and 0xF0) shr 4] + result[2 * i + 1] = hex[b and 0xF] inc(i) - str[24] = '\0' + when T is cstring: + result[N] = '\0' + +proc oidToString*(oid: Oid, str: cstring) {.deprecated: "unsafe; use `$`".} = + ## Converts an oid to a string which must have space allocated for 25 elements. + # work around a compiler bug: + var str = str + toStringImpl(str, oid) proc `$`*(oid: Oid): string = - result = newString(24) - oidToString(oid, result) + ## Converts an OID to a string. + toStringImpl(result, oid) -proc rand(): cint {.importc: "rand", header: "", nodecl.} -proc srand(seed: cint) {.importc: "srand", header: "", nodecl.} -var t = getTime().toUnix.int32 -srand(t) +let + t = getTime().toUnix.int32 var - incr: int = rand() - fuzz: int32 = rand() + seed = initRand(t) + incr: int = seed.rand(int.high) -proc genOid*(): Oid = - ## generates a new OID. - t = getTime().toUnix.int32 - var i = int32(atomicInc(incr)) +let fuzz = cast[int32](seed.rand(high(int))) - bigEndian32(addr result.time, addr(t)) + +template genOid(result: var Oid, incr: var int, fuzz: int32) = + var time = getTime().toUnix.int32 + var i = cast[int32](atomicInc(incr)) + + bigEndian32(addr result.time, addr(time)) 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. + ## Returns the generated timestamp of the OID. var tmp: int32 var dummy = oid.time 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 8de4430c1d..63e3598f09 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -7,56 +7,69 @@ # 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 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 `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 -## `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) +##[ +This module implements types which encapsulate an optional value. -import typetraits +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` + + +import std/typetraits when (NimMajor, NimMinor) >= (1, 1): type @@ -67,7 +80,9 @@ else: type Option*[T] = object - ## An optional type that stores its value and state separately in a boolean. + ## 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`. when T is SomePointer: val: T else: @@ -78,21 +93,20 @@ type UnpackError* {.deprecated: "See corresponding Defect".} = UnpackDefect proc option*[T](val: T): Option[T] {.inline.} = - ## Can be used to convert a pointer type (`ptr` or `ref` or `proc`) to an option type. - ## It converts `nil` to `None`. + ## 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)`. ## - ## See also: - ## * `some <#some,T>`_ - ## * `none <#none,typedesc>`_ + ## **See also:** + ## * `some proc <#some,T>`_ + ## * `none proc <#none,typedesc>`_ runnableExamples: type Foo = ref object a: int b: string - var c: Foo - assert c.isNil - var d = option(c) - assert d.isNone + + assert option[Foo](nil).isNone + assert option(42).isSome result.val = val when T isnot SomePointer: @@ -101,21 +115,18 @@ proc option*[T](val: T): Option[T] {.inline.} = proc some*[T](val: T): Option[T] {.inline.} = ## Returns an `Option` that has the value `val`. ## - ## See also: - ## * `option <#option,T>`_ - ## * `none <#none,typedesc>`_ - ## * `isSome <#isSome,Option[T]>`_ + ## **See also:** + ## * `option proc <#option,T>`_ + ## * `none proc <#none,typedesc>`_ + ## * `isSome proc <#isSome,Option[T]>`_ runnableExamples: - var - a = some("abc") - b = some(42) - assert $type(a) == "Option[system.string]" - assert b.isSome + let a = some("abc") + + assert a.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 @@ -124,30 +135,29 @@ proc some*[T](val: T): Option[T] {.inline.} = proc none*(T: typedesc): Option[T] {.inline.} = ## Returns an `Option` for this type that has no value. ## - ## See also: - ## * `option <#option,T>`_ - ## * `some <#some,T>`_ - ## * `isNone <#isNone,Option[T]>`_ + ## **See also:** + ## * `option proc <#option,T>`_ + ## * `some proc <#some,T>`_ + ## * `isNone proc <#isNone,Option[T]>`_ runnableExamples: - var a = none(int) - assert a.isNone - assert $type(a) == "Option[system.int]" + assert none(int).isNone # the default is the none type discard proc none*[T]: Option[T] {.inline.} = - ## Alias for `none(T) proc <#none,typedesc>`_. + ## Alias for `none(T) <#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: - var - a = some(42) - b = none(string) - assert a.isSome - assert not b.isSome + assert some(42).isSome + assert not none(string).isSome when T is SomePointer: not self.val.isNil @@ -156,44 +166,40 @@ 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: - var - a = some(42) - b = none(string) - assert not a.isNone - assert b.isNone + assert not some(42).isNone + assert none(string).isNone + when T is SomePointer: self.val.isNil else: not self.has proc get*[T](self: Option[T]): lent T {.inline.} = - ## Returns contents of an `Option`. If it is `None`, then an exception is - ## thrown. + ## Returns the content of an `Option`. If it has no value, + ## an `UnpackDefect` exception is raised. ## - ## See also: - ## * `get proc <#get,Option[T],T>`_ with the default return value + ## **See also:** + ## * `get proc <#get,Option[T],T>`_ with a default return value runnableExamples: - let - a = some(42) - b = none(string) - assert a.get == 42 + assert some(42).get == 42 doAssertRaises(UnpackDefect): - echo b.get + echo none(string).get if self.isNone: raise newException(UnpackDefect, "Can't obtain a value from a `none`") result = self.val proc get*[T](self: Option[T], otherwise: T): T {.inline.} = - ## Returns the contents of the `Option` or an `otherwise` value if - ## the `Option` is `None`. + ## Returns the content of the `Option` or `otherwise` if + ## the `Option` has no value. runnableExamples: - var - a = some(42) - b = none(int) - assert a.get(9999) == 42 - assert b.get(9999) == 9999 + assert some(42).get(9999) == 42 + assert none(int).get(9999) == 9999 if self.isSome: self.val @@ -201,13 +207,14 @@ proc get*[T](self: Option[T], otherwise: T): T {.inline.} = otherwise proc get*[T](self: var Option[T]): var T {.inline.} = - ## Returns contents of the `var Option`. If it is `None`, then an exception - ## is thrown. + ## Returns the content of the `var Option` mutably. If it has no value, + ## an `UnpackDefect` exception is raised. runnableExamples: - let + var a = some(42) b = none(string) - assert a.get == 42 + inc(a.get) + assert a.get == 43 doAssertRaises(UnpackDefect): echo b.get @@ -218,22 +225,17 @@ proc get*[T](self: var Option[T]): var T {.inline.} = proc map*[T](self: Option[T], callback: proc (input: T)) {.inline.} = ## 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 - let - a = some(42) - b = none(int) - - b.map(saveDouble) + none(int).map(saveDouble) assert d == 0 - a.map(saveDouble) + some(42).map(saveDouble) assert d == 84 if self.isSome: @@ -243,49 +245,45 @@ proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] {.inli ## Applies a `callback` function to the value of the `Option` and returns an ## `Option` containing the new value. ## - ## If the `Option` is `None`, `None` of the return type of the `callback` - ## will be returned. + ## If the `Option` has no value, `none(R)` will be returned. ## - ## 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)>`_ + ## **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` runnableExamples: - var - a = some(42) - b = none(int) - proc isEven(x: int): bool = x mod 2 == 0 - assert $(a.map(isEven)) == "Some(true)" - assert $(b.map(isEven)) == "None[bool]" + assert some(42).map(isEven) == some(true) + assert none(int).map(isEven) == none(bool) if self.isSome: some[R](callback(self.val)) else: none(R) -proc flatten*[A](self: Option[Option[A]]): Option[A] {.inline.} = +proc flatten*[T](self: Option[Option[T]]): Option[T] {.inline.} = ## Remove one level of structure in a nested `Option`. + ## + ## **See also:** + ## * `flatMap proc <#flatMap,Option[T],proc(T)>`_ runnableExamples: - let a = some(some(42)) - assert $flatten(a) == "Some(42)" + assert flatten(some(some(42))) == some(42) + assert flatten(none(Option[int])) == none(int) if self.isSome: self.val else: - none(A) + none(T) -proc flatMap*[A, B](self: Option[A], - callback: proc (input: A): Option[B]): Option[B] {.inline.} = - ## Applies a `callback` function to the value of the `Option` and returns an - ## `Option` containing the new value. +proc flatMap*[T, R](self: Option[T], + callback: proc (input: T): Option[R]): Option[R] {.inline.} = + ## Applies a `callback` function to the value of the `Option` and returns the new value. ## - ## If the `Option` is `None`, `None` of the return type of the `callback` - ## will be returned. + ## If the `Option` has no value, `none(R)` will be returned. ## - ## Similar to `map`, with the difference that the `callback` returns an + ## This is 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. ## @@ -295,47 +293,40 @@ proc flatMap*[A, B](self: Option[A], runnableExamples: proc doublePositives(x: int): Option[int] = if x > 0: - return some(2*x) + some(2 * x) else: - 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) + none(int) + + assert some(42).flatMap(doublePositives) == some(84) + assert none(int).flatMap(doublePositives) == none(int) + assert some(-11).flatMap(doublePositives) == none(int) map(self, callback).flatten() proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] {.inline.} = ## 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: - ## * `map proc <#map,Option[T],proc(T)_2>`_ + ## **See also:** ## * `flatMap proc <#flatMap,Option[A],proc(A)>`_ runnableExamples: proc isEven(x: int): bool = x mod 2 == 0 - 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) + + assert some(42).filter(isEven) == some(42) + assert none(int).filter(isEven) == none(int) + assert some(-11).filter(isEven) == none(int) if self.isSome and not callback(self.val): none(T) else: self -proc `==`*(a, b: Option): bool {.inline.} = - ## Returns `true` if both `Option`s are `None`, - ## or if they are both `Some` and have equal values. +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. runnableExamples: let a = some(42) @@ -347,27 +338,35 @@ proc `==`*(a, b: Option): bool {.inline.} = assert b == d assert not (a == b) - (a.isSome and b.isSome and a.val == b.val) or (not a.isSome and not b.isSome) + 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) proc `$`*[T](self: Option[T]): string = ## Get the string representation of the `Option`. - ## - ## 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`. + runnableExamples: + assert $some(42) == "some(42)" + assert $none(int) == "none(int)" + if self.isSome: - result = "Some(" + when defined(nimLagacyOptionsDollar): + result = "Some(" + else: + result = "some(" result.addQuoted self.val result.add ")" else: - result = "None[" & name(T) & "]" + when defined(nimLagacyOptionsDollar): + result = "None[" & name(T) & "]" + else: + result = "none(" & name(T) & ")" proc unsafeGet*[T](self: Option[T]): lent T {.inline.}= - ## Returns the value of a `some`. Behavior is undefined for `none`. + ## Returns the value of a `some`. The behavior is undefined for `none`. ## - ## **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. + ## **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. assert self.isSome result = self.val diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 77499deea2..d0b3aef1a9 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -12,7 +12,7 @@ ## working with directories, running shell commands, etc. ## ## .. code-block:: -## import os +## import std/os ## ## let myFile = "/path/to/my/file.nim" ## @@ -41,11 +41,10 @@ ## * `dynlib module `_ ## * `streams module `_ -include "system/inclrtl" +include system/inclrtl import std/private/since -import - strutils, pathnorm +import std/[strutils, pathnorm] const weirdTarget = defined(nimscript) or defined(js) @@ -66,16 +65,16 @@ since (1, 1): when weirdTarget: discard elif defined(windows): - import winlean, times + import std/[winlean, times] elif defined(posix): - import posix, times + import std/[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 and defined(nimErrorProcCanHaveBody): +when weirdTarget: {.pragma: noWeirdTarget, error: "this proc is not available on the NimScript/js target".} else: {.pragma: noWeirdTarget.} @@ -226,7 +225,7 @@ proc joinPath*(parts: varargs[string]): string {.noSideEffect, for i in 0..high(parts): joinPathImpl(result, state, parts[i]) -proc `/`*(head, tail: string): string {.noSideEffect.} = +proc `/`*(head, tail: string): string {.noSideEffect, inline.} = ## The same as `joinPath(head, tail) proc <#joinPath,string,string>`_. ## ## See also: @@ -244,7 +243,7 @@ proc `/`*(head, tail: string): string {.noSideEffect.} = assert "usr/" / "/lib/" == "usr/lib/" assert "usr" / "lib" / "../bin" == "usr/bin" - return joinPath(head, tail) + result = joinPath(head, tail) proc splitPath*(path: string): tuple[head, tail: string] {. noSideEffect, rtl, extern: "nos$1".} = @@ -902,9 +901,14 @@ proc getHomeDir*(): string {.rtl, extern: "nos$1", ## * `setCurrentDir proc <#setCurrentDir,string>`_ runnableExamples: assert getHomeDir() == expandTilde("~") + # `getHomeDir()` doesn't end in `DirSep` even if `$HOME` (on posix) or + # `$USERPROFILE` (on windows) does, unless `-d:nimLegacyHomeDir` is specified. + from std/strutils import endsWith + assert not getHomeDir().endsWith DirSep - when defined(windows): return string(getEnv("USERPROFILE")) & "\\" - else: return string(getEnv("HOME")) & "/" + when defined(windows): result = getEnv("USERPROFILE") + else: result = getEnv("HOME") + result.normalizePathEnd(trailingSep = defined(nimLegacyHomeDir)) proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} = @@ -913,10 +917,7 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1", ## 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. + ## directory ("~/.config"). ## ## See also: ## * `getHomeDir proc <#getHomeDir>`_ @@ -924,21 +925,49 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1", ## * `expandTilde proc <#expandTilde,string>`_ ## * `getCurrentDir proc <#getCurrentDir>`_ ## * `setCurrentDir proc <#setCurrentDir,string>`_ + runnableExamples: + from std/strutils import endsWith + # See `getHomeDir` for behavior regarding trailing DirSep. + assert not getConfigDir().endsWith DirSep when defined(windows): - result = getEnv("APPDATA").string + result = getEnv("APPDATA") else: - result = getEnv("XDG_CONFIG_HOME", getEnv("HOME").string / ".config").string - result.normalizePathEnd(trailingSep = true) + result = getEnv("XDG_CONFIG_HOME", getEnv("HOME") / ".config") + result.normalizePathEnd(trailingSep = defined(nimLegacyHomeDir)) + +when defined(windows): + type DWORD = uint32 + + proc getTempPath( + nBufferLength: DWORD, lpBuffer: WideCString + ): DWORD {.stdcall, dynlib: "kernel32.dll", importc: "GetTempPathW".} = + ## Retrieves the path of the directory designated for temporary files. + +template getEnvImpl(result: var string, tempDirList: openArray[string]) = + for dir in tempDirList: + if existsEnv(dir): + result = getEnv(dir) + break + +template getTempDirImpl(result: var string) = + when defined(windows): + getEnvImpl(result, ["TMP", "TEMP", "USERPROFILE"]) + else: + getEnvImpl(result, ["TMPDIR", "TEMP", "TMP", "TEMPDIR"]) 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. + ## 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 <#getHomeDir>`_ @@ -946,16 +975,31 @@ proc getTempDir*(): string {.rtl, extern: "nos$1", ## * `expandTilde proc <#expandTilde,string>`_ ## * `getCurrentDir proc <#getCurrentDir>`_ ## * `setCurrentDir proc <#setCurrentDir,string>`_ + runnableExamples: + from std/strutils import endsWith + # See `getHomeDir` for behavior regarding trailing DirSep. + assert not getTempDir().endsWith(DirSep) 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) + when nimvm: + getTempDirImpl(result) + else: + when defined(windows): + let size = getTempPath(0, nil) + # If the function fails, the return value is zero. + if size > 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 + result.normalizePathEnd(trailingSep = defined(nimLegacyHomeDir)) proc expandTilde*(path: string): string {. tags: [ReadEnvEffect, ReadIOEffect].} = @@ -964,6 +1008,8 @@ proc expandTilde*(path: string): string {. ## ## Windows: this is still supported despite Windows platform not having this ## convention; also, both ``~/`` and ``~\`` are handled. + ## + ## .. warning:: `~bob` and `~bob/` are not yet handled correctly. ## ## See also: ## * `getHomeDir proc <#getHomeDir>`_ @@ -975,6 +1021,9 @@ proc expandTilde*(path: string): string {. assert expandTilde("~" / "appname.cfg") == getHomeDir() / "appname.cfg" assert expandTilde("~/foo/bar") == getHomeDir() / "foo/bar" assert expandTilde("/foo/bar") == "/foo/bar" + assert expandTilde("~") == getHomeDir() + from std/strutils import endsWith + assert not expandTilde("~").endsWith(DirSep) if len(path) == 0 or path[0] != '~': result = path @@ -1060,14 +1109,16 @@ when defined(windows) or defined(posix) or defined(nintendoswitch): 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_rename(oldname, newname: cstring): cint {. + importc: "rename", header: "".} + proc c_strlen(a: cstring): cint {. + importc: "strlen", header: "", noSideEffect.} + proc c_free(p: pointer) {. + importc: "free", header: "".} when defined(windows) and not weirdTarget: @@ -1151,28 +1202,18 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", else: var a = getFileAttributesA(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 return lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode) -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 - -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) +when not defined(windows): + const maxSymlinkLen = 1024 const - maxSymlinkLen = 1024 ExeExts* = ## Platform specific file extension for executables. ## On Windows ``["exe", "cmd", "bat"]``, on Posix ``[""]``. when defined(windows): ["exe", "cmd", "bat"] else: [""] @@ -1199,7 +1240,7 @@ proc findExe*(exe: string, followSymlinks: bool = true; if '/' in exe: checkCurrentDir() else: checkCurrentDir() - let path = string(getEnv("PATH")) + let path = getEnv("PATH") for candidate in split(path, PathSep): if candidate.len == 0: continue when defined(windows): @@ -1213,7 +1254,7 @@ proc findExe*(exe: string, followSymlinks: bool = true; if fileExists(x): when not defined(windows): while followSymlinks: # doubles as if here - if x.checkSymlink: + if x.symlinkExists: var r = newString(maxSymlinkLen) var len = readlink(x, r, maxSymlinkLen) if len < 0: @@ -1381,7 +1422,7 @@ proc setCurrentDir*(newDir: string) {.inline, tags: [], noWeirdTarget.} = ## * `getConfigDir proc <#getConfigDir>`_ ## * `getTempDir proc <#getTempDir>`_ ## * `getCurrentDir proc <#getCurrentDir>`_ - when defined(Windows): + when defined(windows): when useWinUnicode: if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32: raiseOSError(osLastError(), newDir) @@ -1414,7 +1455,7 @@ proc absolutePathInternal(path: string): string = proc normalizeExe*(file: var string) {.since: (1, 3, 5).} = ## on posix, prepends `./` if `file` doesn't contain `/` and is not `"", ".", ".."`. runnableExamples: - import sugar + import std/sugar when defined(posix): doAssert "foo".dup(normalizeExe) == "./foo" doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar" @@ -1431,8 +1472,8 @@ proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [].} = ## 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. + ## .. warning:: URL-encoded and Unicode attempts at directory traversal are not detected. + ## Triple dot is not handled. ## ## See also: ## * `absolutePath proc <#absolutePath,string>`_ @@ -1485,7 +1526,7 @@ proc normalizedPath*(path: string): string {.rtl, extern: "nos$1", tags: [].} = assert normalizedPath("a///b//..//c///d") == "a/c/d" result = pathnorm.normalizePath(path) -when defined(Windows) and not weirdTarget: +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: @@ -1518,7 +1559,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1", ## ## See also: ## * `sameFileContent proc <#sameFileContent,string,string>`_ - when defined(Windows): + when defined(windows): var success = true var f1 = openHandle(path1) var f2 = openHandle(path2) @@ -1605,10 +1646,18 @@ proc getFilePermissions*(filename: string): set[FilePermission] {. else: result = {fpUserExec..fpOthersRead} -proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {. - rtl, extern: "nos$1", tags: [WriteDirEffect], noWeirdTarget.} = +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. @@ -1630,7 +1679,13 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {. 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)) + 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: when useWinUnicode: wrapUnary(res, getFileAttributesW, filename) @@ -1647,10 +1702,116 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {. 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], noWeirdTarget.} = +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`. + 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") + + defer: + if freeSid(administratorsGroup) != nil: + raiseOSError(osLastError(), "failed to free SID for Administrators group") + + var b: WINBOOL + if not isSuccess(checkTokenMembership(0, administratorsGroup, addr b)): + raiseOSError(osLastError(), "could not check access token membership") + + return isSuccess(b) + else: + return geteuid() == 0 + +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 developper mode enabled. + ## + ## See also: + ## * `createHardlink proc <#createHardlink,string,string>`_ + ## * `expandSymlink proc <#expandSymlink,string>`_ + + 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 + 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 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 <#createSymlink,string,string>`_ + when defined(windows): + result = symlinkPath + else: + result = newString(maxSymlinkLen) + var len = readlink(symlinkPath, result, maxSymlinkLen) + if len < 0: + raiseOSError(osLastError(), symlinkPath) + if len > maxSymlinkLen: + result = newString(len+1) + len = readlink(symlinkPath, result, len) + setLen(result, len) + +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 @@ -1658,7 +1819,8 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1", ## ## On other platforms you need ## to use `getFilePermissions <#getFilePermissions,string>`_ and - ## `setFilePermissions <#setFilePermissions,string,set[FilePermission]>`_ procs + ## `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 @@ -1667,51 +1829,87 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1", ## 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 <#CopyFlag>`_ ## * `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): + 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): when useWinUnicode: let s = newWideCString(source) let d = newWideCString(dest) - if copyFileW(s, d, 0'i32) == 0'i32: raiseOSError(osLastError(), $(source, 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)) + 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) + 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) - close(d) raiseOSError(osLastError(), dest) - if bytesread != bufSize: break - dealloc(buf) - close(s) - flushFile(d) - close(d) + 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) {.noWeirdTarget, since: (1,3,7).} = +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 <#CopyFlag>`_ + ## * `copyFile proc <#copyDir,string,string>`_ if dir.len == 0: # treating "" as "." is error prone raise newException(ValueError, "dest is empty") - copyFile(source, dir / source.lastPathPart) + copyFile(source, dir / source.lastPathPart, options) -when not declared(ENOENT) and not defined(Windows): +when not declared(ENOENT) and not defined(windows): when NoFakeVars: when not defined(haiku): const ENOENT = cint(2) # 2 on most systems including Solaris @@ -1720,7 +1918,7 @@ when not declared(ENOENT) and not defined(Windows): else: var ENOENT {.importc, header: "".}: cint -when defined(Windows) and not weirdTarget: +when defined(windows) and not weirdTarget: when useWinUnicode: template deleteFile(file: untyped): untyped = deleteFileW(file) template setFileAttributes(file, attrs: untyped): untyped = @@ -1744,7 +1942,7 @@ proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirE ## * `removeFile proc <#removeFile,string>`_ ## * `moveFile proc <#moveFile,string,string>`_ result = true - when defined(Windows): + when defined(windows): when useWinUnicode: let f = newWideCString(file) else: @@ -1785,7 +1983,7 @@ proc tryMoveFSObject(source, dest: string): bool {.noWeirdTarget.} = ## 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 defined(windows): when useWinUnicode: let s = newWideCString(source) let d = newWideCString(dest) @@ -1803,9 +2001,12 @@ proc tryMoveFSObject(source, dest: string): bool {.noWeirdTarget.} = return true proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", - tags: [ReadIOEffect, WriteIOEffect], noWeirdTarget.} = + 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. ## @@ -1821,7 +2022,7 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", if not tryMoveFSObject(source, dest): when not defined(windows): # Fallback to copy & del - copyFile(source, dest) + copyFile(source, dest, {cfSymlinkAsIs}) try: removeFile(source) except: @@ -1926,6 +2127,11 @@ iterator walkPattern*(pattern: string): string {.tags: [ReadDirEffect], noWeirdT ## * `walkDirs iterator <#walkDirs.i,string>`_ ## * `walkDir iterator <#walkDir.i,string>`_ ## * `walkDirRec iterator <#walkDirRec.i,string>`_ + runnableExamples: + 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.} = @@ -1940,6 +2146,9 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTar ## * `walkDirs iterator <#walkDirs.i,string>`_ ## * `walkDir iterator <#walkDir.i,string>`_ ## * `walkDirRec iterator <#walkDirRec.i,string>`_ + runnableExamples: + 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.} = @@ -1954,6 +2163,10 @@ iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTarg ## * `walkFiles iterator <#walkFiles.i,string>`_ ## * `walkDir iterator <#walkDir.i,string>`_ ## * `walkDirRec iterator <#walkDirRec.i,string>`_ + runnableExamples: + import std/sequtils + let paths = toSeq(walkDirs("lib/pure/*")) # works on windows too + assert "lib/pure/concurrency".unixToNativePath in paths walkCommon(pattern, isDir) proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", @@ -2109,10 +2322,7 @@ iterator walkDir*(dir: string; relative = false, checkDir = false): 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 + var y = $cstring(addr x.d_name) if y != "." and y != "..": var s: Stat let path = dir / y @@ -2152,9 +2362,8 @@ iterator walkDirRec*(dir: string, ## 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! + ## .. 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: ## @@ -2281,11 +2490,10 @@ proc rawCreateDir(dir: string): bool {.noWeirdTarget.} = proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [WriteDirEffect, ReadDirEffect], noWeirdTarget.} = - ## Check if a `directory`:idx: `dir` exists, and create it otherwise. + ## Checks if a `directory`:idx: `dir` exists, and creates it otherwise. ## - ## Does not create parent directories (fails if parent does not exist). - ## Returns `true` if the directory already exists, and `false` - ## 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 <#removeDir,string>`_ @@ -2331,9 +2539,12 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1", discard existsOrCreateDir(dir) proc copyDir*(source, dest: string) {.rtl, extern: "nos$1", - tags: [WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} = + 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 @@ -2355,16 +2566,17 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1", createDir(dest) for kind, path in walkDir(source): var noSource = splitPath(path).tail - case kind - of pcFile: - copyFile(path, dest / noSource) - of pcDir: + if kind == pcDir: copyDir(path, dest / noSource) - else: discard + else: + copyFile(path, dest / noSource, {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: @@ -2380,44 +2592,16 @@ proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect], noWei copyDir(source, dest) removeDir(source) -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). - ## - ## 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) {.noWeirdTarget.} = ## 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 <#createSymlink,string,string>`_ - when defined(Windows): + when defined(windows): when useWinUnicode: var wSrc = newWideCString(src) var wDst = newWideCString(dest) @@ -2431,9 +2615,14 @@ proc createHardlink*(src, dest: string) {.noWeirdTarget.} = raiseOSError(osLastError(), $(src, dest)) proc copyFileWithPermissions*(source, dest: string, - ignorePermissionErrors = true) {.noWeirdTarget.} = + 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 <#copyFile,string,string>`_, ## `getFilePermissions <#getFilePermissions,string>`_ and ## `setFilePermissions<#setFilePermissions,string,set[FilePermission]>`_ @@ -2449,25 +2638,31 @@ proc copyFileWithPermissions*(source, dest: string, ## `OSError`. ## ## See also: + ## * `CopyFlag enum <#CopyFlag>`_ ## * `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): + copyFile(source, dest, options) + when not defined(windows): try: - setFilePermissions(dest, getFilePermissions(source)) + setFilePermissions(dest, getFilePermissions(source), followSymlinks = + (cfSymlinkFollow in options)) except: if not ignorePermissionErrors: raise proc copyDirWithPermissions*(source, dest: string, - ignorePermissionErrors = true) {.rtl, extern: "nos$1", - tags: [WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} = + 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 ## <#copyDir,string,string>`_ and `copyFileWithPermissions ## <#copyFileWithPermissions,string,string>`_ procs @@ -2491,20 +2686,19 @@ proc copyDirWithPermissions*(source, dest: string, ## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_ ## * `createDir proc <#createDir,string>`_ createDir(dest) - when not defined(Windows): + when not defined(windows): try: - setFilePermissions(dest, getFilePermissions(source)) + setFilePermissions(dest, getFilePermissions(source), followSymlinks = + false) 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: + if kind == pcDir: copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors) - else: discard + else: + copyFileWithPermissions(path, dest / noSource, ignorePermissionErrors, {cfSymlinkAsIs}) proc inclFilePermissions*(filename: string, permissions: set[FilePermission]) {. @@ -2524,25 +2718,6 @@ proc exclFilePermissions*(filename: string, ## setFilePermissions(filename, getFilePermissions(filename)-permissions) setFilePermissions(filename, getFilePermissions(filename)-permissions) -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 <#createSymlink,string,string>`_ - when defined(windows): - result = symlinkPath - else: - result = newString(maxSymlinkLen) - var len = readlink(symlinkPath, result, maxSymlinkLen) - if len < 0: - raiseOSError(osLastError(), symlinkPath) - if len > maxSymlinkLen: - 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. @@ -2670,16 +2845,16 @@ when defined(nimdoc): ## else: ## # Do something else! - proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = + 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() <#paramCount>`_ with this proc you can call the - ## convenience `commandLineParams() <#commandLineParams>`_. + ## 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 + ## 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. ## @@ -2703,8 +2878,23 @@ when defined(nimdoc): ## # Do something else! elif defined(nimscript): discard -elif defined(nintendoswitch) or weirdTarget: - proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = +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(nintendoswitch): + proc paramStr*(i: int): string {.tags: [ReadIOEffect].} = raise newException(OSError, "paramStr is not implemented on Nintendo Switch") proc paramCount*(): int {.tags: [ReadIOEffect].} = @@ -2727,22 +2917,29 @@ elif defined(windows): ownParsedArgv = true result = ownArgv.len-1 - proc paramStr*(i: int): TaintedString {.rtl, extern: "nos$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: return TaintedString(ownArgv[i]) - raise newException(IndexDefect, formatErrorIndexBound(i, ownArgv.len-1)) + 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): TaintedString = + 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: + 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. @@ -2750,17 +2947,19 @@ elif not defined(createNimRtl) and cmdCount {.importc: "cmdCount".}: cint cmdLine {.importc: "cmdLine".}: cstringArray - proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = + proc paramStr*(i: int): string {.tags: [ReadIOEffect].} = # Docstring in nimdoc block. - if i < cmdCount and i >= 0: return TaintedString($cmdLine[i]) - raise newException(IndexDefect, formatErrorIndexBound(i, cmdCount-1)) + 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[TaintedString] = + proc commandLineParams*(): seq[string] = ## Convenience proc which returns the command line parameters. ## ## This returns **only** the parameters. If you want to get the application @@ -2789,7 +2988,7 @@ when declared(paramCount) or defined(nimdoc): for i in 1..paramCount(): result.add(paramStr(i)) else: - proc commandLineParams*(): seq[TaintedString] {.error: + proc commandLineParams*(): seq[string] {.error: "commandLineParams() unsupported by dynamic libraries".} = discard @@ -2851,7 +3050,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 = string(paramStr(0)) + let exePath = paramStr(0) if len(exePath) == 0: return "" @@ -2870,7 +3069,7 @@ when not weirdTarget and defined(openbsd): return expandFilename(result) # search in path - for p in split(string(getEnv("PATH")), {PathSep}): + for p in split(getEnv("PATH"), {PathSep}): var x = joinPath(p, exePath) if fileExists(x): return expandFilename(x) @@ -2880,12 +3079,12 @@ when not weirdTarget and defined(openbsd): when not (defined(windows) or defined(macosx) or weirdTarget): proc getApplHeuristic(): string = when declared(paramStr): - result = string(paramStr(0)) + result = 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(string(getEnv("PATH")), {PathSep}): + for p in split(getEnv("PATH"), {PathSep}): var x = joinPath(p, result) if fileExists(x): return x else: @@ -3021,7 +3220,7 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1", close(f) else: raiseOSError(osLastError(), file) -when defined(Windows) or weirdTarget: +when defined(windows) or weirdTarget: type DeviceId* = int32 FileId* = int64 @@ -3053,7 +3252,7 @@ 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): + 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) @@ -3131,7 +3330,7 @@ proc getFileInfo*(handle: FileHandle): FileInfo {.noWeirdTarget.} = ## * `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. @@ -3173,7 +3372,7 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo {.noWeirdTarget. ## See also: ## * `getFileInfo(handle) proc <#getFileInfo,FileHandle>`_ ## * `getFileInfo(file) proc <#getFileInfo,File>`_ - when defined(Windows): + when defined(windows): var handle = openHandle(path, followSymlink) rawInfo: BY_HANDLE_FILE_INFORMATION @@ -3245,7 +3444,7 @@ proc isHidden*(path: string): bool {.noWeirdTarget.} = assert not "".isHidden assert ".foo/".isHidden - when defined(Windows): + when defined(windows): when useWinUnicode: wrapUnary(attributes, getFileAttributesW, path) else: @@ -3310,3 +3509,12 @@ func isValidFilename*(filename: string, maxLen = 259.Positive): bool {.since: (1 find(f.name, invalidFilenameChars) != -1): return false for invalid in invalidFilenames: if cmpIgnoreCase(f.name, invalid) == 0: return false + +# 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 diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 9c198e6fa5..6aefb8d6c7 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -75,14 +75,13 @@ const poDemon* {.deprecated.} = poDaemon ## Nim versions before 0.20 proc execProcess*(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, options: set[ProcessOption] = {poStdErrToStdOut, poUsePath, poEvalCommand}): - TaintedString {.rtl, extern: "nosp$1", + string {.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 backwards + ## compatibility. Make sure to pass options explicitly. ## ## See also: ## * `startProcess proc @@ -155,9 +154,9 @@ proc startProcess*(command: string, workingDir: string = "", 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,6 +186,7 @@ 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`. @@ -198,6 +198,7 @@ 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", tags: [].} ## Returns true if the process `p` is still running. Returns immediately. @@ -213,8 +214,8 @@ proc waitForExit*(p: Process, timeout: int = -1): int {.rtl, 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. @@ -228,8 +229,8 @@ proc peekExitCode*(p: Process): int {.rtl, extern: "nosp$1", tags: [].} 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>`_ @@ -242,8 +243,8 @@ proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## 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>`_ @@ -256,8 +257,8 @@ proc errorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## 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>`_ @@ -268,8 +269,8 @@ proc peekableOutputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [] ## ## You can peek returned 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: ## * `outputStream proc <#outputStream,Process>`_ @@ -280,8 +281,8 @@ proc peekableErrorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [], ## ## 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``. + ## .. warning:: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. ## ## See also: ## * `errorStream proc <#errorStream,Process>`_ @@ -291,8 +292,8 @@ 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>`_ @@ -303,8 +304,8 @@ proc outputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", 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>`_ @@ -315,8 +316,8 @@ proc errorHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", 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>`_ @@ -502,25 +503,25 @@ when not defined(useNimRtl): args: openArray[string] = [], env: StringTableRef = nil, options: set[ProcessOption] = {poStdErrToStdOut, poUsePath, poEvalCommand}): - TaintedString = + string = var p = startProcess(command, workingDir = workingDir, args = args, env = env, options = options) var outp = outputStream(p) - result = TaintedString"" - var line = newStringOfCap(120).TaintedString + result = "" + var line = newStringOfCap(120) while true: # FIXME: converts CR-LF to LF. if outp.readLine(line): - result.string.add(line.string) - result.string.add("\n") + result.add(line) + result.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 @@ -930,7 +931,7 @@ elif not defined(useNimRtl): result = cast[cstringArray](alloc0((counter + 1) * sizeof(cstring))) var i = 0 for key, val in envPairs(): - var x = key.string & "=" & val.string + var x = key & "=" & val result[i] = cast[cstring](alloc(x.len+1)) copyMem(result[i], addr(x[0]), x.len+1) inc(i) @@ -979,7 +980,7 @@ elif not defined(useNimRtl): when not defined(android): "/bin/sh" else: "/system/bin/sh" data.sysCommand = useShPath - sysArgsRaw = @[data.sysCommand, "-c", command] + sysArgsRaw = @[useShPath, "-c", command] assert args.len == 0, "`args` has to be empty when using poEvalCommand." else: data.sysCommand = command @@ -1232,7 +1233,7 @@ elif not defined(useNimRtl): when defined(macosx) or defined(freebsd) or defined(netbsd) or defined(openbsd) or defined(dragonfly): - import kqueue, times + import kqueue proc waitForExit(p: Process, timeout: int = -1): int = if p.exitFlag: @@ -1570,7 +1571,7 @@ elif not defined(useNimRtl): proc execCmdEx*(command: string, options: set[ProcessOption] = { poStdErrToStdOut, poUsePath}, env: StringTableRef = nil, workingDir = "", input = ""): tuple[ - output: TaintedString, + output: string, exitCode: int] {.tags: [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} = ## A convenience proc that runs the `command`, and returns its `output` and @@ -1591,7 +1592,7 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { ## ## .. code-block:: Nim ## var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4") - ## import strutils, strtabs + ## import std/[strutils, strtabs] ## stripLineEnd(result[0]) ## portable way to remove trailing newline, if any ## doAssert result == ("12", 0) ## doAssert execCmdEx("ls --nonexistant").exitCode != 0 @@ -1617,12 +1618,12 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { inputStream(p).write(input) close inputStream(p) - result = (TaintedString"", -1) - var line = newStringOfCap(120).TaintedString + result = ("", -1) + var line = newStringOfCap(120) while true: if outp.readLine(line): - result[0].string.add(line.string) - result[0].string.add("\n") + result[0].add(line) + result[0].add("\n") else: result[1] = peekExitCode(p) if result[1] != -1: break diff --git a/lib/pure/oswalkdir.nim b/lib/pure/oswalkdir.nim index 7d80b312cb..866f9ed702 100644 --- a/lib/pure/oswalkdir.nim +++ b/lib/pure/oswalkdir.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -## This module is deprecated, ``import os`` instead. +## This module is deprecated, `import os` instead. {.deprecated: "import os.nim instead".} import os export PathComponent, walkDir, walkDirRec diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 79cf522f03..23bb09ac4b 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -22,7 +22,7 @@ ## ## .. code-block:: nim ## -## import os, parsecfg, strutils, streams +## import std/[os, parsecfg, strutils, streams] ## ## var f = newFileStream(paramStr(1), fmRead) ## if f != nil: @@ -32,7 +32,7 @@ ## var e = next(p) ## case e.kind ## of cfgEof: break -## of cfgSectionStart: ## a ``[section]`` has been parsed +## of cfgSectionStart: ## a `[section]` has been parsed ## echo("new section: " & e.section) ## of cfgKeyValuePair: ## echo("key-value-pair: " & e.key & ": " & e.value) @@ -66,7 +66,7 @@ ## ----------------------------- ## .. code-block:: nim ## -## import parsecfg +## import std/parsecfg ## var dict=newConfig() ## dict.setSectionKey("","charset","utf-8") ## dict.setSectionKey("Package","name","hello") @@ -80,7 +80,7 @@ ## ---------------------------- ## .. code-block:: nim ## -## import parsecfg +## import std/parsecfg ## var dict = loadConfig("config.ini") ## var charset = dict.getSectionValue("","charset") ## var threads = dict.getSectionValue("Package","--threads") @@ -94,7 +94,7 @@ ## ------------------------------ ## .. code-block:: nim ## -## import parsecfg +## import std/parsecfg ## var dict = loadConfig("config.ini") ## dict.setSectionKey("Author","name","lhf") ## dict.writeConfig("config.ini") @@ -103,7 +103,7 @@ ## ---------------------------------------------- ## .. code-block:: nim ## -## import parsecfg +## import std/parsecfg ## var dict = loadConfig("config.ini") ## dict.delSectionKey("Author","email") ## dict.writeConfig("config.ini") @@ -115,7 +115,7 @@ # taken from https://docs.python.org/3/library/configparser.html#supported-ini-file-structure runnableExamples: - import streams + import std/streams var dict = loadConfig(newStringStream("""[Simple Values] key=value diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim index 4a7117dc5b..1e34f3649f 100644 --- a/lib/pure/parsecsv.nim +++ b/lib/pure/parsecsv.nim @@ -14,9 +14,9 @@ ## =========== ## ## .. code-block:: nim -## import parsecsv -## from os import paramStr -## from streams import newFileStream +## import std/parsecsv +## from std/os import paramStr +## from std/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 parsecsv +## import std/parsecsv ## ## # Prepare a file ## let content = """One,Two,Three,Four @@ -120,7 +120,7 @@ proc open*(my: var CsvParser, input: Stream, filename: string, ## * `open proc <#open,CsvParser,string,char,char,char>`_ which creates the ## file stream for you runnableExamples: - import streams + import std/streams var strm = newStringStream("One,Two,Three\n1,2,3\n10,20,30") var parser: CsvParser parser.open(strm, "tmp.csv") @@ -142,7 +142,7 @@ proc open*(my: var CsvParser, filename: string, ## Similar to the `other open proc<#open,CsvParser,Stream,string,char,char,char>`_, ## but creates the file stream for you. runnableExamples: - from os import removeFile + from std/os import removeFile writeFile("tmp.csv", "One,Two,Three\n1,2,3\n10,20,300") var parser: CsvParser parser.open("tmp.csv") @@ -203,7 +203,7 @@ proc processedRows*(my: var CsvParser): int = ## But even if `readRow <#readRow,CsvParser,int>`_ arrived at EOF then ## processed rows counter is incremented. runnableExamples: - import streams + import std/streams var strm = newStringStream("One,Two,Three\n1,2,3") var parser: CsvParser @@ -229,7 +229,7 @@ proc readRow*(my: var CsvParser, columns = 0): bool = ## ## Blank lines are skipped. runnableExamples: - import streams + import std/streams var strm = newStringStream("One,Two,Three\n1,2,3\n\n10,20,30") var parser: CsvParser parser.open(strm, "tmp.csv") @@ -296,7 +296,7 @@ proc readHeaderRow*(my: var CsvParser) = ## See also: ## * `rowEntry proc <#rowEntry,CsvParser,string>`_ runnableExamples: - import streams + import std/streams var strm = newStringStream("One,Two,Three\n1,2,3") var parser: CsvParser @@ -325,7 +325,7 @@ proc rowEntry*(my: var CsvParser, entry: string): var string = ## ## If specified `entry` does not exist, raises KeyError. runnableExamples: - import streams + import std/streams var strm = newStringStream("One,Two,Three\n1,2,3\n\n10,20,30") var parser: CsvParser parser.open(strm, "tmp.csv") diff --git a/lib/pure/parsejson.nim b/lib/pure/parsejson.nim index 8a0e042980..196d8c360b 100644 --- a/lib/pure/parsejson.nim +++ b/lib/pure/parsejson.nim @@ -8,7 +8,7 @@ # ## 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 @@ -21,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 ## end of an array: the `]` token TokKind* = enum # must be synchronized with TJsonEventKind! tkError, @@ -49,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 @@ -71,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 @@ -119,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) @@ -151,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]] diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index 94df5ea40f..b2d024a39e 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 +## 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 parseopt +## import std/parseopt ## ## var p = initOptParser("-ab -e:5 --foo --bar=20 file.txt") ## while true: @@ -75,31 +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. ## -## ``shortNoVal`` and ``longNoVal`` -## ================================ +## `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 parseopt +## import std/parseopt ## ## proc printToken(kind: CmdLineKind, key: string, val: string) = ## case kind @@ -172,7 +172,7 @@ type cmds: seq[string] idx: int kind*: CmdLineKind ## The detected command line token - key*, val*: TaintedString ## Key and value pair; the key is the option + key*, val*: string ## Key and value pair; the key is the option ## or the argument, and the value is not "" if ## the option was given a value @@ -192,101 +192,112 @@ proc parseWord(s: string, i: int, w: var string, add(w, s[result]) inc(result) -when declared(os.paramCount): - # we cannot provide this for NimRtl creation on Posix, because we can't - # access the command line arguments then! +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<#shortnoval-and-longnoval>`_ 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"]) - 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. - ## - ## ``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. - ## - ## 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) + 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: + when declared(paramCount): + result.cmds = newSeq[string](paramCount()) + for i in countup(1, paramCount()): + result.cmds[i-1] = paramStr(i) else: - result.cmds = newSeq[string](os.paramCount()) - for i in countup(1, os.paramCount()): - result.cmds[i-1] = os.paramStr(i).string + # 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 = TaintedString"" - result.val = TaintedString"" + result.kind = cmdEnd + result.key = "" + result.val = "" - 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"]) +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"]) - 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: @@ -338,7 +349,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.string, {' ', '\t', ':', '='}) + i = parseWord(p.cmds[p.idx], i, p.key, {' ', '\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) @@ -349,12 +360,12 @@ proc next*(p: var OptParser) {.rtl, extern: "npo$1".} = inc p.idx i = 0 if p.idx < p.cmds.len: - 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] + 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] inc p.idx else: - p.val = TaintedString"" + p.val = "" inc p.idx p.pos = 0 else: @@ -362,29 +373,30 @@ proc next*(p: var OptParser) {.rtl, extern: "npo$1".} = handleShortOption(p, p.cmds[p.idx]) else: p.kind = cmdArgument - p.key = TaintedString p.cmds[p.idx] + p.key = p.cmds[p.idx] inc p.idx p.pos = 0 -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 +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 + ## else: continue + ## doAssert p.cmdLineRest == "foo.txt bar.txt" + result = p.cmds[p.idx .. ^1].quoteShellCommand -proc remainingArgs*(p: OptParser): seq[TaintedString] {.rtl, extern: "npo$1".} = +proc remainingArgs*(p: OptParser): seq[string] {.rtl, extern: "npo$1".} = ## Retrieves a sequence of the arguments that have not been parsed yet. ## ## See also: @@ -401,14 +413,14 @@ proc remainingArgs*(p: OptParser): seq[TaintedString] {.rtl, extern: "npo$1".} = ## 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. + ## There is no need to check for `cmdEnd` while iterating. ## ## See also: ## * `initOptParser proc<#initOptParser,string,set[char],seq[string]>`_ @@ -442,54 +454,53 @@ iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, 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) +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<#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[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) {.pop.} diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim index 23d43dfe03..eb5d7c2cce 100644 --- a/lib/pure/parsesql.nim +++ b/lib/pure/parsesql.nim @@ -7,7 +7,7 @@ # 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. @@ -1179,9 +1179,12 @@ type proc add(s: var SqlWriter, thing: char) = s.buffer.add(thing) -proc add(s: var SqlWriter, thing: string) = +proc prepareAdd(s: var SqlWriter) {.inline.} = 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) = @@ -1223,6 +1226,17 @@ 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 @@ -1235,7 +1249,8 @@ proc ra(n: SqlNode, s: var SqlWriter) = of nkQuotedIdent: s.add(quoted(n.strVal)) of nkStringLit: - s.add(escape(n.strVal, "'", "'")) + s.prepareAdd + s.buffer.escape(n.strVal) of nkBitStringLit: s.add("b'" & n.strVal & "'") of nkHexStringLit: diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 5ceff26a05..64949428fa 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -26,7 +26,7 @@ ## ## .. code-block:: nim ## :test: -## from strutils import Digits, parseInt +## from std/strutils import Digits, parseInt ## ## let ## input1 = "2019 school start" diff --git a/lib/pure/pathnorm.nim b/lib/pure/pathnorm.nim index 7834f8d950..10a2a0b679 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 "includes/osseps" +import includes/osseps type PathIter* = object diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index f9868b619a..06a77af577 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -941,7 +941,7 @@ template eventParser*(pegAst, handlers: untyped): (proc(s: string): int) = ## evaluates an arithmetic expression defined by a simple PEG: ## ## .. code-block:: nim - ## import strutils, pegs + ## import std/[strutils, pegs] ## ## let ## pegAst = """ @@ -1158,9 +1158,6 @@ proc findAll*(s: string, pattern: Peg, start = 0): seq[string] {. 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: @@ -1332,7 +1329,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).string + var x = readFile(infile) writeFile(outfile, x.parallelReplace(subs)) diff --git a/lib/pure/prelude.nim b/lib/pure/prelude.nim new file mode 100644 index 0000000000..f1728b5f72 --- /dev/null +++ b/lib/pure/prelude.nim @@ -0,0 +1,28 @@ +# +# +# 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] + 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] diff --git a/lib/pure/random.nim b/lib/pure/random.nim index d599727c33..f91d92731d 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -7,9 +7,9 @@ # distribution, for details about the copyright. # -## Nim's standard random number generator. +## Nim's standard random number generator (RNG). ## -## 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 ## * C implementation: http://xoroshiro.di.unimi.it/xoroshiro128plus.c @@ -19,69 +19,63 @@ ## Basic usage ## =========== ## -## 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. +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. ## For convenience, this module contains a default Rand state that corresponds -## to the default random number generator. Most procs in this module which do +## to the default RNG. 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, then the default generator will always produce +## `randomize` is not called, the default generator will always produce ## the same results. ## -## Generators that are independent of the default one can be created with the -## `initRand proc<#initRand,int64>`_. +## RNGs 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 ## ======== -## * `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 -## `_ +## * `std/sysrand module `_ for a cryptographically secure pseudorandom number generator +## * `mersenne module `_ for the Mersenne Twister random number generator +## * `math module `_ for basic math routines +## * `stats module `_ for statistical analysis +## * `list of cryptographic and hashing modules `_ ## in the standard library -import algorithm, math +import std/[algorithm, math] import std/private/since -include "system/inclrtl" +include system/inclrtl {.push debugger: off.} when defined(js): @@ -96,12 +90,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 random number generator's state. + ## It corresponds to the default RNG'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 @@ -129,9 +123,9 @@ 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 @@ -144,6 +138,7 @@ proc next*(r: var Rand): uint64 = 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 @@ -154,12 +149,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 @@ -170,34 +165,30 @@ 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. ## - ## 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: + ## **See also:** ## * `next proc<#next,Rand>`_ + runnableExamples("--threads:on"): + import std/[random, threadpool] + + const spawns = 4 + const numbers = 100000 + + proc randomSum(r: Rand): int = + var r = r + for i in 1..numbers: + result += r.rand(0..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: + doAssert abs(^val - numbers * 5) / numbers < 0.1 + when defined(js): const helper = [0xbeac0467u32, 0xd86b048bu32] else: @@ -217,9 +208,8 @@ proc skipRandomNumbers*(s: var Rand) = proc rand*(r: var Rand; max: Natural): int {.benign.} = ## Returns a random integer in the range `0..max` using the given state. ## - ## See also: - ## * `rand proc<#rand,int>`_ that returns an integer using the default - ## random number generator + ## **See also:** + ## * `rand proc<#rand,int>`_ that returns an integer using the default RNG ## * `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 @@ -229,22 +219,22 @@ proc rand*(r: var Rand; max: Natural): int {.benign.} = 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)) + 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 random number generator. Thus, it is **not** - ## thread-safe. + ## This proc uses the default RNG. 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 @@ -256,23 +246,23 @@ proc rand*(max: int): int {.benign.} = 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 - ## random number generator + ## **See also:** + ## * `rand proc<#rand,float>`_ that returns a float using the default RNG ## * `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,typedesc[T]>`_ that accepts an integer or range type runnableExamples: var r = initRand(234) - let f = r.rand(1.0) - ## f = 8.717181376738381e-07 + let f = r.rand(1.0) # 8.717181376738381e-07 + let x = next(r) when defined(js): result = (float(x) / float(high(uint32))) * max @@ -283,13 +273,12 @@ 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 random number generator. Thus, it is **not** - ## thread-safe. + ## This proc uses the default RNG. 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 @@ -298,8 +287,8 @@ proc rand*(max: float): float {.benign.} = ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type runnableExamples: randomize(234) - let f = rand(1.0) - ## f = 8.717181376738381e-07 + let f = rand(1.0) # 8.717181376738381e-07 + rand(state, max) proc rand*[T: Ordinal or SomeFloat](r: var Rand; x: HSlice[T, T]): T = @@ -308,9 +297,9 @@ 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: + ## **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 random number generator + ## that accepts a slice and uses the default RNG ## * `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 @@ -319,8 +308,8 @@ proc rand*[T: Ordinal or SomeFloat](r: var Rand; x: HSlice[T, T]): T = 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 + let f = r.rand(-1.0 .. 1.0) # 0.8741183448756229 + assert x.a <= x.b when T is SomeFloat: result = rand(r, x.b - x.a) + x.a else: # Integers and Enum types @@ -331,13 +320,12 @@ proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T = ## ## 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 random number generator. Thus, it is **not** - ## thread-safe. + ## This proc uses the default RNG. Thus, it is **not** thread-safe. ## - ## See also: + ## **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 ## * `rand proc<#rand,int>`_ that returns an integer @@ -348,18 +336,18 @@ proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T = doAssert rand(1..6) == 4 doAssert rand(1..6) == 4 doAssert rand(1..6) == 6 + result = rand(state, x) 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 random number generator. Thus, it is **not** - ## thread-safe. + ## This proc uses the default RNG. 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]>`_ @@ -375,18 +363,18 @@ proc rand*[T: SomeInteger](t: typedesc[T]): T = 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) 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 random number - ## generator - ## * `sample proc<#sample,Rand,openArray[T]>`_ for openarrays + ## **See also:** + ## * `sample proc<#sample,set[T]>`_ that uses the default RNG + ## * `sample proc<#sample,Rand,openArray[T]>`_ for `openArray`s ## * `sample proc<#sample,Rand,openArray[T],openArray[U]>`_ that uses a ## cumulative distribution function runnableExamples: @@ -395,6 +383,7 @@ proc sample*[T](r: var Rand; s: set[T]): T = 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: @@ -402,17 +391,16 @@ 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 random number generator. Thus, it is **not** - ## thread-safe. + ## This proc uses the default RNG. 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 openarrays + ## * `sample proc<#sample,openArray[T]>`_ for `openArray`s ## * `sample proc<#sample,openArray[T],openArray[U]>`_ that uses a ## cumulative distribution function runnableExamples: @@ -421,14 +409,14 @@ proc sample*[T](s: set[T]): T = 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 - ## random number generator + ## **See also:** + ## * `sample proc<#sample,openArray[T]>`_ that uses the default RNG ## * `sample proc<#sample,Rand,openArray[T],openArray[U]>`_ that uses a ## cumulative distribution function ## * `sample proc<#sample,Rand,set[T]>`_ for sets @@ -438,18 +426,18 @@ proc sample*[T](r: var Rand; a: openArray[T]): T = 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]): T = - ## Returns a random element from ``a``. + ## 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 random number generator. Thus, it is **not** - ## thread-safe. + ## This proc uses the default RNG. 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 @@ -460,28 +448,29 @@ proc sample*[T](a: openArray[T]): T = 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 random number generator + ## a CDF but uses the default RNG ## * `sample proc<#sample,Rand,openArray[T]>`_ that does not use a CDF ## * `sample proc<#sample,Rand,set[T]>`_ for sets runnableExamples: - from math import cumsummed + from std/math import cumsummed let marbles = ["red", "blue", "green", "yellow", "purple"] let count = [1, 6, 8, 3, 4] @@ -490,35 +479,34 @@ proc sample*[T, U](r: var Rand; a: openArray[T]; cdf: openArray[U]): T = 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[T, U](Rand, openArray[T], openArray[U]) - ## <#sample,Rand,openArray[T],openArray[U]>`_. + ## `sample <#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 random number generator. Thus, it is **not** - ## thread-safe. + ## This proc uses the default RNG. 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 math import cumsummed + from std/math import cumsummed let marbles = ["red", "blue", "green", "yellow", "purple"] let count = [1, 6, 8, 3, 4] @@ -527,14 +515,15 @@ proc sample*[T, U](a: openArray[T]; cdf: openArray[U]): T = 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`` + ## with mean `mu` and standard deviation `sigma` ## using the given state. # Ratio of uniforms method for normal - # http://www2.econ.osaka-u.ac.jp/~tanizaki/class/2013/econome3/13.pdf + # https://www2.econ.osaka-u.ac.jp/~tanizaki/class/2013/econome3/13.pdf const K = sqrt(2 / E) var a = 0.0 @@ -547,36 +536,34 @@ proc gauss*(r: var Rand; mu = 0.0; sigma = 1.0): float {.since: (1, 3).} = proc gauss*(mu = 0.0, sigma = 1.0): float {.since: (1, 3).} = ## Returns a Gaussian random variate, - ## with mean ``mu`` and standard deviation ``sigma``. + ## with mean `mu` and standard deviation `sigma`. ## - ## 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 random number generator. Thus, it is **not** - ## thread-safe. + ## 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. ## ## `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 random number - ## generator's state. + ## The resulting state is independent of the default RNG's state. ## - ## 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 + ## **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 runnableExamples: - from times import getTime, toUnix, nanosecond + from std/times import getTime, toUnix, nanosecond var r1 = initRand(123) let now = getTime() var r2 = initRand(now.toUnix * 1_000_000_000 + now.nanosecond) + 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) @@ -588,29 +575,33 @@ proc randomize*(seed: int64) {.benign.} = ## `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>`_ + ## **See also:** + ## * `initRand proc<#initRand,int64>`_ that initializes a Rand state + ## with a given seed ## * `randomize proc<#randomize>`_ that uses the current time instead + ## * `initRand proc<#initRand>`_ that initializes a Rand state using + ## the current time runnableExamples: - from times import getTime, toUnix, nanosecond + from std/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 - ## random number generator + ## **See also:** + ## * `shuffle proc<#shuffle,openArray[T]>`_ that uses the default RNG runnableExamples: var cards = ["Ace", "King", "Queen", "Jack", "Ten"] var r = initRand(678) r.shuffle(cards) doAssert cards == ["King", "Ace", "Queen", "Ten", "Jack"] + for i in countdown(x.high, 1): let j = r.rand(i) swap(x[i], x[j]) @@ -618,42 +609,60 @@ 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 random number generator. Thus, it is **not** - ## thread-safe. + ## This proc uses the default RNG. 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) doAssert cards == ["King", "Ace", "Queen", "Ten", "Jack"] + shuffle(state, x) when not defined(nimscript) and not defined(standalone): - import times + import std/times + + proc initRand(): Rand = + ## Initializes a new Rand state with a seed based on the current time. + ## + ## The resulting state is independent of the default RNG's state. + ## + ## **Note:** Does not work for NimScript or 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: + let now = times.getTime() + result = initRand(convert(Seconds, Nanoseconds, now.toUnix) + now.nanosecond) + + since (1, 5, 1): + export initRand proc randomize*() {.benign.} = - ## Initializes the default random number generator with a value based on + ## Initializes the default random number generator with a seed 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 random - ## number generator. + ## the first usage of procs from this module that use the default RNG. ## - ## **Note:** Does not work for NimScript. + ## **Note:** Does not work for NimScript or the compile-time VM. ## - ## See also: + ## **See also:** ## * `randomize proc<#randomize,int64>`_ that accepts a seed - ## * `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) + ## * `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() {.pop.} diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index 2a1a97d3be..a059651bb0 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -8,56 +8,93 @@ # -## This module implements rational numbers, consisting of a numerator `num` and -## a denominator `den`, both of type int. The denominator can not be 0. +## This module implements rational numbers, consisting of a numerator and +## a denominator. The denominator can not be 0. -import math -import hashes +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 std/[math, hashes] type Rational*[T] = object - ## a rational number, consisting of a numerator and denominator + ## A rational number, consisting of a numerator `num` and a denominator `den`. 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] = - ## Create a new rational number. - assert(den != 0, "a denominator of zero value is invalid") + ## 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") result.num = num result.den = den + reduce(result) -func `//`*[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 +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 = - ## Turn a rational number into a string. + ## Turns a rational number into a string. + runnableExamples: + doAssert $(1 // 2) == "1/2" + result = $x.num & "/" & $x.den func toRational*[T: SomeInteger](x: T): Rational[T] = - ## Convert some integer `x` to a rational number. + ## Converts some integer `x` to a rational number. + runnableExamples: + doAssert toRational(42) == 42 // 1 + result.num = x result.den = 1 func toRational*(x: float, n: int = high(int) shr (sizeof(int) div 2 * 8)): Rational[int] = - ## 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). + ## Calculates the best rational approximation of `x`, + ## where the denominator is smaller than `n` + ## (default is the largest possible `int` for maximal 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 @@ -69,124 +106,113 @@ 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 = - ## Convert a rational number `x` to a float. + ## Converts a rational number `x` to a `float`. x.num / x.den func toInt*[T](x: Rational[T]): int = - ## Convert a rational number `x` to an int. Conversion rounds towards 0 if + ## Converts 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 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(DivByZeroDefect, "division by zero") - -func `+` *[T](x, y: Rational[T]): Rational[T] = - ## Add two rational numbers. +func `+`*[T](x, y: Rational[T]): Rational[T] = + ## Adds 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] = - ## Add rational `x` to int `y`. +func `+`*[T](x: Rational[T], y: T): Rational[T] = + ## Adds the rational `x` to the int `y`. result.num = x.num + y * x.den result.den = x.den -func `+` *[T](x: T, y: Rational[T]): Rational[T] = - ## Add int `x` to rational `y`. +func `+`*[T](x: T, y: Rational[T]): Rational[T] = + ## Adds the int `x` to the rational `y`. result.num = x * y.den + y.num result.den = y.den -func `+=` *[T](x: var Rational[T], y: Rational[T]) = - ## Add rational `y` to rational `x`. +func `+=`*[T](x: var Rational[T], y: Rational[T]) = + ## Adds the rational `y` to the rational `x` in-place. 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) = - ## Add int `y` to rational `x`. +func `+=`*[T](x: var Rational[T], y: T) = + ## Adds the int `y` to the rational `x` in-place. x.num += y * x.den -func `-` *[T](x: Rational[T]): Rational[T] = +func `-`*[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] = - ## Subtract two rational numbers. +func `-`*[T](x, y: Rational[T]): Rational[T] = + ## Subtracts 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] = - ## Subtract int `y` from rational `x`. +func `-`*[T](x: Rational[T], y: T): Rational[T] = + ## Subtracts the int `y` from the rational `x`. result.num = x.num - y * x.den result.den = x.den -func `-` *[T](x: T, y: Rational[T]): Rational[T] = - ## Subtract rational `y` from int `x`. +func `-`*[T](x: T, y: Rational[T]): Rational[T] = + ## Subtracts the rational `y` from the int `x`. result.num = x * y.den - y.num result.den = y.den -func `-=` *[T](x: var Rational[T], y: Rational[T]) = - ## Subtract rational `y` from rational `x`. +func `-=`*[T](x: var Rational[T], y: Rational[T]) = + ## Subtracts the rational `y` from the rational `x` in-place. 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) = - ## Subtract int `y` from rational `x`. +func `-=`*[T](x: var Rational[T], y: T) = + ## Subtracts the int `y` from the rational `x` in-place. x.num -= y * x.den -func `*` *[T](x, y: Rational[T]): Rational[T] = - ## Multiply two rational numbers. +func `*`*[T](x, y: Rational[T]): Rational[T] = + ## Multiplies 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] = - ## Multiply rational `x` with int `y`. +func `*`*[T](x: Rational[T], y: T): Rational[T] = + ## Multiplies the rational `x` with the int `y`. result.num = x.num * y result.den = x.den reduce(result) -func `*` *[T](x: T, y: Rational[T]): Rational[T] = - ## Multiply int `x` with rational `y`. +func `*`*[T](x: T, y: Rational[T]): Rational[T] = + ## Multiplies the int `x` with the rational `y`. result.num = x * y.num result.den = y.den reduce(result) -func `*=` *[T](x: var Rational[T], y: Rational[T]) = - ## Multiply rationals `y` to `x`. +func `*=`*[T](x: var Rational[T], y: Rational[T]) = + ## Multiplies the rational `x` by `y` in-place. x.num *= y.num x.den *= y.den reduce(x) -func `*=` *[T](x: var Rational[T], y: T) = - ## Multiply int `y` to rational `x`. +func `*=`*[T](x: var Rational[T], y: T) = + ## Multiplies the rational `x` by the int `y` in-place. x.num *= y reduce(x) func reciprocal*[T](x: Rational[T]): Rational[T] = - ## Calculate the reciprocal of `x`. (1/x) + ## Calculates the reciprocal of `x` (`1/x`). + ## If `x` is 0, raises `DivByZeroDefect`. if x.num > 0: result.num = x.den result.den = x.num @@ -197,48 +223,59 @@ func reciprocal*[T](x: Rational[T]): Rational[T] = raise newException(DivByZeroDefect, "division by zero") func `/`*[T](x, y: Rational[T]): Rational[T] = - ## Divide rationals `x` by `y`. + ## Divides the rational `x` by the rational `y`. result.num = x.num * y.den result.den = x.den * y.num reduce(result) func `/`*[T](x: Rational[T], y: T): Rational[T] = - ## Divide rational `x` by int `y`. + ## Divides the rational `x` by the int `y`. result.num = x.num result.den = x.den * y reduce(result) func `/`*[T](x: T, y: Rational[T]): Rational[T] = - ## Divide int `x` by Rational `y`. + ## Divides the int `x` by the rational `y`. result.num = x * y.den result.den = y.num reduce(result) func `/=`*[T](x: var Rational[T], y: Rational[T]) = - ## Divide rationals `x` by `y` in place. + ## Divides the rational `x` by the rational `y` in-place. x.num *= y.den x.den *= y.num reduce(x) func `/=`*[T](x: var Rational[T], y: T) = - ## Divide rational `x` by int `y` in place. + ## Divides the rational `x` by the int `y` in-place. x.den *= y reduce(x) func cmp*(x, y: Rational): int = - ## Compares two rationals. + ## Compares two rationals. Returns + ## * a value less than zero, if `x < y` + ## * a value greater than zero, if `x > y` + ## * zero, if `x == y` (x - y).num -func `<` *(x, y: Rational): bool = +func `<`*(x, y: Rational): bool = + ## Returns true if `x` is less than `y`. (x - y).num < 0 -func `<=` *(x, y: Rational): bool = +func `<=`*(x, y: Rational): bool = + ## Returns tue if `x` is less than or equal to `y`. (x - y).num <= 0 -func `==` *(x, y: Rational): bool = +func `==`*(x, y: Rational): bool = + ## Compares two rationals for equality. (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 + result.num = abs x.num result.den = abs x.den @@ -248,29 +285,29 @@ func `div`*[T: SomeInteger](x, y: Rational[T]): T = func `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 = ## 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] = ## 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 func 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 hash for rational `x` + ## Computes the hash for the rational `x`. # reduce first so that hash(x) == hash(y) for x == y var copy = x reduce(copy) diff --git a/lib/pure/reservedmem.nim b/lib/pure/reservedmem.nim index 469ca7efaa..232a2b3838 100644 --- a/lib/pure/reservedmem.nim +++ b/lib/pure/reservedmem.nim @@ -76,7 +76,7 @@ when defined(windows): template check(expr) = let r = expr - if r == cast[type(r)](0): + if r == cast[typeof(r)](0): raiseOSError(osLastError()) else: diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index 83850e03ea..42550af1d8 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -8,16 +8,16 @@ # ## This module contains support for a `rope`:idx: data type. -## Ropes can represent very long strings efficiently; especially concatenation +## Ropes can represent very long strings efficiently; in particular, 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" -import streams +include system/inclrtl +import std/streams {.push debugger: off.} # the user does not want to trace a part # of the standard library! @@ -29,8 +29,8 @@ var cacheEnabled = false type - Rope* = ref RopeObj ## empty rope is represented by nil - RopeObj {.acyclic.} = object + Rope* {.acyclic.} = ref object + ## A rope data type. The empty rope is represented by `nil`. left, right: Rope length: int data: string # not empty if a leaf @@ -45,8 +45,7 @@ type proc len*(a: Rope): int {.rtl, extern: "nro$1".} = ## The rope's length. - if a == nil: result = 0 - else: result = a.length + if a == nil: 0 else: a.length proc newRope(): Rope = new(result) proc newRope(data: string): Rope = @@ -128,8 +127,9 @@ proc insertInCache(s: string, tree: Rope): Rope = proc rope*(s: string = ""): Rope {.rtl, extern: "nro$1Str".} = ## Converts a string to a rope. runnableExamples: - var r = rope("I'm a rope") + let r = rope("I'm a rope") doAssert $r == "I'm a rope" + if s.len == 0: result = nil else: @@ -146,15 +146,17 @@ 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: - var r = rope(429) + 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: - var r = rope(4.29) + let r = rope(4.29) doAssert $r == "4.29" + result = rope($f) proc enableCache*() {.rtl, extern: "nro$1".} = @@ -170,12 +172,9 @@ proc disableCache*() {.rtl, extern: "nro$1".} = proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} = ## The concatenation operator for ropes. runnableExamples: - var - r1 = rope("Hello, ") - r2 = rope("Nim!") - - let r = r1 & r2 + let r = rope("Hello, ") & rope("Nim!") doAssert $r == "Hello, Nim!" + if a == nil: result = b elif b == nil: @@ -189,78 +188,62 @@ proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} = proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} = ## The concatenation operator for ropes. runnableExamples: - var - r1 = rope("Hello, ") - r2 = "Nim!" - - let r = r1 & r2 + let r = rope("Hello, ") & "Nim!" doAssert $r == "Hello, Nim!" + result = a & rope(b) proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} = ## The concatenation operator for ropes. runnableExamples: - var - r1 = "Hello, " - r2 = rope("Nim!") - - let r = r1 & r2 + let r = "Hello, " & rope("Nim!") doAssert $r == "Hello, Nim!" + result = rope(a) & b proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} = - ## The concatenation operator for an openarray of ropes. + ## The concatenation operator for an `openArray` of ropes. runnableExamples: - let s = @[rope("Hello, "), rope("Nim"), rope("!")] - let r = &s + let r = &[rope("Hello, "), rope("Nim"), rope("!")] doAssert $r == "Hello, Nim!" + for item in a: result = result & item proc add*(a: var Rope, b: Rope) {.rtl, extern: "nro$1Rope".} = ## Adds `b` to the rope `a`. runnableExamples: - var - r1 = rope("Hello, ") - r2 = rope("Nim!") + var r = rope("Hello, ") + r.add(rope("Nim!")) + doAssert $r == "Hello, Nim!" - r1.add(r2) - doAssert $r1 == "Hello, Nim!" a = a & b proc add*(a: var Rope, b: string) {.rtl, extern: "nro$1Str".} = ## Adds `b` to the rope `a`. runnableExamples: - var - r1 = rope("Hello, ") - r2 = "Nim!" + var r = rope("Hello, ") + r.add("Nim!") + doAssert $r == "Hello, Nim!" - r1.add(r2) - doAssert $r1 == "Hello, Nim!" 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``, ``\0`` is returned. + ## expensive! Worst-case: O(n). If `i >= r.len or i < 0`, `\0` is returned. runnableExamples: - let r1 = rope("Hello, Nim!") + let r = rope("Hello, Nim!") - doAssert r1[0] == 'H' - doAssert r1[7] == 'N' - doAssert r1[22] == '\0' - - let r2 = rope("Hello") & rope(", Nim!") - - doAssert r2[0] == 'H' - doAssert r2[7] == 'N' - doAssert r2[22] == '\0' + doAssert r[0] == 'H' + doAssert r[7] == 'N' + doAssert r[22] == '\0' var x = r var j = i - if x == nil: return + if x == nil or i < 0 or i >= r.len: return while true: if x != nil and x.data.len > 0: - if j < x.data.len: return x.data[j] - return '\0' + # leaf + return x.data[j] else: if x.left.length > j: x = x.left @@ -276,7 +259,7 @@ iterator leaves*(r: Rope): string = var index = 0 for leave in r.leaves: doAssert leave == s[index] - inc index + inc(index) if r != nil: var stack = @[r] @@ -307,16 +290,19 @@ proc `$`*(r: Rope): string {.rtl, extern: "nroToString".} = 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. +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" + var i = 0 var length = len(frmt) result = nil @@ -357,13 +343,13 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {. 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)``. +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" + add(c, frmt % args) when not defined(js) and not defined(nimscript): @@ -386,14 +372,12 @@ when not defined(js) and not defined(nimscript): bpos = 0 blen = readBuffer(f, addr(buf[0]), buf.len) if blen == 0: # no more data in file - result = false - return + return false let n = min(blen - bpos, slen - spos) - # TODO There's gotta be a better way of comparing here... + # 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 + cast[pointer](cast[int](cstring(s)) + spos), n): + return false spos += n bpos += n diff --git a/lib/pure/segfaults.nim b/lib/pure/segfaults.nim index 2fa9a0b1cc..e0da8b81d1 100644 --- a/lib/pure/segfaults.nim +++ b/lib/pure/segfaults.nim @@ -13,6 +13,8 @@ ## ## Tested on these OSes: Linux, Windows, OSX +# xxx possibly broken on arm64, see bug #17178 + {.used.} # do allocate memory upfront: diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index 20bf1b3b08..e78219aec0 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,7 +25,7 @@ ## 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 os, nativesockets @@ -36,7 +36,7 @@ const ioselSupportedPlatform* = defined(macosx) or defined(freebsd) or defined(dragonfly) or (defined(linux) and not defined(android) and not defined(emscripten)) ## 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 @@ -86,62 +86,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. @@ -150,77 +150,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``. + ## 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 ## @@ -230,7 +230,7 @@ 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 diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index 66d181d408..5ba0486084 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -41,7 +41,7 @@ ## ## ## For SSL support this module relies on OpenSSL. If you want to -## enable SSL, compile with ``-d:ssl``. +## enable SSL, compile with `-d:ssl`. import net, strutils, strtabs, base64, os, strutils import asyncnet, asyncdispatch @@ -72,10 +72,10 @@ proc containsNewline(xs: seq[string]): bool = return true proc debugSend*(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} = - ## Sends ``cmd`` on the socket connected to the SMTP server. + ## Sends `cmd` on the socket connected to the SMTP server. ## - ## If the ``smtp`` object was created with ``debug`` enabled, - ## debugSend will invoke ``echo("C:" & cmd)`` before sending. + ## If the `smtp` object was created with `debug` enabled, + ## debugSend will invoke `echo("C:" & cmd)` before sending. ## ## This is a lower level proc and not something that you typically ## would need to call when using this module. One exception to @@ -86,12 +86,12 @@ proc debugSend*(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} = echo("C:" & cmd) await smtp.sock.send(cmd) -proc debugRecv*(smtp: Smtp | AsyncSmtp): Future[TaintedString] {.multisync.} = +proc debugRecv*(smtp: Smtp | AsyncSmtp): Future[string] {.multisync.} = ## Receives a line of data from the socket connected to the ## SMTP server. ## - ## If the ``smtp`` object was created with ``debug`` enabled, - ## debugRecv will invoke ``echo("S:" & result.string)`` after + ## If the `smtp` object was created with `debug` enabled, + ## debugRecv will invoke `echo("S:" & result.string)` after ## the data is received. ## ## This is a lower level proc and not something that you typically @@ -103,7 +103,7 @@ proc debugRecv*(smtp: Smtp | AsyncSmtp): Future[TaintedString] {.multisync.} = result = await smtp.sock.recvLine() if smtp.debug: - echo("S:" & result.string) + echo("S:" & result) proc quitExcpt(smtp: Smtp, msg: string) = smtp.debugSend("QUIT") @@ -125,8 +125,8 @@ proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string], otherHeaders: openArray[tuple[name, value: string]]): Message = ## Creates a new MIME compliant message. ## - ## You need to make sure that ``mSubject``, ``mTo`` and ``mCc`` don't contain - ## any newline characters. Failing to do so will raise ``AssertionDefect``. + ## You need to make sure that `mSubject`, `mTo` and `mCc` don't contain + ## any newline characters. Failing to do so will raise `AssertionDefect`. doAssert(not mSubject.contains({'\c', '\L'}), "'mSubject' shouldn't contain any newline characters") doAssert(not (mTo.containsNewline() or mCc.containsNewline()), @@ -144,8 +144,8 @@ proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string] = @[]): Message = ## Alternate version of the above. ## - ## You need to make sure that ``mSubject``, ``mTo`` and ``mCc`` don't contain - ## any newline characters. Failing to do so will raise ``AssertionDefect``. + ## You need to make sure that `mSubject`, `mTo` and `mCc` don't contain + ## any newline characters. Failing to do so will raise `AssertionDefect`. doAssert(not mSubject.contains({'\c', '\L'}), "'mSubject' shouldn't contain any newline characters") doAssert(not (mTo.containsNewline() or mCc.containsNewline()), @@ -157,7 +157,7 @@ proc createMessage*(mSubject, mBody: string, mTo, result.msgOtherHeaders = newStringTable() proc `$`*(msg: Message): string = - ## stringify for ``Message``. + ## stringify for `Message`. result = "" if msg.msgTo.len() > 0: result = "TO: " & msg.msgTo.join(", ") & "\c\L" @@ -173,7 +173,7 @@ proc `$`*(msg: Message): string = proc newSmtp*(useSsl = false, debug = false, sslContext: SslContext = nil): Smtp = - ## Creates a new ``Smtp`` instance. + ## Creates a new `Smtp` instance. new result result.debug = debug result.sock = newSocket() @@ -188,7 +188,7 @@ proc newSmtp*(useSsl = false, debug = false, proc newAsyncSmtp*(useSsl = false, debug = false, sslContext: SslContext = nil): AsyncSmtp = - ## Creates a new ``AsyncSmtp`` instance. + ## Creates a new `AsyncSmtp` instance. new result result.debug = debug @@ -212,9 +212,9 @@ proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] = proc checkReply*(smtp: Smtp | AsyncSmtp, reply: string) {.multisync.} = ## Calls `debugRecv<#debugRecv,AsyncSmtp>`_ and checks that the received - ## data starts with ``reply``. If the received data does not start - ## with ``reply``, then a ``QUIT`` command will be sent to the SMTP - ## server and a ``ReplyError`` exception will be raised. + ## data starts with `reply`. If the received data does not start + ## with `reply`, then a `QUIT` command will be sent to the SMTP + ## server and a `ReplyError` exception will be raised. ## ## This is a lower level proc and not something that you typically ## would need to call when using this module. One exception to @@ -269,12 +269,12 @@ proc auth*(smtp: Smtp | AsyncSmtp, username, password: string) {.multisync.} = 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 + ## Sends `msg` from `fromAddr` to the addresses specified in `toAddrs`. + ## Messages may be formed using `createMessage` by converting the ## Message into a string. ## - ## You need to make sure that ``fromAddr`` and ``toAddrs`` don't contain - ## any newline characters. Failing to do so will raise ``AssertionDefect``. + ## You need to make sure that `fromAddr` and `toAddrs` don't contain + ## any newline characters. Failing to do so will raise `AssertionDefect`. doAssert(not (toAddrs.containsNewline() or fromAddr.contains({'\c', '\L'})), "'toAddrs' and 'fromAddr' shouldn't contain any newline characters") diff --git a/lib/pure/ssl_certs.nim b/lib/pure/ssl_certs.nim index c1003f445b..2d2644ebe8 100644 --- a/lib/pure/ssl_certs.nim +++ b/lib/pure/ssl_certs.nim @@ -11,16 +11,48 @@ ## SSL_CERT_DIR environment variables. import os, strutils -from os import existsEnv, getEnv -import strutils - -# SECURITY: this unnecessarily scans through dirs/files regardless of the -# actual host OS/distribution. Hopefully all the paths are writeble only by -# root. # FWIW look for files before scanning entire dirs. -const certificatePaths = [ +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 + "/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 @@ -37,8 +69,6 @@ const certificatePaths = [ "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", # OpenBSD, FreeBSD (optional symlink) "/etc/ssl/cert.pem", - # Mac OS X - "/System/Library/OpenSSL/certs/cert.pem", # Fedora/RHEL "/etc/pki/tls/certs", # Android @@ -47,7 +77,7 @@ const certificatePaths = [ "/usr/local/share/certs", # NetBSD "/etc/openssl/certs", -] + ] when defined(haiku): const @@ -67,16 +97,29 @@ iterator scanSSLCertificates*(useEnvVars = false): string = ## 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 existsEnv("SSL_CERT_FILE"): + if useEnvVars and existsEnv("SSL_CERT_FILE"): yield getEnv("SSL_CERT_FILE") - elif existsEnv("SSL_CERT_DIR"): + elif useEnvVars and existsEnv("SSL_CERT_DIR"): let p = getEnv("SSL_CERT_DIR") for fn in joinPath(p, "*").walkFiles(): yield fn else: - when not defined(haiku): + 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): diff --git a/lib/pure/stats.nim b/lib/pure/stats.nim index af6cffef27..6e2d5fecdd 100644 --- a/lib/pure/stats.nim +++ b/lib/pure/stats.nim @@ -9,65 +9,72 @@ ## Statistical analysis framework for performing ## basic statistical analysis of data. -## The data is analysed in a single pass, when a data value -## is pushed to the ``RunningStat`` or ``RunningRegress`` objects +## The data is analysed in a single pass, when it +## is pushed to a `RunningStat` or `RunningRegress` object. ## -## ``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 var) +## - varianceS (sample variance) ## - standardDeviation -## - standardDeviationS (sample stddev) +## - standardDeviationS (sample standard deviation) ## - skewness (the third statistical moment) ## - kurtosis (the fourth statistical moment) ## -## ``RunningRegress`` calculates for two sets of data -## - n +## `RunningRegress` calculates for two sets of data +## - n (data count) ## - slope ## - intercept ## - correlation ## -## Procs have been provided to calculate statistics on arrays and sequences. +## Procs are provided to calculate statistics on `openArray`s. ## ## However, if more than a single statistical calculation is required, it is more -## 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() +## efficient to push the data once to a `RunningStat` object and then +## call the numerous statistical procs for the `RunningStat` object: -from math import FloatClass, sqrt, pow, round +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 + +from std/math import FloatClass, sqrt, pow, round {.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 ## number of pushed data + RunningStat* = object ## An accumulator for statistical data. + n*: int ## amount 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 ## number of pushed data - x_stats*: RunningStat ## stats for first set of data - y_stats*: RunningStat ## stats for second set of data + 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 s_xy: float ## accumulated data for combined xy # ----------- RunningStat -------------------------- + proc clear*(s: var RunningStat) = - ## reset `s` + ## Resets `s`. s.n = 0 s.min = toBiggestFloat(int.high) s.max = 0.0 @@ -78,7 +85,7 @@ proc clear*(s: var RunningStat) = s.mom4 = 0.0 proc push*(s: var RunningStat, x: float) = - ## pushes a value `x` for processing + ## 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 @@ -97,63 +104,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. + ## 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 = - ## combine two RunningStats. + ## Combines two `RunningStat`s. ## - ## Useful if performing parallel analysis of data series - ## and need to re-combine parallel result sets + ## Useful when performing parallel analysis of data series + ## and needing to re-combine parallel result sets. result.clear() result.n = a.n + b.n @@ -178,11 +185,11 @@ proc `+`*(a, b: RunningStat): RunningStat = result.min = min(a.min, b.min) proc `+=`*(a: var RunningStat, b: RunningStat) {.inline.} = - ## add a second RunningStats `b` to `a` + ## Adds the `RunningStat` `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: ## @@ -199,56 +206,57 @@ 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 standardDeviation of `x` + ## Computes the population standard deviation of `x`. var rs: RunningStat rs.push(x) result = rs.standardDeviation() proc standardDeviationS*[T](x: openArray[T]): float = - ## computes the sample standardDeviation of `x` + ## Computes the sample standard deviation 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() @@ -256,14 +264,14 @@ proc kurtosisS*[T](x: openArray[T]): float = # ---------------------- Running Regression ----------------------------- proc clear*(r: var RunningRegress) = - ## reset `r` + ## Resets `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) @@ -271,38 +279,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. + ## Pushes two sets of values `x` and `y` for processing. assert(x.len == y.len) for i in 0..`_ runnableExamples: - from os import removeFile + from std/os import removeFile var strm = newFileStream("somefile.txt", fmWrite) @@ -216,7 +214,7 @@ 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): 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.. len(str): setLen(str.untaint, length) +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.string), length) - if L != len(str): setLen(str.untaint, L) + let L = readData(s, cstring(str), length) + if L != len(str): setLen(str, L) -proc readStr*(s: Stream, length: int, str: var TaintedString) {.since: (1, 3).} = +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): TaintedString = +proc readStr*(s: Stream, length: int): string = ## Reads a string of length `length` from the stream `s`. Raises `IOError` if ## an error occurred. runnableExamples: @@ -950,23 +942,23 @@ proc readStr*(s: Stream, length: int): TaintedString = doAssert strm.readStr(2) == "e" doAssert strm.readStr(2) == "" strm.close() - result = newString(length).TaintedString + result = newString(length) readStrPrivate(s, length, result) -proc peekStrPrivate(s: Stream, length: int, str: var TaintedString) = - if length > len(str): setLen(str.untaint, length) +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.string), length) - if L != len(str): setLen(str.untaint, L) + let L = peekData(s, cstring(str), length) + if L != len(str): setLen(str, L) -proc peekStr*(s: Stream, length: int, str: var TaintedString) {.since: (1, 3).} = +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): TaintedString = +proc peekStr*(s: Stream, length: int): string = ## Peeks a string of length `length` from the stream `s`. Raises `IOError` if ## an error occurred. runnableExamples: @@ -977,10 +969,10 @@ proc peekStr*(s: Stream, length: int): TaintedString = doAssert strm.readStr(2) == "ab" doAssert strm.peekStr(2) == "cd" strm.close() - result = newString(length).TaintedString + result = newString(length) peekStrPrivate(s, length, result) -proc readLine*(s: Stream, line: var TaintedString): bool = +proc readLine*(s: Stream, line: var string): bool = ## Reads a line of text from the stream `s` into `line`. `line` must not be ## ``nil``! May throw an IO exception. ## @@ -992,7 +984,7 @@ proc readLine*(s: Stream, line: var TaintedString): bool = ## See also: ## * `readLine(Stream) proc <#readLine,Stream>`_ ## * `peekLine(Stream) proc <#peekLine,Stream>`_ - ## * `peekLine(Stream, TaintedString) proc <#peekLine,Stream,TaintedString>`_ + ## * `peekLine(Stream, string) proc <#peekLine,Stream,string>`_ runnableExamples: var strm = newStringStream("The first line\nthe second line\nthe third line") var line = "" @@ -1010,7 +1002,7 @@ proc readLine*(s: Stream, line: var TaintedString): bool = result = s.readLineImpl(s, line) else: # fallback - line.untaint.setLen(0) + line.setLen(0) while true: var c = readChar(s) if c == '\c': @@ -1020,10 +1012,10 @@ proc readLine*(s: Stream, line: var TaintedString): bool = elif c == '\0': if line.len > 0: break else: return false - line.untaint.add(c) + line.add(c) result = true -proc peekLine*(s: Stream, line: var TaintedString): bool = +proc peekLine*(s: Stream, line: var string): bool = ## Peeks a line of text from the stream `s` into `line`. `line` must not be ## ``nil``! May throw an IO exception. ## @@ -1034,7 +1026,7 @@ proc peekLine*(s: Stream, line: var TaintedString): bool = ## ## See also: ## * `readLine(Stream) proc <#readLine,Stream>`_ - ## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_ + ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_ ## * `peekLine(Stream) proc <#peekLine,Stream>`_ runnableExamples: var strm = newStringStream("The first line\nthe second line\nthe third line") @@ -1054,15 +1046,15 @@ proc peekLine*(s: Stream, line: var TaintedString): bool = defer: setPosition(s, pos) result = readLine(s, line) -proc readLine*(s: Stream): TaintedString = +proc readLine*(s: Stream): string = ## Reads a line from a stream `s`. Raises `IOError` if an error occurred. ## ## **Note:** This is not very efficient. ## ## See also: - ## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_ + ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_ ## * `peekLine(Stream) proc <#peekLine,Stream>`_ - ## * `peekLine(Stream, TaintedString) proc <#peekLine,Stream,TaintedString>`_ + ## * `peekLine(Stream, string) proc <#peekLine,Stream,string>`_ runnableExamples: var strm = newStringStream("The first line\nthe second line\nthe third line") doAssert strm.readLine() == "The first line" @@ -1071,7 +1063,7 @@ proc readLine*(s: Stream): TaintedString = doAssertRaises(IOError): discard strm.readLine() strm.close() - result = TaintedString"" + result = "" if s.atEnd: raise newEIO("cannot read from stream") while true: @@ -1082,17 +1074,17 @@ proc readLine*(s: Stream): TaintedString = if c == '\L' or c == '\0': break else: - result.untaint.add(c) + result.add(c) -proc peekLine*(s: Stream): TaintedString = +proc peekLine*(s: Stream): string = ## 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, TaintedString) proc <#readLine,Stream,TaintedString>`_ - ## * `peekLine(Stream, TaintedString) proc <#peekLine,Stream,TaintedString>`_ + ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_ + ## * `peekLine(Stream, string) proc <#peekLine,Stream,string>`_ runnableExamples: var strm = newStringStream("The first line\nthe second line\nthe third line") doAssert strm.peekLine() == "The first line" @@ -1106,13 +1098,13 @@ proc peekLine*(s: Stream): TaintedString = defer: setPosition(s, pos) result = readLine(s) -iterator lines*(s: Stream): TaintedString = +iterator lines*(s: Stream): string = ## Iterates over every line in the stream. ## The iteration is based on ``readLine``. ## ## See also: ## * `readLine(Stream) proc <#readLine,Stream>`_ - ## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_ + ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_ runnableExamples: var strm = newStringStream("The first line\nthe second line\nthe third line") var lines: seq[string] @@ -1121,7 +1113,7 @@ iterator lines*(s: Stream): TaintedString = doAssert lines == @["The first line", "the second line", "the third line"] strm.close() - var line: TaintedString + var line: string while s.readLine(line): yield line @@ -1158,10 +1150,7 @@ when (NimMajor, NimMinor) < (1, 3) and defined(js): proc ssClose(s: Stream) {.compileTime.} = var s = StringStream(s) - when defined(nimNoNilSeqs): - s.data = "" - else: - s.data = nil + s.data = "" proc newStringStream*(s: string = ""): owned StringStream {.compileTime.} = new(result) @@ -1187,7 +1176,7 @@ when (NimMajor, NimMinor) < (1, 3) and defined(js): if readBytes < bufferSize: break -else: # after 1.3 or JS not defined +else: # after 1.3 or JS not defined proc ssAtEnd(s: Stream): bool = var s = StringStream(s) return s.pos >= s.data.len @@ -1261,10 +1250,7 @@ else: # after 1.3 or JS not defined proc ssClose(s: Stream) = var s = StringStream(s) - when defined(nimNoNilSeqs): - s.data = "" - else: - s.data = nil + s.data = "" proc newStringStream*(s: string = ""): owned StringStream = ## Creates a new stream from the string `s`. @@ -1333,7 +1319,7 @@ 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 = +proc fsReadLine(s: Stream, line: var string): bool = result = readLine(FileStream(s).f, line) proc newFileStream*(f: File): owned FileStream = @@ -1401,7 +1387,7 @@ proc newFileStream*(filename: string, mode: FileMode = fmRead, ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a ## file stream from the file name and the mode. runnableExamples: - from os import removeFile + from std/os import removeFile var strm = newFileStream("somefile.txt", fmWrite) if not isNil(strm): strm.writeLine("The first line") diff --git a/lib/pure/streamwrapper.nim b/lib/pure/streamwrapper.nim index b99982f1b3..7a501760be 100644 --- a/lib/pure/streamwrapper.nim +++ b/lib/pure/streamwrapper.nim @@ -26,12 +26,12 @@ type baseReadLineImpl: typeof(StreamObj.readLineImpl) baseReadDataImpl: typeof(StreamObj.readDataImpl) -proc posReadLine[T](s: Stream, line: var TaintedString): bool = +proc posReadLine[T](s: Stream, line: var string): bool = var s = PipeOutStream[T](s) assert s.baseReadLineImpl != nil let n = s.buffer.len - line.string.setLen(0) + line.setLen(0) for i in 0.. 0 - line.string.add(c) + line.add(c) var line2: string result = s.baseReadLineImpl(s, line2) @@ -89,7 +89,7 @@ proc newPipeOutStream*[T](s: sink (ref T)): owned PipeOutStream[T] = ## Example: ## ## .. code-block:: Nim - ## import osproc, streamwrapper + ## import std/[osproc, streamwrapper] ## var ## p = startProcess(exePath) ## outStream = p.outputStream().newPipeOutStream() diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index ddf996e484..7ab3590388 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -9,163 +9,148 @@ ##[ String `interpolation`:idx: / `format`:idx: inspired by -Python's ``f``-strings. +Python's f-strings. -``fmt`` vs. ``&`` -================= +# `fmt` vs. `&` -You can use either ``fmt`` or the unary ``&`` operator for formatting. The +You can use either `fmt` or the unary `&` operator for formatting. The difference between them is subtle but important. -The ``fmt"{expr}"`` syntax is more aesthetically pleasing, but it hides a small +The `fmt"{expr}"` syntax is more aesthetically pleasing, but it hides a small gotcha. The string is a `generalized raw string literal `_. This has some surprising effects: +]## -.. code-block:: nim +runnableExamples: + let msg = "hello" + assert fmt"{msg}\n" == "hello\\n" - 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 +##[ +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: +]## -.. code-block:: nim +runnableExamples: + let msg = "hello" - import strformat - let msg = "hello" + assert &"{msg}\n" == "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" + assert fmt"{msg}{'\n'}" == "hello\n" + assert fmt("{msg}\n") == "hello\n" + assert "{msg}\n".fmt == "hello\n" +##[ The choice of style is up to you. -Formatting strings -================== +# Formatting strings +]## -.. code-block:: nim +runnableExamples: + assert &"""{"abc":>4}""" == " abc" + assert &"""{"abc":<4}""" == "abc " - import strformat +##[ +# Formatting floats +]## - doAssert &"""{"abc":>4}""" == " abc" - doAssert &"""{"abc":<4}""" == "abc " +runnableExamples: + assert fmt"{-12345:08}" == "-0012345" + assert fmt"{-1:3}" == " -1" + assert fmt"{-1:03}" == "-01" + assert fmt"{16:#X}" == "0x10" -Formatting floats -================= + 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 " -.. code-block:: nim + assert fmt"{123.456:e}" == "1.234560e+02" + assert fmt"{123.456:>13e}" == " 1.234560e+02" + assert fmt"{123.456:13e}" == " 1.234560e+02" - import strformat - doAssert fmt"{-12345:08}" == "-0012345" - doAssert fmt"{-1:3}" == " -1" - doAssert fmt"{-1:03}" == "-01" - doAssert fmt"{16:#X}" == "0x10" +##[ +# Debugging strings - 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" - - -Debugging strings -================= - -``fmt"{expr=}"`` expands to ``fmt"expr={expr}"`` namely the text of the expression, +`fmt"{expr=}"` expands to `fmt"expr={expr}"` namely the text of the expression, an equal sign and the results of evaluated expression. +]## -.. code-block:: nim +runnableExamples: + assert fmt"{123.456=}" == "123.456=123.456" + assert fmt"{123.456=:>9.3f}" == "123.456= 123.456" - import strformat - doAssert fmt"{123.456=}" == "123.456=123.456" - doAssert fmt"{123.456=:>9.3f}" == "123.456= 123.456" + let x = "hello" + assert fmt"{x=}" == "x=hello" + assert fmt"{x =}" == "x =hello" - 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 - let a = "hello" - let b = 3.1415926 - doAssert fmt"{hello(x, y) = }" == "hello(x, y) = 12" - doAssert fmt"{x.hello(y) = }" == "x.hello(y) = 12" - doAssert fmt"{hello x, y = }" == "hello x, y = 12" + 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" +##[ Note that it is space sensitive: +]## -.. code-block:: nim +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" - import strformat - 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" +##[ +# Implementation details - -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 an ``{`` or ``}`` double it. +as Nim code, to escape a `{` or `}`, double it. -``&`` 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 specifier for strings, integers and floats -========================================================== - +# Standard format specifiers for strings, integers and floats The general form of a standard format specifier is:: [[fill]align][sign][#][0][minimumwidth][.precision][type] -The square brackets ``[]`` indicate an optional element. +The square brackets `[]` indicate an optional element. -The optional align flag can be one of the following: +The optional 'align' flag can be one of the following: '<' Forces the field to be left-aligned within the available @@ -191,17 +176,17 @@ The 'sign' option is only valid for numeric types, and can be one of the followi ================= ==================================================== 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. +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, then the field width will be determined by the content. @@ -218,48 +203,44 @@ 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 +`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' exponent notation. -``G`` General format. Same as 'g' except switches to 'E' +`G` General format. Same as 'g' except it 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: @@ -272,44 +253,40 @@ 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 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``. +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`. +# 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 also -helps in readability since there is only so much you can cram into +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 single letter DSLs. - ]## -import macros, parseutils, unicode -import strutils except format +import std/[macros, parseutils, unicode] +import std/strutils except format proc mkDigit(v: int, typ: char): string {.inline.} = assert(v < 26) @@ -318,10 +295,9 @@ 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 ``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 the `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 @@ -343,28 +319,30 @@ 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 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. +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. when n is SomeUnsignedInt: var v = n.uint64 let negative = false else: - var v = n.int64 - let negative = v.int64 < 0 - if negative: - # FIXME: overflow error for low(int64) - v = v * -1 + 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 xx = "" if spec.alternateForm: @@ -379,9 +357,9 @@ proc formatInt(n: SomeNumber; radix: int; result = "0" else: result = "" - while v > type(v)(0): - let d = v mod type(v)(radix) - v = v div type(v)(radix) + while v > typeof(v)(0): + let d = v mod typeof(v)(radix) + v = v div typeof(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] @@ -417,9 +395,9 @@ proc parseStandardFormatSpecifier*(s: string; start = 0; ## ## [[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' @@ -441,7 +419,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 @@ -463,10 +441,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 @@ -484,9 +462,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 @@ -541,9 +519,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 @@ -557,8 +535,7 @@ 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) @@ -647,16 +624,18 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = echo repr result macro `&`*(pattern: string): untyped = strformatImpl(pattern, '{', '}') - ## For a specification of the ``&`` macro, see the module level documentation. + ## For a specification of the `&` macro, see the module level documentation. macro fmt*(pattern: string): untyped = strformatImpl(pattern, '{', '}') - ## An alias for ``&``. + ## An alias for `& <#&.m,string>`_. macro fmt*(pattern: string; openChar, closeChar: char): untyped = - ## Use ``openChar`` instead of '{' and ``closeChar`` instead of '}' + ## The same as `fmt <#fmt.m,string>`_, but uses `openChar` instead of `'{'` + ## and `closeChar` instead of `'}'`. runnableExamples: let testInt = 123 - doAssert "".fmt('<', '>') == "123" - doAssert """(()"foo" & "bar"())""".fmt(')', '(') == "(foobar)" - doAssert """ ""{"123+123"}"" """.fmt('"', '"') == " \"{246}\" " + assert "".fmt('<', '>') == "123" + assert """(()"foo" & "bar"())""".fmt(')', '(') == "(foobar)" + assert """ ""{"123+123"}"" """.fmt('"', '"') == " \"{246}\" " + strformatImpl(pattern, openChar.intVal.char, closeChar.intVal.char) diff --git a/lib/pure/strmisc.nim b/lib/pure/strmisc.nim index 5060deb78d..c8cd839be2 100644 --- a/lib/pure/strmisc.nim +++ b/lib/pure/strmisc.nim @@ -8,12 +8,12 @@ # ## This module contains various string utility routines that are uncommonly -## used in comparison to `strutils `_. +## used in comparison to the ones in `strutils `_. -import strutils +import std/strutils -proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect.} = - ## Expand tab characters in `s` replacing them by spaces. +func expandTabs*(s: string, tabSize: int = 8): string = + ## Expands 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,9 +24,7 @@ proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect.} = runnableExamples: 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("ab\tcd\n\txy\t", 3) == "ab cd\n xy " + doAssert expandTabs("a\tb\n\txy\t", 3) == "a b\n xy " result = newStringOfCap(s.len + s.len shr 2) var pos = 0 @@ -50,37 +48,39 @@ proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect.} = if c == '\l': pos = 0 -proc partition*(s: string, sep: string, - right: bool = false): (string, string, string) - {.noSideEffect.} = - ## Split the string at the first or last occurrence of `sep` into a 3-tuple +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. ## - ## 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 + ## 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>`_ runnableExamples: - 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 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") 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, "", "") -proc rpartition*(s: string, sep: string): (string, string, string) - {.noSideEffect.} = - ## Split the string at the last occurrence of `sep` into a 3-tuple +func rpartition*(s: string, sep: string): (string, string, string) = + ## Splits the string at the last occurrence of `sep` into a 3-tuple. ## - ## Returns a 3 string tuple of (beforeSep, `sep`, afterSep) or - ## ("", "", `s`) if `sep` is not found + ## 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>`_ runnableExamples: - 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", "") + doAssert rpartition("foo:bar:baz", ":") == ("foo:bar", ":", "baz") + doAssert rpartition("foobar", ":") == ("", "", "foobar") - return partition(s, sep, right = true) + partition(s, sep, right = true) diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 9c55bf3e3c..73b53e3d68 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -175,7 +175,7 @@ overloaded to handle both single characters and sets of character. .. code-block:: nim - import streams + import std/streams template atom(input: Stream; idx: int; c: char): bool = ## Used in scanp for the matching of atoms (usually chars). @@ -577,6 +577,7 @@ 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 @@ -688,4 +689,4 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool = result.add toIfChain(conds, idx, res, 0) result.add res when defined(debugScanp): - echo repr result \ No newline at end of file + echo repr result diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 7cf668d192..3b90fea509 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -300,11 +300,10 @@ proc raiseFormatException(s: string) = proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string = if hasKey(t, key): return t.getOrDefault(key) - # hm difficult: assume safety in taint mode here. XXX This is dangerous! when defined(js) or defined(nimscript) or defined(Standalone): result = "" else: - if useEnvironment in flags: result = getEnv(key).string + if useEnvironment in flags: result = getEnv(key) else: result = "" if result.len == 0: if useKey in flags: result = '$' & key diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 0028ac4fba..4098749ce6 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -38,7 +38,7 @@ runnableExamples: ## `method call syntax`_: runnableExamples: - from sequtils import map + from std/sequtils import map let jenny = "867-5309" assert jenny.split('-').map(parseInt) == @[867, 5309] @@ -75,12 +75,13 @@ from math import pow, floor, log10 from algorithm import reverse import std/enumutils -when defined(nimVmExportFixed): - from unicode import toLower, toUpper - export toLower, toUpper +from unicode import toLower, toUpper +export toLower, toUpper include "system/inclrtl" import std/private/since +from std/private/strimpl import cmpIgnoreStyleImpl, cmpIgnoreCaseImpl, startsWithImpl, endsWithImpl + const Whitespace* = {' ', '\t', '\v', '\r', '\l', '\f'} @@ -319,13 +320,7 @@ func cmpIgnoreCase*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreCase".} = doAssert cmpIgnoreCase("FooBar", "foobar") == 0 doAssert cmpIgnoreCase("bar", "Foo") < 0 doAssert cmpIgnoreCase("Foo5", "foo4") > 0 - 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 + cmpIgnoreCaseImpl(a, b) {.push checks: off, line_trace: off.} # this is a hot-spot in the compiler! # thus we compile without checks here @@ -344,25 +339,7 @@ func cmpIgnoreStyle*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreStyle".} = runnableExamples: doAssert cmpIgnoreStyle("foo_bar", "FooBar") == 0 doAssert cmpIgnoreStyle("foo_bar_5", "FooBar4") > 0 - 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 + cmpIgnoreStyleImpl(a, b) {.pop.} # --------- Private templates for different split separators ----------- @@ -1552,11 +1529,7 @@ func startsWith*(s, prefix: string): bool {.rtl, extern: "nsuStartsWith".} = let a = "abracadabra" doAssert a.startsWith("abra") == true doAssert a.startsWith("bra") == false - var i = 0 - while true: - if i >= prefix.len: return true - if i >= s.len or s[i] != prefix[i]: return false - inc(i) + startsWithImpl(s, prefix) func endsWith*(s: string, suffix: char): bool {.inline.} = ## Returns true if `s` ends with `suffix`. @@ -1584,12 +1557,7 @@ func endsWith*(s, suffix: string): bool {.rtl, extern: "nsuEndsWith".} = let a = "abracadabra" doAssert a.endsWith("abra") == true doAssert a.endsWith("dab") == false - 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 + endsWithImpl(s, suffix) func continuesWith*(s, substr: string, start: Natural): bool {.rtl, extern: "nsuContinuesWith".} = @@ -2069,7 +2037,7 @@ func contains*(s: string, chars: set[char]): bool = func replace*(s, sub: string, by = ""): string {.rtl, extern: "nsuReplaceStr".} = - ## Replaces `sub` in `s` by the string `by`. + ## Replaces every occurrence of the string `sub` in `s` with the string `by`. ## ## See also: ## * `find func<#find,string,string,Natural,int>`_ @@ -2111,7 +2079,8 @@ func replace*(s, sub: string, by = ""): string {.rtl, func replace*(s: string, sub, by: char): string {.rtl, extern: "nsuReplaceChar".} = - ## Replaces `sub` in `s` by the character `by`. + ## Replaces every occurrence of the character `sub` in `s` with the character + ## `by`. ## ## Optimized version of `replace <#replace,string,string,string>`_ for ## characters. @@ -2129,7 +2098,7 @@ func replace*(s: string, sub, by: char): string {.rtl, func replaceWord*(s, sub: string, by = ""): string {.rtl, extern: "nsuReplaceWord".} = - ## Replaces `sub` in `s` by the string `by`. + ## Replaces every occurrence of the string `sub` in `s` with the string `by`. ## ## Each occurrence of `sub` has to be surrounded by word boundaries ## (comparable to `\b` in regular expressions), otherwise it is not @@ -2237,7 +2206,7 @@ func escape*(s: string, prefix = "\"", suffix = "\""): string {.rtl, ## ## See also: ## * `unescape func<#unescape,string,string,string>`_ for the opposite - ## operation + ## operation result = newStringOfCap(s.len + s.len shr 2) result.add(prefix) for c in items(s): @@ -2372,17 +2341,11 @@ func formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault, frmtstr[3] = '*' frmtstr[4] = floatFormatToChar[format] frmtstr[5] = '\0' - when defined(nimNoArrayToCstringConversion): - L = c_sprintf(addr buf, addr frmtstr, precision, f) - else: - L = c_sprintf(buf, frmtstr, precision, f) + L = c_sprintf(addr buf, addr 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) + L = c_sprintf(addr buf, addr frmtstr, f) result = newString(L) for i in 0 ..< L: # Depending on the locale either dot or comma is produced, @@ -2791,6 +2754,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>`_ runnableExamples: let a = " vhellov " diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 6867295151..9654a06785 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -11,7 +11,7 @@ ## macro system. import std/private/since -import macros, typetraits +import std/macros proc checkPragma(ex, prag: var NimNode) = since (1, 3): @@ -53,22 +53,23 @@ proc createProcType(p, b: NimNode): NimNode {.compileTime.} = result.add prag macro `=>`*(p, b: untyped): untyped = - ## Syntax sugar for anonymous procedures. - ## It also supports pragmas. + ## Syntax sugar for anonymous procedures. It also supports pragmas. runnableExamples: - proc passTwoAndTwo(f: (int, int) -> int): int = - f(2, 2) + proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2) - doAssert passTwoAndTwo((x, y) => x + y) == 4 + assert passTwoAndTwo((x, y) => x + y) == 4 type Bot = object - call: proc (name: string): string {.noSideEffect.} + call: (string {.noSideEffect.} -> string) var myBot = Bot() myBot.call = (name: string) {.noSideEffect.} => "Hello " & name & ", I'm a bot." - doAssert myBot.call("John") == "Hello John, 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"] @@ -85,16 +86,6 @@ macro `=>`*(p, b: untyped): untyped = checkPragma(p, pragma) # check again after -> transform - since (1, 3): - if p.kind in {nnkCall, nnkObjConstr}: - # foo(x, y) => x + y - kind = nnkProcDef - name = p[0] - let newP = newNimNode(nnkPar) - for i in 1..`*(p, b: untyped): untyped = procType = kind) macro `->`*(p, b: untyped): untyped = - ## Syntax sugar for procedure types. - ## - ## .. 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) + ## Syntax sugar for procedure types. It also supports pragmas. + 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 result = createProcType(p, b) @@ -161,19 +154,44 @@ macro dump*(x: untyped): untyped = ## of the tree representing the expression - as it would appear in ## source code - together with the value of the expression. ## - ## As an example, - ## - ## .. code-block:: nim - ## let - ## x = 10 - ## y = 20 - ## dump(x + y) - ## - ## will print ``x + y = 30``. + ## 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` + let s = x.toStrLit - let r = quote do: + result = quote do: debugEcho `s`, " = ", `x` - return r + +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 + nonexistant) + 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 # TODO: consider exporting this in macros.nim proc freshIdentNodes(ast: NimNode): NimNode = @@ -193,21 +211,18 @@ proc freshIdentNodes(ast: NimNode): NimNode = macro capture*(locals: varargs[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. 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 + ## 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" + var params = @[newIdentNode("auto")] let locals = if locals.len == 1 and locals[0].kind == nnkBracket: locals[0] else: locals @@ -216,11 +231,11 @@ macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).} error("The variable name cannot be `result`!", arg) params.add(newIdentDefs(ident(arg.strVal), freshIdentNodes getTypeInst arg)) result = newNimNode(nnkCall) - result.add(newProc(newEmptyNode(), params, body, nnkProcDef)) + result.add(newProc(newEmptyNode(), params, body, nnkLambda)) for arg in locals: result.add(arg) since (1, 1): - import std / private / underscored_calls + import std/private/underscored_calls macro dup*[T](arg: T, calls: varargs[untyped]): T = ## Turns an `in-place`:idx: algorithm into one that works on @@ -228,41 +243,39 @@ since (1, 1): ## ## This macro also allows for (otherwise in-place) function chaining. ## - ## **Since**: Version 1.2. + ## **Since:** Version 1.2. runnableExamples: - import algorithm + import std/algorithm + + let a = @[1, 2, 3, 4, 5, 6, 7, 8, 9] + assert a.dup(sort) == sorted(a) - var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9] - doAssert a.dup(sort) == sorted(a) # Chaining: var aCopy = a aCopy.insert(10) + assert a.dup(insert(10), sort) == sorted(aCopy) - doAssert a.dup(insert(10), sort) == sorted(aCopy) + let s1 = "abc" + let s2 = "xyz" + assert s1 & s2 == s1.dup(&= s2) - var s1 = "abc" - var s2 = "xyz" - doAssert 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]) - var c = "xyz" - - # An underscore (_) can be used to denote the place of the argument you're passing: - doAssert "".dup(addQuoted(_, "foo")) == "\"foo\"" - # but `_` is optional here since the substitution is in 1st position: - doAssert "".dup(addQuoted("foo")) == "\"foo\"" + let c = "xyz" # chaining: - # b = "xyz" - var d = dup c: + let d = dup c: makePalindrome # xyzyx sort(_, SortOrder.Descending) # zyyxx makePalindrome # zyyxxxyyz - - doAssert d == "zyyxxxyyz" + assert d == "zyyxxxyyz" result = newNimNode(nnkStmtListExpr, arg) let tmp = genSym(nskVar, "dupResult") @@ -344,51 +357,60 @@ macro collect*(init, body: untyped): untyped {.since: (1, 1).} = # analyse the body, find the deepest expression 'it' and replace it via # 'result.add it' runnableExamples: - import sets, tables + import std/[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} + ## HashSet: + let y = collect(initHashSet()): + 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 == {0: "bird", 1: "word"}.toTable + result = collectImpl(init, body) macro collect*(body: untyped): untyped {.since: (1, 5).} = ## Same as `collect` but without an `init` parameter. runnableExamples: - import sets, tables - # Seq: + 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) \ No newline at end of file + + # avoid `collect` when `sequtils.toSeq` suffices: + assert collect(for i in 1..3: i*i) == @[1, 4, 9] # ok in this case + assert collect(for i in 1..3: i) == @[1, 2, 3] # overkill in this case + from std/sequtils import toSeq + assert toSeq(1..3) == @[1, 2, 3] # simpler + + result = collectImpl(nil, body) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 3bda5b7aa6..cada721967 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -12,9 +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 ``system.addQuitProc(resetAttributes)`` to restore the defaults. +## code `exitprocs.addExitProc(resetAttributes)` to restore the defaults. ## Similarly, if you hide the cursor, make sure to unhide it with -## ``showCursor`` before quitting. +## `showCursor` before quitting. import macros import strformat @@ -48,8 +48,8 @@ proc getTerminal(): PTerminal {.inline.} = result = gTerm const - fgPrefix = "\x1b[38;2;" - bgPrefix = "\x1b[48;2;" + fgPrefix = "\e[38;2;" + bgPrefix = "\e[48;2;" ansiResetCode* = "\e[0m" stylePrefix = "\e[" @@ -253,7 +253,7 @@ else: discard close(fd) if w > 0: return w var s = getEnv("COLUMNS") #Try standard env var - if len(s) > 0 and parseInt(string(s), w) > 0 and w > 0: + if len(s) > 0 and parseInt(s, w) > 0 and w > 0: return w return 80 #Finally default to venerable value @@ -271,7 +271,7 @@ else: discard close(fd) if h > 0: return h var s = getEnv("LINES") # Try standard env var - if len(s) > 0 and parseInt(string(s), h) > 0 and h > 0: + if len(s) > 0 and parseInt(s, h) > 0 and h > 0: return h return 0 # Could not determine height @@ -332,7 +332,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 @@ -543,7 +543,7 @@ 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 @@ -555,7 +555,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): @@ -579,7 +579,7 @@ 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, toU16(old or defaultForegroundColor)) @@ -608,7 +608,7 @@ 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, toU16(old or defaultBackgroundColor)) @@ -697,10 +697,10 @@ template styledEchoProcessArg(f: File, cmd: TerminalCmd) = term.fgSetColor = cmd == fgColor 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. + ## 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: ## @@ -730,7 +730,7 @@ 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. + ## Calls `styledWrite` and appends a newline at the end. ## ## Example: ## @@ -743,7 +743,7 @@ template styledWriteLine*(f: File, args: varargs[untyped]) = 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 = @@ -769,14 +769,12 @@ proc getch*(): char = discard fd.tcSetAttr(TCSADRAIN, addr oldMode) when defined(windows): - from unicode import toUTF8, Rune, runeLenAt - - proc readPasswordFromStdin*(prompt: string, password: var TaintedString): + proc readPasswordFromStdin*(prompt: string, password: var string): 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.string.setLen(0) + ## be `nil`! Returns `false` if the end of the file has been reached, + ## `true` otherwise. + password.setLen(0) stdout.write(prompt) let hi = createFileA("CONIN$", GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0) @@ -797,9 +795,9 @@ when defined(windows): else: import termios - proc readPasswordFromStdin*(prompt: string, password: var TaintedString): + proc readPasswordFromStdin*(prompt: string, password: var string): bool {.tags: [ReadIOEffect, WriteIOEffect].} = - password.string.setLen(0) + password.setLen(0) let fd = stdin.getFileHandle() var cur, old: Termios discard fd.tcGetAttr(cur.addr) @@ -811,9 +809,9 @@ else: stdout.write "\n" discard fd.tcSetAttr(TCSADRAIN, old.addr) -proc readPasswordFromStdin*(prompt = "password: "): TaintedString = +proc readPasswordFromStdin*(prompt = "password: "): string = ## Reads a password from stdin without printing it. - result = TaintedString("") + result = "" discard readPasswordFromStdin(prompt, result) @@ -843,7 +841,7 @@ template setBackgroundColor*(color: Color) = proc resetAttributes*() {.noconv.} = ## Resets all attributes on stdout. ## It is advisable to register this as a quit proc with - ## ``system.addQuitProc(resetAttributes)``. + ## `exitprocs.addExitProc(resetAttributes)`. resetAttributes(stdout) proc isTrueColorSupported*(): bool = @@ -882,7 +880,7 @@ proc enableTrueColors*() = else: term.trueColorIsEnabled = true else: - term.trueColorIsSupported = string(getEnv("COLORTERM")).toLowerAscii() in [ + term.trueColorIsSupported = getEnv("COLORTERM").toLowerAscii() in [ "truecolor", "24bit"] term.trueColorIsEnabled = term.trueColorIsSupported @@ -908,7 +906,7 @@ proc newTerminal(): owned(PTerminal) = when not defined(testing) and isMainModule: assert ansiStyleCode(styleBright) == "\e[1m" assert ansiStyleCode(styleStrikethrough) == "\e[9m" - #system.addQuitProc(resetAttributes) + # exitprocs.addExitProc(resetAttributes) write(stdout, "never mind") stdout.eraseLine() stdout.styledWriteLine({styleBright, styleBlink, styleUnderscore}, "styled text ") diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 35dda131b3..e763b17bbd 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 times, os + import std/[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,124 +51,128 @@ 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`` - ``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`` - ============= ================================================================================= ================================================ + =========== ================================================================================= ============================================== + 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` + =========== ================================================================================= ============================================== - 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: @@ -182,8 +186,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. @@ -249,9 +253,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" @@ -291,7 +295,7 @@ type 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 + ## not ignored, but the `DateTime`'s returned by procedures in this ## module will never have a leap second. nanosecond: NanosecondRange second: SecondRange @@ -309,7 +313,7 @@ type 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 proc + ## To create a new `Duration`, use `initDuration proc ## <#initDuration,int64,int64,int64,int64,int64,int64,int64,int64>`_. seconds: int64 nanosecond: NanosecondRange @@ -319,23 +323,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 @@ -351,7 +355,7 @@ type Timezone* = ref object ## \ ## Timezone interface for supporting `DateTime <#DateTime>`_\s of arbitrary - ## timezones. The ``times`` module only supplies implementations for the + ## timezones. The `times` module only supplies implementations for the ## systems local time and UTC. zonedTimeFromTimeImpl: proc (x: Time): ZonedTime {.tags: [], raises: [], benign.} @@ -411,8 +415,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: @@ -421,14 +425,14 @@ proc normalize[T: Duration|Time](seconds, nanoseconds: int64): T = result.nanosecond = nanosecond.int 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 @@ -481,7 +485,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 ``initDateTime(monthday, month, year, 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 @@ -501,7 +505,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 ``initDateTime(monthday, month, year, 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" @@ -516,7 +520,7 @@ proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay result = if wd == 0: dSun else: WeekDay(wd - 1) proc getDaysInYear*(year: int): int = - ## Get the number of days in a ``year`` + ## Get the number of days in a `year` runnableExamples: doAssert getDaysInYear(2000) == 366 doAssert getDaysInYear(2001) == 365 @@ -677,9 +681,9 @@ 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 @@ -709,7 +713,7 @@ proc toParts*(dur: Duration): DurationParts = result[unit] = quantity 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" @@ -749,9 +753,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) @@ -832,20 +836,20 @@ proc initTime*(unix: int64, nanosecond: NanosecondRange): Time = result.nanosecond = nanosecond proc nanosecond*(time: Time): NanosecondRange = - ## Get the fractional part of a ``Time`` as the number + ## 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``. + ## 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``). + ## 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 @@ -875,19 +879,19 @@ since((1, 1)): proc fromWinTime*(win: int64): Time = ## Convert a Windows file time (100-nanosecond intervals since - ## ``1601-01-01T00:00:00Z``) to a ``Time``. + ## `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``). + ## 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 getTime*(): Time {.tags: [TimeEffect], benign.} = - ## Gets the current time as a ``Time`` with up to nanosecond resolution. + ## 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) @@ -916,29 +920,29 @@ proc `-`*(a, b: Time): Duration {.operator, extern: "ntDiffTime".} = subImpl[Duration](a, b) proc `+`*(a: Time, b: Duration): Time {.operator, extern: "ntAddTime".} = - ## Add a duration of time to a ``Time``. + ## 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``. + ## 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``. + ## 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``. + ## 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. + ## 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) = @@ -1024,7 +1028,7 @@ proc isDst*(dt: DateTime): bool {.inline.} = proc timezone*(dt: DateTime): Timezone {.inline.} = ## The timezone represented as an implementation - ## of ``Timezone``. + ## of `Timezone`. assertDateTimeInitialized(dt) dt.timezone @@ -1032,9 +1036,9 @@ 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 + ## formatted offset string like `+01:00` (which ## would be equivalent to the UTC offset - ## ``-3600``). + ## `-3600`). assertDateTimeInitialized(dt) dt.utcOffset @@ -1063,7 +1067,7 @@ proc isLeapDay*(dt: DateTime): bool {.since: (1, 1).} = 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. + ## Converts a `DateTime` to a `Time` representing the same point in time. assertDateTimeInitialized dt let epochDay = toEpochDay(dt.monthday, dt.month, dt.year) var seconds = epochDay * secondsInDay @@ -1074,7 +1078,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) @@ -1109,11 +1113,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 @@ -1143,15 +1147,15 @@ proc name*(zone: Timezone): string = 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 = @@ -1159,7 +1163,7 @@ proc `$`*(zone: Timezone): string = if zone != nil: result = zone.name proc `==`*(zone1, zone2: Timezone): bool = - ## Two ``Timezone``'s are considered equal if their name is equal. + ## Two `Timezone`'s are considered equal if their name is equal. runnableExamples: doAssert local() == local() doAssert local() != utc() @@ -1171,13 +1175,13 @@ proc `==`*(zone1, zone2: Timezone): bool = 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. + ## Returns a `DateTime` representing the same point in time as `dt` but + ## using `zone` as the timezone. assertDateTimeInitialized dt dt.toTime.inZone(zone) @@ -1283,7 +1287,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" @@ -1292,7 +1296,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" @@ -1302,25 +1306,27 @@ 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 now*(): DateTime {.tags: [TimeEffect], benign.} = - ## Get the current time as a ``DateTime`` in the local timezone. + ## Get the current time as a `DateTime` in the local timezone. + ## Shorthand for `getTime().local`. ## - ## Shorthand for ``getTime().local``. + ## .. warning:: Unsuitable for benchmarking, use `monotimes.getMonoTime` or + ## `cpuTime` instead, depending on the use case. getTime().local proc initDateTime*(monthday: MonthdayRange, month: Month, year: int, @@ -1370,7 +1376,7 @@ proc `-`*(dt: DateTime, dur: Duration): DateTime = (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 = initDateTime(30, mMar, 2017, 00, 00, 00, utc()) let dt2 = initDateTime(25, mMar, 2017, 00, 00, 00, utc()) @@ -1380,15 +1386,15 @@ proc `-`*(dt1, dt2: DateTime): Duration = 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. + ## 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 @@ -1400,7 +1406,7 @@ proc `-=`*(a: var DateTime, b: Duration) = 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``. + ## Gets the current local date as a string of the format `YYYY-MM-DD`. runnableExamples: echo getDateStr(now() - 1.months) assertDateTimeInitialized dt @@ -1408,7 +1414,7 @@ proc getDateStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} '-' & 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``. + ## Gets the current local clock time as a string of the format `HH:mm:ss`. runnableExamples: echo getClockStr(now() - 1.hours) assertDateTimeInitialized dt @@ -1469,30 +1475,31 @@ type 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( @@ -1508,7 +1515,7 @@ 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" @@ -1621,6 +1628,8 @@ 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") @@ -1629,7 +1638,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) @@ -1727,7 +1736,7 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string, result.add '+' & $year of UUUU: result.add $dt.year - of z, zz, zzz, zzzz: + of z, zz, zzz, zzzz, ZZZ, ZZZZ: if dt.timezone != nil and dt.timezone.name == "Etc/UTC": result.add 'Z' else: @@ -1738,16 +1747,18 @@ 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: + of zzz, ZZZ: let h = (absOffset div 3600).intToStr(2) let m = ((absOffset div 60) mod 60).intToStr(2) - result.add h & ":" & m - of zzzz: + let sep = if pattern == zzz: ":" else: "" + result.add h & sep & m + of zzzz, 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) - result.add h & ":" & m & ":" & s + let sep = if pattern == zzzz: ":" else: "" + result.add h & sep & m & sep & s else: assert false of g: result.add if dt.year < 1: "BC" else: "AD" @@ -1881,7 +1892,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: + of z, zz, zzz, zzzz, ZZZ, ZZZZ: case input[i] of '+', '-': let sign = if input[i] == '-': 1 else: -1 @@ -1892,21 +1903,24 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int, offset = takeInt(1..2) * 3600 of zz: offset = takeInt(2..2) * 3600 - of zzz: + of zzz, ZZZ: offset.inc takeInt(2..2) * 3600 - if input[i] != ':': - return false - i.inc + if pattern == zzz: + if input[i] != ':': + return false + i.inc offset.inc takeInt(2..2) * 60 - of zzzz: + of zzzz, ZZZZ: offset.inc takeInt(2..2) * 3600 - if input[i] != ':': - return false - i.inc + if pattern == zzzz: + if input[i] != ':': + return false + i.inc offset.inc takeInt(2..2) * 60 - if input[i] != ':': - return false - i.inc + if pattern == zzzz: + if input[i] != ':': + return false + i.inc offset.inc takeInt(2..2) else: assert false parsed.utcOffset = some(offset * sign) @@ -1981,7 +1995,7 @@ proc toDateTime(p: ParsedTime, zone: Timezone, f: TimeFormat, 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 = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) @@ -2004,10 +2018,10 @@ 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 = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) doAssert "2000-01-01" == format(dt, "yyyy-MM-dd") @@ -2015,7 +2029,7 @@ proc format*(dt: DateTime, f: string, loc: DateTimeLocale = DefaultLocale): stri 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) @@ -2026,11 +2040,11 @@ proc formatValue*(result: var string; value: DateTime, specifier: string) = 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 = initDateTime(01, mJan, 1970, 00, 00, 00, utc()) var tm = dt.toTime() @@ -2039,23 +2053,23 @@ proc format*(time: Time, f: string, zone: Timezone = local()): string 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. + ## 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 {.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. + ## 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 = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) @@ -2094,11 +2108,11 @@ proc parse*(input: string, f: TimeFormat, zone: Timezone = local(), proc parse*(input, f: string, tz: Timezone = local(), loc: DateTimeLocale = DefaultLocale): DateTime {.raises: [TimeParseError, TimeFormatParseError, Defect].} = - ## Shorthand for constructing a ``TimeFormat`` and using it to parse - ## ``input`` as a ``DateTime``. + ## 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 = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) doAssert dt == parse("2000-01-01", "yyyy-MM-dd", utc()) @@ -2108,17 +2122,17 @@ proc parse*(input, f: string, tz: Timezone = local(), proc parse*(input: string, f: static[string], zone: Timezone = local(), loc: DateTimeLocale = DefaultLocale): DateTime {.raises: [TimeParseError, Defect].} = - ## Overload that validates ``f`` at compile time. + ## 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 {.raises: [TimeParseError, TimeFormatParseError, Defect].} = - ## Shorthand for constructing a ``TimeFormat`` and using it to parse - ## ``input`` as a ``DateTime``, then converting it a ``Time``. + ## 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) @@ -2126,13 +2140,13 @@ proc parseTime*(input, f: string, zone: Timezone): Time proc parseTime*(input: string, f: static[string], zone: Timezone): Time {.raises: [TimeParseError, Defect].} = - ## Overload that validates ``format`` at compile time. + ## Overload that validates `format` at compile time. const f2 = initTimeFormat(f) result = input.parse(f2, zone).toTime() 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 = initDateTime(01, mJan, 2000, 12, 00, 00, utc()) doAssert $dt == "2000-01-01T12:00:00Z" @@ -2144,7 +2158,7 @@ proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} = 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 = initDateTime(01, mJan, 1970, 00, 00, 00, local()) let tm = dt.toTime() @@ -2161,11 +2175,11 @@ proc initTimeInterval*(nanoseconds, microseconds, milliseconds, ## Creates a new `TimeInterval <#TimeInterval>`_. ## ## This proc doesn't perform any normalization! For example, - ## ``initTimeInterval(hours = 24)`` and ``initTimeInterval(days = 1)`` are + ## `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``. + ## 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()) @@ -2183,7 +2197,7 @@ proc initTimeInterval*(nanoseconds, microseconds, milliseconds, result.years = years proc `+`*(ti1, ti2: TimeInterval): TimeInterval = - ## Adds two ``TimeInterval`` objects together. + ## Adds two `TimeInterval` objects together. result.nanoseconds = ti1.nanoseconds + ti2.nanoseconds result.microseconds = ti1.microseconds + ti2.microseconds result.milliseconds = ti1.milliseconds + ti2.milliseconds @@ -2215,7 +2229,7 @@ proc `-`*(ti: TimeInterval): TimeInterval = ) proc `-`*(ti1, ti2: TimeInterval): TimeInterval = - ## Subtracts TimeInterval ``ti1`` from ``ti2``. + ## Subtracts TimeInterval `ti1` from `ti2`. ## ## Time components are subtracted one-by-one, see output: runnableExamples: @@ -2245,8 +2259,8 @@ proc evaluateStaticInterval(interval: TimeInterval): Duration = 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: + ## 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 @@ -2350,10 +2364,10 @@ proc between*(startDt, endDt: DateTime): TimeInterval = result.nanoseconds = parts[Nanoseconds].int proc toParts*(ti: TimeInterval): TimeIntervalParts = - ## Converts a ``TimeInterval`` into an array consisting of its time units, + ## 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. + ## 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)) @@ -2366,7 +2380,7 @@ proc toParts*(ti: TimeInterval): TimeIntervalParts = index += 1 proc `$`*(ti: TimeInterval): string = - ## Get string representation of ``TimeInterval``. + ## Get string representation of `TimeInterval`. runnableExamples: doAssert $initTimeInterval(years = 1, nanoseconds = 123) == "1 year and 123 nanoseconds" @@ -2381,63 +2395,63 @@ proc `$`*(ti: TimeInterval): string = result = humanizeParts(parts) proc nanoseconds*(nanos: int): TimeInterval {.inline.} = - ## TimeInterval of ``nanos`` nanoseconds. + ## TimeInterval of `nanos` nanoseconds. initTimeInterval(nanoseconds = nanos) proc microseconds*(micros: int): TimeInterval {.inline.} = - ## TimeInterval of ``micros`` microseconds. + ## TimeInterval of `micros` microseconds. initTimeInterval(microseconds = micros) proc milliseconds*(ms: int): TimeInterval {.inline.} = - ## TimeInterval of ``ms`` milliseconds. + ## TimeInterval of `ms` milliseconds. initTimeInterval(milliseconds = ms) proc seconds*(s: int): TimeInterval {.inline.} = - ## TimeInterval of ``s`` seconds. + ## TimeInterval of `s` seconds. ## - ## ``echo getTime() + 5.seconds`` + ## `echo getTime() + 5.seconds` initTimeInterval(seconds = s) proc minutes*(m: int): TimeInterval {.inline.} = - ## TimeInterval of ``m`` minutes. + ## TimeInterval of `m` minutes. ## - ## ``echo getTime() + 5.minutes`` + ## `echo getTime() + 5.minutes` initTimeInterval(minutes = m) proc hours*(h: int): TimeInterval {.inline.} = - ## TimeInterval of ``h`` hours. + ## TimeInterval of `h` hours. ## - ## ``echo getTime() + 2.hours`` + ## `echo getTime() + 2.hours` initTimeInterval(hours = h) proc days*(d: int): TimeInterval {.inline.} = - ## TimeInterval of ``d`` days. + ## TimeInterval of `d` days. ## - ## ``echo getTime() + 2.days`` + ## `echo getTime() + 2.days` initTimeInterval(days = d) proc weeks*(w: int): TimeInterval {.inline.} = - ## TimeInterval of ``w`` weeks. + ## TimeInterval of `w` weeks. ## - ## ``echo getTime() + 2.weeks`` + ## `echo getTime() + 2.weeks` initTimeInterval(weeks = w) proc months*(m: int): TimeInterval {.inline.} = - ## TimeInterval of ``m`` months. + ## TimeInterval of `m` months. ## - ## ``echo getTime() + 2.months`` + ## `echo getTime() + 2.months` initTimeInterval(months = m) proc years*(y: int): TimeInterval {.inline.} = - ## TimeInterval of ``y`` years. + ## TimeInterval of `y` years. ## - ## ``echo getTime() + 2.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``. + ## 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 @@ -2476,9 +2490,9 @@ proc evaluateInterval(dt: DateTime, interval: TimeInterval): 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 + ## 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 @@ -2505,9 +2519,9 @@ proc `+`*(dt: DateTime, interval: TimeInterval): DateTime = 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 + ## 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()) @@ -2562,7 +2576,10 @@ proc epochTime*(): float {.tags: [TimeEffect].} = ## because sub-second resolution is likely to be supported (depending ## on the hardware/OS). ## - ## ``getTime`` should generally be preferred over this proc. + ## `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) @@ -2597,11 +2614,11 @@ when not defined(js): 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``. + ## 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) diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 7b6c94cbd6..6827e23b1a 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -15,103 +15,167 @@ import std/private/since export system.`$` # for backward compatibility -proc name*(t: typedesc): string {.magic: "TypeTrait".} +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 the given type. ## - ## Alias for system.`$`(t) since Nim v0.20. + ## Alias for `system.\`$\`(t) `_ since Nim v0.20. + runnableExamples: + doAssert name(int) == "int" + doAssert name(seq[string]) == "seq[string]" proc arity*(t: typedesc): int {.magic: "TypeTrait".} = ## 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. + ## components or the number of generic parameters a given type `t` has. runnableExamples: - assert arity(seq[string]) == 1 - assert arity(array[3, int]) == 2 - assert arity((int, int, float, string)) == 4 + doAssert arity(int) == 0 + doAssert arity(seq[string]) == 1 + doAssert arity(array[3, int]) == 2 + doAssert 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 <#stripGenericParams,typedesc>`_ - ## - ## Example: - ## - ## .. code-block:: nim - ## type - ## Functor[A] = concept f - ## type MatchedGenericType = genericHead(typeof(f)) - ## # `f` will be a value of a type such as `Option[T]` - ## # `MatchedGenericType` will become the `Option` type + ## **See also:** + ## * `stripGenericParams proc <#stripGenericParams,typedesc>`_ + runnableExamples: + type + Foo[T] = object + FooInst = Foo[int] + Foo2 = genericHead(FooInst) + doAssert Foo2 is Foo and Foo is Foo2 + doAssert genericHead(Foo[seq[string]]) is Foo + doAssert not compiles(genericHead(int)) -proc stripGenericParams*(t: typedesc): typedesc {.magic: "TypeTrait".} + 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".} = ## This trait is similar to `genericHead <#genericHead,typedesc>`_, but - ## instead of producing error for non-generic types, it will just return + ## instead of producing an 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".} - ## This trait returns true if the type ``t`` is safe to use for + ## This trait returns true if 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".} - ## Return true for named tuples, false for any other type. +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 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): typedesc {.magic: "TypeTrait".} = + ## Returns the base type for distinct types, or the type itself otherwise. + ## + ## **See also:** + ## * `distinctBase template <#distinctBase.t,T>`_ + runnableExamples: + type MyInt = distinct int + doAssert distinctBase(MyInt) is int + doAssert distinctBase(int) is int since (1, 1): template distinctBase*[T](a: T): untyped = - ## overload for values + ## Overload of `distinctBase <#distinctBase,typedesc>`_ for values. runnableExamples: type MyInt = distinct int doAssert 12.MyInt.distinctBase == 12 - distinctBase(type(a))(a) + doAssert 12.distinctBase == 12 + when T is distinct: + distinctBase(typeof(a))(a) + else: # avoids hint ConvFromXtoItselfNotNeeded + a - proc tupleLen*(T: typedesc[tuple]): int {.magic: "TypeTrait".} - ## Return number of elements of `T` + 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 = - ## Return number of elements of `t` - tupleLen(type(t)) + ## 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 = - ## Return `i`\th element of `T` + ## Returns the `i`-th element of `T`. # Note: `[]` currently gives: `Error: no generic parameters allowed for ...` - type(default(T)[i]) + runnableExamples: + doAssert get((int, int, float, string), 2) is float + + typeof(default(T)[i]) type StaticParam*[value: static type] = object - ## used to wrap a static value in `genericParams` + ## Used to wrap a static value in `genericParams <#genericParams.t,typedesc>`_. since (1, 3, 5): template elementType*(a: untyped): typedesc = - ## return element type of `a`, which can be any iterable (over which you - ## can iterate) + ## 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..`_ 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 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. +## 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. ## -## 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. +## 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. -import unicode +import std/unicode when not defined(noUnidecodeTable): - import strutils + import std/strutils const translationTable = splitLines(slurp"unidecode/unidecode.dat") else: @@ -38,25 +39,26 @@ else: var translationTable: seq[string] proc loadUnidecodeTable*(datafile = "unidecode.dat") = - ## 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`. + ## 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`. when defined(noUnidecodeTable): newSeq(translationTable, 0xffff) var i = 0 for line in lines(datafile): - translationTable[i] = line.string + translationTable[i] = line 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: - assert unidecode("北京") == "Bei Jing " + doAssert unidecode("北京") == "Bei Jing " + doAssert unidecode("Äußerst") == "Ausserst" 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]) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index ab45f78dc7..3cff833e4b 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -9,11 +9,6 @@ ## :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. @@ -22,9 +17,18 @@ ## parent test as failed. Setup and teardown are inherited. Setup can be ## overridden locally. ## -## Compiled test files as well as ``nim c -r `` +## 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. +## ## Running a single test ## ===================== ## @@ -39,7 +43,7 @@ ## Running a single test suite ## =========================== ## -## Specify the suite name delimited by ``"::"``. +## Specify the suite name delimited by `"::"`. ## ## .. code:: ## @@ -50,7 +54,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,7 +96,7 @@ ## discard v[4] ## ## echo "suite teardown: run once after the tests" -## +## ## Limitations/Bugs ## ================ ## Since `check` will rewrite some expressions for supporting checkpoints @@ -104,16 +108,15 @@ import std/private/since import std/exitprocs -import - macros, strutils, streams, times, sets, sequtils +import std/[macros, strutils, streams, times, sets, sequtils] when declared(stdout): - import os + import std/os const useTerminal = not defined(js) when useTerminal: - import terminal + import std/terminal type TestStatus* = enum ## The status of a test when it is done. @@ -511,7 +514,9 @@ template suite*(name, body) {.dirty.} = finally: suiteEnded() -template exceptionTypeName(e: typed): string = $e.name +proc exceptionTypeName(e: ref Exception): string {.inline.} = + if e == nil: "" + else: $e.name template test*(name, body) {.dirty.} = ## Define a single test case identified by `name`. @@ -548,8 +553,11 @@ template test*(name, body) {.dirty.} = let e = getCurrentException() let eTypeDesc = "[" & exceptionTypeName(e) & "]" checkpoint("Unhandled exception: " & getCurrentExceptionMsg() & " " & eTypeDesc) - var stackTrace {.inject.} = e.getStackTrace() - fail() + if e == nil: # foreign + fail() + else: + var stackTrace {.inject.} = e.getStackTrace() + fail() finally: if testStatusIMPL == TestStatus.FAILED: @@ -628,19 +636,17 @@ 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``). - ## Example: - ## - ## .. code-block:: nim - ## - ## import strutils - ## - ## check("AKB48".toLowerAscii() == "akb48") - ## - ## let teams = {'A', 'K', 'B', '4', '8'} - ## - ## check: - ## "AKB48".toLowerAscii() == "akb48" - ## 'C' in teams + runnableExamples: + import std/strutils + + check("AKB48".toLowerAscii() == "akb48") + + let teams = {'A', 'K', 'B', '4', '8'} + + check: + "AKB48".toLowerAscii() == "akb48" + 'C' notin teams + let checked = callsite()[1] template asgn(a: untyped, value: typed) = @@ -669,14 +675,15 @@ 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}: + if exp[i].kind in nnkCallKinds + {nnkDotExpr, nnkBracketExpr, nnkPar} and + (exp[i].typeKind notin {ntyTypeDesc} or $exp[0] notin ["is", "isnot"]): 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}: @@ -731,22 +738,19 @@ 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. - ## Example: - ## - ## .. code-block:: nim - ## - ## import math, random - ## 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() - let exp = callsite() + 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() + template expectBody(errorTypes, lineInfoLit, body): NimNode {.dirty.} = try: body @@ -758,13 +762,11 @@ macro expect*(exceptions: varargs[typed], body: untyped): untyped = checkpoint(lineInfoLit & ": Expect Failed, unexpected exception was thrown.") fail() - var body = exp[exp.len - 1] - var errorTypes = newNimNode(nnkBracket) - for i in countup(1, exp.len - 2): - errorTypes.add(exp[i]) + for exp in exceptions: + errorTypes.add(exp) - result = getAst(expectBody(errorTypes, exp.lineInfo, body)) + result = getAst(expectBody(errorTypes, errorTypes.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 e993c240da..920529ecff 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -14,40 +14,33 @@ ## as a locator, a name, or both. The term "Uniform Resource Locator" ## (URL) refers to the subset of URIs. ## -## 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" -## -## Data URI Base64 -## --------------- -## -## .. code-block::nim -## doAssert getDataUri("Hello World", "text/plain") == "data:text/plain;charset=utf-8;base64,SGVsbG8gV29ybGQ=" -## doAssert getDataUri("Nim", "text/plain") == "data:text/plain;charset=utf-8;base64,Tmlt" +## # Basic usage -import std/private/since -import strutils, parseutils, base64 -import std/private/decode_helpers +## ## Combine URIs +runnableExamples: + 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 +runnableExamples: + let res = parseUri("sftp://127.0.0.1:4343") + if isAbsolute(res): + assert res.port == "4343" + else: + echo "Wrong format" + +## ## Data URI Base64 +runnableExamples: + doAssert getDataUri("Hello World", "text/plain") == "data:text/plain;charset=utf-8;base64,SGVsbG8gV29ybGQ=" + doAssert getDataUri("Nim", "text/plain") == "data:text/plain;charset=utf-8;base64,Tmlt" + + +import std/[strutils, parseutils, base64] +import std/private/[since, decode_helpers] type @@ -59,17 +52,24 @@ type opaque*: bool isIpv6: bool # not expose it for compatibility. + 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 = ## 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>`_ @@ -91,12 +91,12 @@ func encodeUrl*(s: string, usePlus = true): string = func 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. + ## 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:** @@ -129,12 +129,12 @@ func 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 a ``&`` 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:** @@ -153,6 +153,50 @@ func encodeQuery*(query: openArray[(string, string)], usePlus = true, result.add('=') result.add(encodeUrl(val, usePlus)) +iterator decodeQuery*(data: string): tuple[key, value: string] = + ## Reads and decodes query string `data` and yields the `(key, value)` pairs + ## the data consists of. If compiled with `-d:nimLegacyParseQueryStrict`, an + ## error 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 + doAssert toSeq(decodeQuery("foo=1&bar=2=3")) == @[("foo", "1"), ("bar", "2=3")] + doAssert 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, '&') + 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) = var i = 0 var inPort = false @@ -200,8 +244,8 @@ func parsePath(uri: string, i: var int, result: var Uri) = i.inc parseUntil(uri, result.anchor, {}, i) func initUri*(): Uri = - ## Initializes a URI with ``scheme``, ``username``, ``password``, - ## ``hostname``, ``port``, ``path``, ``query`` and ``anchor``. + ## 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 @@ -212,8 +256,8 @@ func initUri*(): Uri = path: "", query: "", anchor: "") func initUri*(isIpv6: bool): Uri {.since: (1, 3, 5).} = - ## Initializes a URI with ``scheme``, ``username``, ``password``, - ## ``hostname``, ``port``, ``path``, ``query``, ``anchor`` and ``isIpv6``. + ## Initializes a URI with `scheme`, `username`, `password`, + ## `hostname`, `port`, `path`, `query`, `anchor` and `isIpv6`. ## ## **See also:** ## * `Uri type <#Uri>`_ for available fields in the URI type @@ -252,7 +296,7 @@ func parseUri*(uri: string, result: var Uri) = # Check if this is a reference URI (relative URI) 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 @@ -295,9 +339,17 @@ func parseUri*(uri: string): Uri = 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. if path.len == 0: return "" var collection: seq[string] = @[] - let endsWithSlash = path[path.len-1] == '/' + let endsWithSlash = path.endsWith '/' var i = 0 var currentSegment = "" while i < path.len: @@ -311,7 +363,7 @@ func removeDotSegments(path: string): string = discard collection.pop() i.inc 3 continue - elif path[i+1] == '/': + elif i + 1 < path.len and path[i+1] == '/': i.inc 2 continue currentSegment.add path[i] @@ -503,3 +555,25 @@ proc getDataUri*(data, mime: string, encoding = "utf-8"): string {.since: (1, 3) runnableExamples: static: doAssert 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 result = "data:" & mime & ";charset=" & encoding & ";base64," & base64.encode(data) + +when isMainModule and defined(testing): + # needed (pending https://github.com/nim-lang/Nim/pull/11865) because + # `removeDotSegments` is private, the other tests are in `turi`. + block: # removeDotSegments + # `removeDotSegments` is exported for -d:testing only + 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// diff --git a/lib/pure/volatile.nim b/lib/pure/volatile.nim index 208f0fcaaa..f30d899df0 100644 --- a/lib/pure/volatile.nim +++ b/lib/pure/volatile.nim @@ -12,7 +12,7 @@ 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 + ## Note that this only effects code generation on `C` like backends. when nimvm: src[] else: @@ -20,17 +20,17 @@ template volatileLoad*[T](src: ptr T): T = src[] else: var res: T - {.emit: [res, " = (*(", type(src[]), " volatile*)", src, ");"].} + {.emit: [res, " = (*(", typeof(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 + ## backends. when nimvm: dest[] = val else: when defined(js): dest[] = val else: - {.emit: ["*((", type(dest[]), " volatile*)(", dest, ")) = ", val, ";"].} + {.emit: ["*((", typeof(dest[]), " volatile*)(", dest, ")) = ", val, ";"].} diff --git a/lib/std/channels.nim b/lib/std/channels.nim new file mode 100644 index 0000000000..3bbc8a6b67 --- /dev/null +++ b/lib/std/channels.nim @@ -0,0 +1,498 @@ +# +# +# The Nim Compiler +# (c) Copyright 2021 Andreas Prell, Mamy André-Ratsimbazafy & Nim Contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + + +# Based on https://github.com/mratsim/weave/blob/5696d94e6358711e840f8c0b7c684fcc5cbd4472/unused/channels/channels_legacy.nim +# Those are translations of @aprell (Andreas Prell) original channels from C to Nim +# (https://github.com/aprell/tasking-2.0/blob/master/src/channel_shm/channel.c) +# And in turn they are an implementation of Michael & Scott lock-based queues +# (note the paper has 2 channels: lock-free and lock-based) with additional caching: +# Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms +# Maged M. Michael, Michael L. Scott, 1996 +# https://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf + +## This module only works with `--gc:arc` or `--gc:orc`. +## +## .. warning:: This module is experimental and its interface may change. +## +## The following is a simple example of two different ways to use channels: +## blocking and non-blocking. +## + +runnableExamples("--threads:on --gc:orc"): + import std/os + + # In this example a channel is declared at module scope. + # Channels are generic, and they include support for passing objects between + # threads. + # Note that isolated data passed through channels is moved around. + var chan = newChannel[string]() + + # This proc will be run in another thread using the threads module. + proc firstWorker() = + chan.send("Hello World!") + + # This is another proc to run in a background thread. This proc takes a while + # to send the message since it sleeps for 2 seconds (or 2000 milliseconds). + proc secondWorker() = + sleep(2000) + chan.send("Another message") + + # Launch the worker. + var worker1: Thread[void] + createThread(worker1, firstWorker) + + # Block until the message arrives, then print it out. + let dest = chan.recv() + assert dest == "Hello World!" + + # Wait for the thread to exit before moving on to the next example. + worker1.joinThread() + + # Launch the other worker. + var worker2: Thread[void] + createThread(worker2, secondWorker) + # This time, use a non-blocking approach with tryRecv. + # Since the main thread is not blocked, it could be used to perform other + # useful work while it waits for data to arrive on the channel. + var messages: seq[string] + while true: + var msg = "" + if chan.tryRecv(msg): + messages.add msg # "Another message" + break + + messages.add "Pretend I'm doing useful work..." + # For this example, sleep in order not to flood stdout with the above + # message. + sleep(400) + + # Wait for the second thread to exit before cleaning up the channel. + worker2.joinThread() + + # Clean up the channel. + assert chan.close() + + assert messages[^1] == "Another message" + assert messages.len >= 2 + + +when not defined(gcArc) and not defined(gcOrc) and not defined(nimdoc): + {.error: "This channel implementation requires --gc:arc or --gc:orc".} + +import std/[locks, atomics, isolation] +import system/ansi_c + +# Channel (Shared memory channels) +# ---------------------------------------------------------------------------------- + +const + cacheLineSize {.intdefine.} = 64 # TODO: some Samsung phone have 128 cache-line + nimChannelCacheSize* {.intdefine.} = 100 + +type + ChannelRaw = ptr ChannelObj + ChannelObj = object + headLock, tailLock: Lock + notFullCond, notEmptyCond: Cond + closed: Atomic[bool] + size: int + itemsize: int # up to itemsize bytes can be exchanged over this channel + head {.align: cacheLineSize.} : int # Items are taken from head and new items are inserted at tail + tail: int + buffer: ptr UncheckedArray[byte] + atomicCounter: Atomic[int] + + ChannelCache = ptr ChannelCacheObj + ChannelCacheObj = object + next: ChannelCache + chanSize: int + chanN: int + numCached: int + cache: array[nimChannelCacheSize, ChannelRaw] + +# ---------------------------------------------------------------------------------- + +proc numItems(chan: ChannelRaw): int {.inline.} = + result = chan.tail - chan.head + if result < 0: + inc(result, 2 * chan.size) + + assert result <= chan.size + +template isFull(chan: ChannelRaw): bool = + abs(chan.tail - chan.head) == chan.size + +template isEmpty(chan: ChannelRaw): bool = + chan.head == chan.tail + +# Unbuffered / synchronous channels +# ---------------------------------------------------------------------------------- + +template numItemsUnbuf(chan: ChannelRaw): int = + chan.head + +template isFullUnbuf(chan: ChannelRaw): bool = + chan.head == 1 + +template isEmptyUnbuf(chan: ChannelRaw): bool = + chan.head == 0 + +# ChannelRaw kinds +# ---------------------------------------------------------------------------------- + +func isUnbuffered(chan: ChannelRaw): bool = + chan.size - 1 == 0 + +# ChannelRaw status and properties +# ---------------------------------------------------------------------------------- + +proc isClosed(chan: ChannelRaw): bool {.inline.} = load(chan.closed, moRelaxed) + +proc peek(chan: ChannelRaw): int {.inline.} = + (if chan.isUnbuffered: numItemsUnbuf(chan) else: numItems(chan)) + +# Per-thread channel cache +# ---------------------------------------------------------------------------------- + +var channelCache {.threadvar.}: ChannelCache +var channelCacheLen {.threadvar.}: int + +proc allocChannelCache(size, n: int): bool = + ## Allocate a free list for storing channels of a given type + var p = channelCache + + # Avoid multiple free lists for the exact same type of channel + while not p.isNil: + if size == p.chanSize and n == p.chanN: + return false + p = p.next + + p = cast[ptr ChannelCacheObj](c_malloc(csize_t sizeof(ChannelCacheObj))) + if p.isNil: + raise newException(OutOfMemDefect, "Could not allocate memory") + + p.chanSize = size + p.chanN = n + p.numCached = 0 + + p.next = channelCache + channelCache = p + inc channelCacheLen + result = true + +proc freeChannelCache*() = + ## Frees the entire channel cache, including all channels + var p = channelCache + var q: ChannelCache + + while not p.isNil: + q = p.next + for i in 0 ..< p.numCached: + let chan = p.cache[i] + if not chan.buffer.isNil: + c_free(chan.buffer) + deinitLock(chan.headLock) + deinitLock(chan.tailLock) + deinitCond(chan.notFullCond) + deinitCond(chan.notEmptyCond) + c_free(chan) + c_free(p) + dec channelCacheLen + p = q + + assert(channelCacheLen == 0) + channelCache = nil + +# Channels memory ops +# ---------------------------------------------------------------------------------- + +proc allocChannel(size, n: int): ChannelRaw = + when nimChannelCacheSize > 0: + var p = channelCache + + while not p.isNil: + if size == p.chanSize and n == p.chanN: + # Check if free list contains channel + if p.numCached > 0: + dec p.numCached + result = p.cache[p.numCached] + assert(result.isEmpty) + return + else: + # All the other lists in cache won't match + break + p = p.next + + result = cast[ChannelRaw](c_malloc(csize_t sizeof(ChannelObj))) + if result.isNil: + raise newException(OutOfMemDefect, "Could not allocate memory") + + # To buffer n items, we allocate for n + result.buffer = cast[ptr UncheckedArray[byte]](c_malloc(csize_t n*size)) + if result.buffer.isNil: + raise newException(OutOfMemDefect, "Could not allocate memory") + + initLock(result.headLock) + initLock(result.tailLock) + initCond(result.notFullCond) + initCond(result.notEmptyCond) + + result.closed.store(false, moRelaxed) # We don't need atomic here, how to? + result.size = n + result.itemsize = size + result.head = 0 + result.tail = 0 + result.atomicCounter.store(0, moRelaxed) + + when nimChannelCacheSize > 0: + # Allocate a cache as well if one of the proper size doesn't exist + discard allocChannelCache(size, n) + +proc freeChannel(chan: ChannelRaw) = + if chan.isNil: + return + + when nimChannelCacheSize > 0: + var p = channelCache + while not p.isNil: + if chan.itemsize == p.chanSize and + chan.size == p.chanN: + if p.numCached < nimChannelCacheSize: + # If space left in cache, cache it + p.cache[p.numCached] = chan + inc p.numCached + return + else: + # All the other lists in cache won't match + break + p = p.next + + if not chan.buffer.isNil: + c_free(chan.buffer) + + deinitLock(chan.headLock) + deinitLock(chan.tailLock) + deinitCond(chan.notFullCond) + deinitCond(chan.notEmptyCond) + + c_free(chan) + +# MPMC Channels (Multi-Producer Multi-Consumer) +# ---------------------------------------------------------------------------------- + +proc sendUnbufferedMpmc(chan: ChannelRaw, data: sink pointer, size: int, nonBlocking: bool): bool = + if nonBlocking and chan.isFullUnbuf: + return false + + acquire(chan.headLock) + + if nonBlocking and chan.isFullUnbuf: + # Another thread was faster + release(chan.headLock) + return false + + while chan.isFullUnbuf: + wait(chan.notFullcond, chan.headLock) + + assert chan.isEmptyUnbuf + assert size <= chan.itemsize + copyMem(chan.buffer, data, size) + + chan.head = 1 + + release(chan.headLock) + signal(chan.notEmptyCond) + result = true + +proc sendMpmc(chan: ChannelRaw, data: sink pointer, size: int, nonBlocking: bool): bool = + assert not chan.isNil + assert not data.isNil + + if isUnbuffered(chan): + return sendUnbufferedMpmc(chan, data, size, nonBlocking) + + if nonBlocking and chan.isFull: + return false + + acquire(chan.tailLock) + + if nonBlocking and chan.isFull: + # Another thread was faster + release(chan.tailLock) + return false + + while chan.isFull: + wait(chan.notFullcond, chan.tailLock) + + assert not chan.isFull + assert size <= chan.itemsize + + let writeIdx = if chan.tail < chan.size: chan.tail + else: chan.tail - chan.size + + copyMem(chan.buffer[writeIdx * chan.itemsize].addr, data, size) + + inc chan.tail + if chan.tail == 2 * chan.size: + chan.tail = 0 + + release(chan.tailLock) + signal(chan.notEmptyCond) + result = true + +proc recvUnbufferedMpmc(chan: ChannelRaw, data: pointer, size: int, nonBlocking: bool): bool = + if nonBlocking and chan.isEmptyUnbuf: + return false + + acquire(chan.headLock) + + if nonBlocking and chan.isEmptyUnbuf: + # Another thread was faster + release(chan.headLock) + return false + + while chan.isEmptyUnbuf: + wait(chan.notEmptyCond, chan.headLock) + + assert chan.isFullUnbuf + assert size <= chan.itemsize + + copyMem(data, chan.buffer, size) + + chan.head = 0 + + release(chan.headLock) + signal(chan.notFullCond) + result = true + +proc recvMpmc(chan: ChannelRaw, data: pointer, size: int, nonBlocking: bool): bool = + assert not chan.isNil + assert not data.isNil + + if isUnbuffered(chan): + return recvUnbufferedMpmc(chan, data, size, nonBlocking) + + if nonBlocking and chan.isEmpty: + return false + + acquire(chan.headLock) + + if nonBlocking and chan.isEmpty: + # Another thread took the last data + release(chan.headLock) + return false + + while chan.isEmpty: + wait(chan.notEmptyCond, chan.headLock) + + assert not chan.isEmpty + assert size <= chan.itemsize + + let readIdx = if chan.head < chan.size: chan.head + else: chan.head - chan.size + + copyMem(data, chan.buffer[readIdx * chan.itemsize].addr, size) + + inc chan.head + if chan.head == 2 * chan.size: + chan.head = 0 + + release(chan.headLock) + signal(chan.notFullCond) + result = true + +proc channelCloseMpmc(chan: ChannelRaw): bool = + # Unsynchronized + + if chan.isClosed: + # ChannelRaw already closed + return false + + store(chan.closed, true, moRelaxed) + result = true + +proc channelOpenMpmc(chan: ChannelRaw): bool = + # Unsynchronized + + if not chan.isClosed: + # ChannelRaw already open + return false + + store(chan.closed, false, moRelaxed) + result = true + +# Public API +# ---------------------------------------------------------------------------------- + +type + Channel*[T] = object ## Typed channels + d: ChannelRaw + +proc `=destroy`*[T](c: var Channel[T]) = + if c.d != nil: + if load(c.d.atomicCounter, moAcquire) == 0: + if c.d.buffer != nil: + freeChannel(c.d) + else: + atomicDec(c.d.atomicCounter) + +proc `=`*[T](dest: var Channel[T], src: Channel[T]) = + ## Shares `Channel` by reference counting. + if src.d != nil: + atomicInc(src.d.atomicCounter) + + if dest.d != nil: + `=destroy`(dest) + dest.d = src.d + +func trySend*[T](c: Channel[T], src: var Isolated[T]): bool {.inline.} = + ## Sends item to the channel(non blocking). + var data = src.extract + result = sendMpmc(c.d, data.addr, sizeof(T), true) + if result: + wasMoved(data) + +template trySend*[T](c: Channel[T], src: T): bool = + ## Helper templates for `trySend`. + trySend(c, isolate(src)) + +func tryRecv*[T](c: Channel[T], dst: var T): bool {.inline.} = + ## Receives item from the channel(non blocking). + recvMpmc(c.d, dst.addr, sizeof(T), true) + +func send*[T](c: Channel[T], src: sink Isolated[T]) {.inline.} = + ## Sends item to the channel(blocking). + var data = src.extract + discard sendMpmc(c.d, data.addr, sizeof(T), false) + wasMoved(data) + +template send*[T](c: Channel[T]; src: T) = + ## Helper templates for `send`. + send(c, isolate(src)) + +func recv*[T](c: Channel[T]): T {.inline.} = + ## Receives item from the channel(blocking). + discard recvMpmc(c.d, result.addr, sizeof(result), false) + +func open*[T](c: Channel[T]): bool {.inline.} = + result = c.d.channelOpenMpmc() + +func close*[T](c: Channel[T]): bool {.inline.} = + result = c.d.channelCloseMpmc() + +func peek*[T](c: Channel[T]): int {.inline.} = peek(c.d) + +proc newChannel*[T](elements = 30): Channel[T] = + ## Returns a new `Channel`. `elements` should be positive. + ## `elements` is used to specify whether a channel is buffered or not. + ## If `elements` = 1, the channel is unbuffered. If `elements` > 1, the + ## channel is buffered. + assert elements >= 1, "Elements must be positive!" + result = Channel[T](d: allocChannel(sizeof(T), elements)) diff --git a/lib/std/compilesettings.nim b/lib/std/compilesettings.nim index b9b13175d5..725b68acd2 100644 --- a/lib/std/compilesettings.nim +++ b/lib/std/compilesettings.nim @@ -31,6 +31,7 @@ type 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 MultipleValueSetting* {.pure.} = enum ## \ ## settings resulting in a seq of string values @@ -42,15 +43,22 @@ type clibs ## libraries passed to the C/C++ compiler proc querySetting*(setting: SingleValueSetting): string {. - compileTime, noSideEffect.} = discard - ## Can be used to get a string compile-time option. Example: + compileTime, noSideEffect.} = + ## Can be used to get a string compile-time option. ## - ## .. code-block:: Nim - ## const nimcache = querySetting(SingleValueSetting.nimcacheDir) + ## 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.} = discard - ## Can be used to get a multi-string compile-time option. Example: + compileTime, noSideEffect.} = + ## Can be used to get a multi-string compile-time option. ## - ## .. code-block:: Nim - ## const nimblePaths = compileSettingSeq(MultipleValueSetting.nimblePaths) + ## See also: + ## * `compileOption `_ for `on|off` options + ## * `compileOption `_ for enum options + runnableExamples: + const nimblePaths = querySettingSeq(MultipleValueSetting.nimblePaths) diff --git a/lib/std/editdistance.nim b/lib/std/editdistance.nim index 2c9203d649..9f29c5c05f 100644 --- a/lib/std/editdistance.nim +++ b/lib/std/editdistance.nim @@ -13,24 +13,24 @@ 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 +44,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 +69,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 +79,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) diff --git a/lib/std/effecttraits.nim b/lib/std/effecttraits.nim index 0f0a244926..358280db0e 100644 --- a/lib/std/effecttraits.nim +++ b/lib/std/effecttraits.nim @@ -12,7 +12,7 @@ ## **Since**: Version 1.4. ## ## One can test for the existance of this standard module -## via ``defined(nimHasEffectTraitsModule)``. +## via `defined(nimHasEffectTraitsModule)`. import macros @@ -22,33 +22,33 @@ 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. + ## 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. + ## 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 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. + ## 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. + ## 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/enumutils.nim b/lib/std/enumutils.nim index 704e42de52..16dab9d1aa 100644 --- a/lib/std/enumutils.nim +++ b/lib/std/enumutils.nim @@ -7,7 +7,10 @@ # distribution, for details about the copyright. # -import macros +import std/macros +from std/typetraits import OrdinalEnum, HoleyEnum + +# 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 = @@ -61,4 +64,38 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, result.add nnkElse.newTree(raiseStmt) else: expectKind(default, nnkSym) - result.add nnkElse.newTree(default) \ No newline at end of file + 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 + type 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 symbolName*[T: OrdinalEnum](a: T): string = + ## Returns the symbol name of an enum. + 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" + const names = enumNames(T) + names[a.ord - T.low.ord] diff --git a/lib/std/isolation.nim b/lib/std/isolation.nim index 7ca5f00800..8daca233bf 100644 --- a/lib/std/isolation.nim +++ b/lib/std/isolation.nim @@ -10,6 +10,9 @@ ## 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. @@ -25,7 +28,22 @@ 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".} - ## Create an isolated subgraph from the expression `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 new file mode 100644 index 0000000000..ccf14080bf --- /dev/null +++ b/lib/std/jsbigints.nim @@ -0,0 +1,221 @@ +## 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.".} + +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`. + when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard + runnableExamples: + doAssert big(1234567890) == big"1234567890" + doAssert 0b1111100111.big == 0o1747.big and 0o1747.big == 999.big + +func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".} = + ## Constructor for `JsBigInt`. + when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard + runnableExamples: + doAssert big"-1" == big"1" - big"2" + # supports decimal, binary, octal, hex: + doAssert big"12" == 12.big + doAssert big"0b101" == 0b101.big + doAssert big"0o701" == 0o701.big + doAssert big"0xdeadbeaf" == 0xdeadbeaf.big + doAssert big"0xffffffffffffffff" == (1.big shl 64.big) - 1.big + +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 new file mode 100644 index 0000000000..36bc772d5d --- /dev/null +++ b/lib/std/jsfetch.nim @@ -0,0 +1,198 @@ +## - Fetch for the JavaScript target: https://developer.mozilla.org/docs/Web/API/Fetch_API +## .. Note:: jsfetch is Experimental. jsfetch module requires `-d:nimExperimentalJsfetch` +when not defined(js): + {.fatal: "Module jsfetch is designed to be used with the JavaScript backend.".} + +when defined(nimExperimentalJsfetch) or defined(nimdoc): + import std/[asyncjs, jsheaders, jsformdata] + 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 + + 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" + + Body* = ref object of JsRoot ## https://developer.mozilla.org/en-US/docs/Web/API/Body + bodyUsed*: bool + + 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*: Body + + 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*: Body + + + 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 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/Body/text + + proc json*(self: Response): Future[JsObject] {.importjs: "#.$1()".} + ## https://developer.mozilla.org/en-US/docs/Web/API/Body/json + + proc formData*(self: Body): Future[FormData] {.importjs: "#.$1()".} + ## https://developer.mozilla.org/en-US/docs/Web/API/Body/formData + + proc unsafeNewFetchOptions*(metod, body, mode, credentials, cache, referrerPolicy: cstring; + keepalive: bool; redirect = "follow".cstring; referrer = "client".cstring; integrity = "".cstring): FetchOptions {.importjs: + "{method: #, body: #, mode: #, credentials: #, cache: #, referrerPolicy: #, keepalive: #, redirect: #, referrer: #, integrity: #}".} + ## .. warning:: Unsafe `newfetchOptions`. + + func newfetchOptions*(metod: HttpMethod; body: cstring; + mode: FetchModes; credentials: FetchCredentials; cache: FetchCaches; referrerPolicy: FetchReferrerPolicies; + keepalive: bool; redirect = frFollow; referrer = "client".cstring; integrity = "".cstring): FetchOptions = + ## Constructor for `FetchOptions`. + result = FetchOptions( + body: body, mode: $mode, credentials: $credentials, cache: $cache, referrerPolicy: $referrerPolicy, + keepalive: keepalive, redirect: $redirect, referrer: referrer, integrity: integrity, + 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 | Body | FetchOptions): cstring {.importjs: "JSON.stringify(#)".} + + func `$`*(self: Request | Response | Body | FetchOptions): string = $toCstring(self) + + +runnableExamples("-d:nimExperimentalJsfetch -r:off"): + import std/[asyncjs, jsconsole, jsheaders, jsformdata] + 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 + ) + 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 + + 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 + ) + 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 + + 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 Body + + discard example() + + when defined(nimExperimentalAsyncjsThen): + 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 new file mode 100644 index 0000000000..120f8742d2 --- /dev/null +++ b/lib/std/jsformdata.nim @@ -0,0 +1,65 @@ +## - `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.".} + +type FormData* = ref object of JsRoot ## FormData API. + +func newFormData*(): FormData {.importjs: "new FormData()".} + +func add*(self: FormData; name: cstring; value: SomeNumber | bool | cstring) {.importjs: "#.append(#, #)".} + ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/append + ## Duplicate keys are allowed and order is preserved. + +func add*(self: FormData; name: cstring; value: SomeNumber | bool | cstring, filename: cstring) {.importjs: "#.append(#, #, #)".} + ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/append + ## 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, value, filename: cstring) {.importjs: "#.set(#, #, #)".} + ## https://developer.mozilla.org/en-US/docs/Web/API/FormData/set + +func `[]=`*(self: FormData; name, value: cstring) {.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 new file mode 100644 index 0000000000..6fd3b3468d --- /dev/null +++ b/lib/std/jsheaders.nim @@ -0,0 +1,83 @@ +## - 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 index 24935f511d..fa61d79dbf 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -11,7 +11,7 @@ runnableExamples: 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 - doAssert j.jsonTo(type(a)).toJson == j + doAssert j.jsonTo(typeof(a)).toJson == j import std/[json,strutils,tables,sets,strtabs,options] @@ -42,7 +42,7 @@ type proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".} proc distinctBase(T: typedesc): typedesc {.magic: "TypeTrait".} -template distinctBase[T](a: T): untyped = distinctBase(type(a))(a) +template distinctBase[T](a: T): untyped = distinctBase(typeof(a))(a) macro getDiscriminants(a: typedesc): seq[string] = ## return the discriminant keys @@ -119,7 +119,7 @@ template fromJsonFields(newObj, oldObj, json, discKeys, opt) = when key notin discKeys: if json.hasKey key: numMatched.inc - fromJson(val, json[key]) + 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 @@ -187,7 +187,8 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) = of JInt: a = T(b.getBiggestInt()) of JString: a = parseEnum[T](b.getStr()) else: checkJson false, $($T, " ", b) - elif T is Ordinal: a = T(to(b, int)) + 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: @@ -201,17 +202,17 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) = if b.kind == JNull: a = nil else: a = T() - fromJson(a[], b) + fromJson(a[], b, opt) elif T is array: checkJson a.len == b.len, $(a.len, b.len, $T) var i = 0 for ai in mitems(a): - fromJson(ai, b[i]) + fromJson(ai, b[i], opt) i.inc elif T is seq: a.setLen b.len for i, val in b.getElems: - fromJson(a[i], val) + fromJson(a[i], val, opt) elif T is object: template fun(key, typ): untyped {.used.} = if b.hasKey key: @@ -237,16 +238,16 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) = checkJson b.kind == JArray, $(b.kind) # we could customize whether to allow JNull var i = 0 for val in fields(a): - fromJson(val, b[i]) + fromJson(val, b[i], opt) i.inc checkJson b.len == i, $(b.len, i, $T, b) # could customize else: # checkJson not appropriate here static: doAssert false, "not yet implemented: " & $T -proc jsonTo*(b: JsonNode, T: typedesc): T = +proc jsonTo*(b: JsonNode, T: typedesc, opt = Joptions()): T = ## reverse of `toJson` - fromJson(result, b) + fromJson(result, b, opt) proc toJson*[T](a: T): JsonNode = ## serializes `a` to json; uses `toJsonHook(a: T)` if it's in scope to @@ -270,6 +271,7 @@ proc toJson*[T](a: T): JsonNode = # in simpler code for `toJson` and `fromJson`. elif T is distinct: result = toJson(a.distinctBase) elif T is bool: result = %(a) + elif T is SomeInteger: result = %a elif T is Ordinal: result = %(a.ord) else: result = %a @@ -280,7 +282,7 @@ proc fromJsonHook*[K, V](t: var (Table[K, V] | OrderedTable[K, V]), ## See also: ## * `toJsonHook proc<#toJsonHook>`_ runnableExamples: - import tables, json + 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}}""")) @@ -300,7 +302,7 @@ proc toJsonHook*[K, V](t: (Table[K, V] | OrderedTable[K, V])): JsonNode = ## See also: ## * `fromJsonHook proc<#fromJsonHook,,JsonNode>`_ runnableExamples: - import tables, json + import std/[tables, json] let foo = ( t: [("two", 2)].toTable, ot: [("one", 1), ("three", 3)].toOrderedTable) @@ -316,7 +318,7 @@ proc fromJsonHook*[A](s: var SomeSet[A], jsonNode: JsonNode) = ## See also: ## * `toJsonHook proc<#toJsonHook,SomeSet[A]>`_ runnableExamples: - import sets, json + import std/[sets, json] var foo: tuple[hs: HashSet[string], os: OrderedSet[string]] fromJson(foo, parseJson(""" {"hs": ["hash", "set"], "os": ["ordered", "set"]}""")) @@ -336,7 +338,7 @@ proc toJsonHook*[A](s: SomeSet[A]): JsonNode = ## See also: ## * `fromJsonHook proc<#fromJsonHook,SomeSet[A],JsonNode>`_ runnableExamples: - import sets, json + import std/[sets, json] let foo = (hs: ["hash"].toHashSet, os: ["ordered", "set"].toOrderedSet) assert $toJson(foo) == """{"hs":["hash"],"os":["ordered","set"]}""" @@ -350,7 +352,7 @@ proc fromJsonHook*[T](self: var Option[T], jsonNode: JsonNode) = ## See also: ## * `toJsonHook proc<#toJsonHook,Option[T]>`_ runnableExamples: - import options, json + import std/[options, json] var opt: Option[string] fromJsonHook(opt, parseJson("\"test\"")) assert get(opt) == "test" @@ -368,7 +370,7 @@ proc toJsonHook*[T](self: Option[T]): JsonNode = ## See also: ## * `fromJsonHook proc<#fromJsonHook,Option[T],JsonNode>`_ runnableExamples: - import options, json + import std/[options, json] let optSome = some("test") assert $toJson(optSome) == "\"test\"" let optNone = none[string]() @@ -385,7 +387,7 @@ proc fromJsonHook*(a: var StringTableRef, b: JsonNode) = ## See also: ## * `toJsonHook proc<#toJsonHook,StringTableRef>`_ runnableExamples: - import strtabs, json + import std/[strtabs, json] var t = newStringTable(modeCaseSensitive) let jsonStr = """{"mode": 0, "table": {"name": "John", "surname": "Doe"}}""" fromJsonHook(t, parseJson(jsonStr)) @@ -403,7 +405,7 @@ proc toJsonHook*(a: StringTableRef): JsonNode = ## See also: ## * `fromJsonHook proc<#fromJsonHook,StringTableRef,JsonNode>`_ runnableExamples: - import strtabs, json + import std/[strtabs, json] let t = newStringTable("name", "John", "surname", "Doe", modeCaseSensitive) let jsonStr = """{"mode": "modeCaseSensitive", "table": {"name": "John", "surname": "Doe"}}""" diff --git a/lib/std/logic.nim b/lib/std/logic.nim index 3cc871a6e8..84640d3807 100644 --- a/lib/std/logic.nim +++ b/lib/std/logic.nim @@ -1,5 +1,5 @@ ## This module provides further logic operators like 'forall' and 'exists' -## They are only supported in ``.ensures`` etc pragmas. +## They are only supported in `.ensures` etc pragmas. proc `->`*(a, b: bool): bool {.magic: "Implies".} proc `<->`*(a, b: bool): bool {.magic: "Iff".} diff --git a/lib/std/monotimes.nim b/lib/std/monotimes.nim index c56bf77b30..78736d719e 100644 --- a/lib/std/monotimes.nim +++ b/lib/std/monotimes.nim @@ -8,34 +8,38 @@ # ##[ - 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: - - .. 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. - - 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. - - See also - ======== - * `times module `_ +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: ]## -import times +runnableExamples: + import std/os + + let a = getMonoTime() + sleep(10) + 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. + +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. + +See also +======== +* `times module `_ +]## + +import std/times type MonoTime* = object ## Represents a monotonic timestamp. @@ -53,18 +57,16 @@ when defined(macosx): when defined(js): proc getJsTicks: float = - ## 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; - } - """.} + ## 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 # Workaround for #6752. {.push overflowChecks: off.} @@ -74,8 +76,8 @@ when defined(js): system.`+`(a, b) {.pop.} -elif defined(posix): - import posix +elif defined(posix) and not defined(osx): + import std/posix elif defined(windows): proc QueryPerformanceCounter(res: var uint64) {. @@ -84,11 +86,11 @@ elif defined(windows): importc: "QueryPerformanceFrequency", stdcall, dynlib: "kernel32".} proc getMonoTime*(): MonoTime {.tags: [TimeEffect].} = - ## Get the current `MonoTime` timestamp. + ## Returns the current `MonoTime` timestamp. ## ## When compiled with the JS backend and executed in a browser, - ## 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) + ## this proc calls `window.performance.now()`. + ## See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now) ## for more information. when defined(js): let ticks = getJsTicks() diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim index a1402a7ffe..2b5896be09 100644 --- a/lib/std/packedsets.nim +++ b/lib/std/packedsets.nim @@ -7,17 +7,18 @@ # distribution, for details about the copyright. # -## The ``packedsets`` module implements an efficient `Ordinal`set implemented as a +## The `packedsets` module implements an efficient `Ordinal` set implemented as a ## `sparse bit set`:idx:. ## ## Supports any Ordinal type. ## -## **Note**: Currently the assignment operator ``=`` for ``PackedSet[A]`` +## **Note**: Currently the assignment operator `=` for `PackedSet[A]` ## performs some rather meaningless shallow copy. Since Nim currently does -## not allow the assignment operator to be overloaded, use `assign proc +## not allow the assignment operator to be overloaded, use the `assign proc ## <#assign,PackedSet[A],PackedSet[A]>`_ to get a deep copy. ## -## **See also:** +## See also +## ======== ## * `sets module `_ for more general hash sets import std/private/since @@ -37,19 +38,18 @@ const IntMask = 1 shl IntShift - 1 type - PTrunk = ref Trunk - Trunk = object - next: PTrunk # all nodes are connected with this pointer + Trunk = 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[PTrunk] + TrunkSeq = seq[Trunk] - ## An efficient set of `Ordinal` types implemented as a sparse bit set. 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: PTrunk + head: Trunk data: TrunkSeq a: array[0..33, int] # profiling shows that 34 elements are enough @@ -62,9 +62,9 @@ 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 + result = ((5 * h) + 1 + perturb) and maxHash -proc packedSetGet[A](t: PackedSet[A], key: int): PTrunk = +proc packedSetGet[A](t: PackedSet[A], key: int): Trunk = var h = key and t.max var perturb = key while t.data[h] != nil: @@ -73,13 +73,13 @@ proc packedSetGet[A](t: PackedSet[A], key: int): PTrunk = h = nextTry(h, t.max, perturb) result = nil -proc intSetRawInsert[A](t: PackedSet[A], data: var TrunkSeq, desc: PTrunk) = +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) + assert data[h] != desc h = nextTry(h, t.max, perturb) - assert(data[h] == nil) + assert data[h] == nil data[h] = desc proc intSetEnlarge[A](t: var PackedSet[A]) = @@ -91,7 +91,7 @@ proc intSetEnlarge[A](t: var PackedSet[A]) = if t.data[i] != nil: intSetRawInsert(t, n, t.data[i]) swap(t.data, n) -proc intSetPut[A](t: var PackedSet[A], key: int): PTrunk = +proc intSetPut[A](t: var PackedSet[A], key: int): Trunk = var h = key and t.max var perturb = key while t.data[h] != nil: @@ -103,7 +103,7 @@ proc intSetPut[A](t: var PackedSet[A], key: int): PTrunk = h = key and t.max perturb = key while t.data[h] != nil: h = nextTry(h, t.max, perturb) - assert(t.data[h] == nil) + assert t.data[h] == nil new(result) result.next = t.head result.key = key @@ -111,8 +111,8 @@ proc intSetPut[A](t: var PackedSet[A], key: int): PTrunk = t.data[h] = result proc bitincl[A](s: var PackedSet[A], key: int) {.inline.} = - var ret: PTrunk - var t = intSetPut(s, `shr`(key, TrunkShift)) + 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)) @@ -121,8 +121,8 @@ proc exclImpl[A](s: var PackedSet[A], key: int) = if s.elems <= s.a.len: for i in 0..`_ + ## **See also:** + ## * `toPackedSet proc <#toPackedSet,openArray[A]>`_ runnableExamples: - var a = initPackedSet[int]() + let a = initPackedSet[int]() assert len(a) == 0 type Id = distinct int @@ -179,27 +179,23 @@ proc initPackedSet*[A]: PackedSet[A] = counter: 0, max: 0, head: nil, - data: when defined(nimNoNilSeqs): @[] else: 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 `in` operator. + ## This allows the usage of the `in` operator. runnableExamples: type ABCD = enum A, B, C, D - var a = initPackedSet[int]() - for x in [1, 3, 5]: - a.incl(x) + let a = [1, 3, 5].toPackedSet assert a.contains(3) assert 3 in a - assert(not a.contains(8)) + assert not a.contains(8) assert 8 notin a - var letters = initPackedSet[ABCD]() - for x in [A, C]: - letters.incl(x) + let letters = [A, C].toPackedSet assert A in letters assert C in letters assert B notin letters @@ -208,7 +204,7 @@ proc contains*[A](s: PackedSet[A], key: A): bool = for i in 0..`_ for excluding an element - ## * `incl proc <#incl,PackedSet[A],PackedSet[A]>`_ for including other set + ## * `incl proc <#incl,PackedSet[A],PackedSet[A]>`_ for including a set ## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_ runnableExamples: var a = initPackedSet[int]() @@ -236,10 +232,10 @@ proc incl*[A](s: var PackedSet[A], key: A) = if s.a[i] == ord(key): return if s.elems < s.a.len: s.a[s.elems] = ord(key) - inc s.elems + inc(s.elems) return newSeq(s.data, InitIntSetSize) - s.max = InitIntSetSize-1 + s.max = InitIntSetSize - 1 for i in 0..`_. ## - ## See also: - ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding other set + ## **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 = initPackedSet[int]() - b = initPackedSet[int]() - a.incl(1) - b.incl(5) - a.incl(b) + 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`. + ## Creates a new `PackedSet[A]` that contains the elements of `x`. ## ## Duplicates are removed. ## - ## See also: - ## * `initPackedSet[A] proc <#initPackedSet>`_ + ## **See also:** + ## * `initPackedSet proc <#initPackedSet>`_ runnableExamples: - var - a = toPackedSet([5, 6, 7]) - b = toPackedSet(@[1, 8, 8, 8]) - assert len(a) == 3 - assert len(b) == 2 + 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: @@ -289,11 +279,11 @@ 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 + ## 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: + ## **See also:** ## * `incl proc <#incl,PackedSet[A],A>`_ for including an element ## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_ runnableExamples: @@ -309,7 +299,7 @@ proc containsOrIncl*[A](s: var PackedSet[A], key: A): bool = incl(s, key) result = false else: - var t = packedSetGet(s, `shr`(ord(key), TrunkShift)) + var t = packedSetGet(s, ord(key) shr TrunkShift) if t != nil: var u = ord(key) and TrunkMask result = (t.bits[u shr IntShift] and BitScalar(1) shl (u and IntMask)) != 0 @@ -325,36 +315,31 @@ proc excl*[A](s: var PackedSet[A], key: A) = ## ## This doesn't do anything if `key` is not found in `s`. ## - ## See also: + ## **See also:** ## * `incl proc <#incl,PackedSet[A],A>`_ for including an element - ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding other set + ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding a set ## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_ runnableExamples: - var a = initPackedSet[int]() - a.incl(3) + var a = [3].toPackedSet a.excl(3) a.excl(3) a.excl(99) assert len(a) == 0 - exclImpl[A](s, cast[int](key)) + + 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 other set + ## **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 = initPackedSet[int]() - b = initPackedSet[int]() - a.incl(1) - a.incl(5) - b.incl(5) - a.excl(b) + var a = [1, 5].toPackedSet + a.excl([5].toPackedSet) assert len(a) == 1 assert 5 notin a @@ -363,6 +348,10 @@ proc excl*[A](s: var PackedSet[A], other: PackedSet[A]) = 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: @@ -372,53 +361,57 @@ proc len*[A](s: PackedSet[A]): int {.inline.} = inc(result) proc missingOrExcl*[A](s: var PackedSet[A], key: A): bool = - ## Excludes `key` in the set `s` and tells if `key` was already missing from `s`. + ## 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 + ## 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: + ## **See also:** ## * `excl proc <#excl,PackedSet[A],A>`_ for excluding an element - ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding other set + ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding a set ## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_ runnableExamples: - var a = initPackedSet[int]() - a.incl(5) + var a = [5].toPackedSet assert a.missingOrExcl(5) == false assert a.missingOrExcl(5) == true var count = s.len - exclImpl(s, cast[int](key)) + exclImpl(s, ord(key)) result = count == s.len proc clear*[A](result: var PackedSet[A]) = - ## Clears the PackedSet[A] back to an empty state. + ## Clears the `PackedSet[A]` back to an empty state. runnableExamples: - var a = initPackedSet[int]() - a.incl(5) - a.incl(7) + 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 - when defined(nimNoNilSeqs): - result.data = @[] - else: - result.data = nil + # 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.} = x.head.isNil and x.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 assign*[A](dest: var PackedSet[A], src: PackedSet[A]) = ## Copies `src` to `dest`. - ## `dest` does not need to be initialized by `initPackedSet[A] proc <#initPackedSet>`_. + ## `dest` does not need to be initialized by the `initPackedSet proc <#initPackedSet>`_. runnableExamples: var a = initPackedSet[int]() @@ -429,10 +422,7 @@ proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) = assert len(a) == 2 if src.elems <= src.a.len: - when defined(nimNoNilSeqs): - dest.data = @[] - else: - dest.data = nil + dest.data = @[] dest.max = 0 dest.counter = src.counter dest.head = nil @@ -449,8 +439,8 @@ proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) = 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: PTrunk + assert dest.data[h] == nil + var n: Trunk new(n) n.next = dest.head n.key = it.key @@ -464,13 +454,12 @@ proc union*[A](s1, s2: PackedSet[A]): PackedSet[A] = ## ## The same as `s1 + s2 <#+,PackedSet[A],PackedSet[A]>`_. runnableExamples: - var - a = initPackedSet[int]() - b = initPackedSet[int]() - 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} + 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) @@ -480,13 +469,12 @@ proc intersection*[A](s1, s2: PackedSet[A]): PackedSet[A] = ## ## The same as `s1 * s2 <#*,PackedSet[A],PackedSet[A]>`_. runnableExamples: - var - a = initPackedSet[int]() - b = initPackedSet[int]() - 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} + 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: @@ -498,13 +486,12 @@ proc difference*[A](s1, s2: PackedSet[A]): PackedSet[A] = ## ## The same as `s1 - s2 <#-,PackedSet[A],PackedSet[A]>`_. runnableExamples: - var - a = initPackedSet[int]() - b = initPackedSet[int]() - 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} + 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: @@ -514,17 +501,17 @@ proc difference*[A](s1, s2: PackedSet[A]): PackedSet[A] = proc symmetricDifference*[A](s1, s2: PackedSet[A]): PackedSet[A] = ## Returns the symmetric difference of the sets `s1` and `s2`. runnableExamples: - var - a = initPackedSet[int]() - b = initPackedSet[int]() - 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} + 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) + 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]>`_. @@ -541,14 +528,12 @@ proc `-`*[A](s1, s2: PackedSet[A]): PackedSet[A] {.inline.} = proc disjoint*[A](s1, s2: PackedSet[A]): bool = ## Returns true if the sets `s1` and `s2` have no items in common. runnableExamples: - var - a = initPackedSet[int]() - b = initPackedSet[int]() - a.incl(1); a.incl(2) - b.incl(2); b.incl(3) + let + a = [1, 2].toPackedSet + b = [2, 3].toPackedSet + c = [3, 4].toPackedSet assert disjoint(a, b) == false - b.excl(2) - assert disjoint(a, b) == true + assert disjoint(a, c) == true for item in s1.items: if contains(s2, item): @@ -557,24 +542,24 @@ proc disjoint*[A](s1, s2: PackedSet[A]): bool = 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 subset of `s2`. + ## Returns true if `s1` is a subset of `s2`. ## - ## A subset `s1` has all of its elements in `s2`, and `s2` doesn't necessarily + ## 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: - var - a = initPackedSet[int]() - b = initPackedSet[int]() - a.incl(1) - b.incl(1); b.incl(2) + let + a = [1].toPackedSet + b = [1, 2].toPackedSet + c = [1, 3].toPackedSet assert a <= b - a.incl(2) - assert a <= b - a.incl(3) - assert(not (a <= b)) + assert b <= b + assert not (c <= b) for item in s1.items: if not s2.contains(item): @@ -582,27 +567,33 @@ proc `<=`*[A](s1, s2: PackedSet[A]): bool = return true proc `<`*[A](s1, s2: PackedSet[A]): bool = - ## Returns true if `s1` is proper subset of `s2`. + ## 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: - var - a = initPackedSet[int]() - b = initPackedSet[int]() - a.incl(1) - b.incl(1); b.incl(2) + let + a = [1].toPackedSet + b = [1, 2].toPackedSet + c = [1, 3].toPackedSet assert a < b - a.incl(2) - assert(not (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 = - ## The `$` operator for int sets. - ## - ## Converts the set `s` to a string, mostly for logging and printing purposes. + ## Converts `s` to a string. + runnableExamples: + let a = [1, 2, 3].toPackedSet + assert $a == "{1, 2, 3}" + dollarImpl() diff --git a/compiler/asciitables.nim b/lib/std/private/asciitables.nim similarity index 89% rename from compiler/asciitables.nim rename to lib/std/private/asciitables.nim index 39bb26a5c8..cbc595651c 100644 --- a/compiler/asciitables.nim +++ b/lib/std/private/asciitables.nim @@ -1,6 +1,6 @@ #[ -move to std/asciitables.nim once stable, or to a nimble paackage -once compiler can depend on nimble +move to std/asciitables.nim once stable, or to a fusion package +once compiler can depend on fusion ]# 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/lib/std/private/decode_helpers.nim b/lib/std/private/decode_helpers.nim index e286516904..f11e3060a6 100644 --- a/lib/std/private/decode_helpers.nim +++ b/lib/std/private/decode_helpers.nim @@ -21,6 +21,13 @@ proc handleHexChar*(c: char, x: var int): bool {.inline.} = 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`. ## diff --git a/lib/std/private/gitutils.nim b/lib/std/private/gitutils.nim new file mode 100644 index 0000000000..bf5e7cb1ff --- /dev/null +++ b/lib/std/private/gitutils.nim @@ -0,0 +1,40 @@ +##[ +internal API for now, API subject to change +]## + +# xxx move other git utilities here; candidate for stdlib. + +import std/[os, osproc, strutils] + +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..= version: - body \ No newline at end of file + body diff --git a/lib/std/private/strimpl.nim b/lib/std/private/strimpl.nim new file mode 100644 index 0000000000..7d42a7cf83 --- /dev/null +++ b/lib/std/private/strimpl.nim @@ -0,0 +1,76 @@ +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) diff --git a/lib/std/private/vmutils.nim b/lib/std/private/vmutils.nim new file mode 100644 index 0000000000..d54977b4e2 --- /dev/null +++ b/lib/std/private/vmutils.nim @@ -0,0 +1,17 @@ +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) + +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) diff --git a/lib/std/setutils.nim b/lib/std/setutils.nim index c6385180e6..c7fac0a549 100644 --- a/lib/std/setutils.nim +++ b/lib/std/setutils.nim @@ -7,10 +7,14 @@ # distribution, for details about the copyright. # -## This module adds functionality to the built-in `set` type. -## See also std/packedsets, std/sets +## This module adds functionality for the built-in `set` type. +## +## See also +## ======== +## * `std/packedsets `_ +## * `std/sets `_ -import typetraits +import std/[typetraits, macros] #[ type SetElement* = char|byte|bool|int16|uint16|enum|uint8|int8 @@ -18,15 +22,56 @@ import typetraits ]# template toSet*(iter: untyped): untyped = - ## Return a built-in set from the elements of iterable `iter` - runnableExamples: + ## 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 enmRange(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 + enmRange(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 3c1674bcbe..b74b285f8c 100644 --- a/lib/std/sha1.nim +++ b/lib/std/sha1.nim @@ -6,41 +6,40 @@ # See the file "copying.txt", included in this # distribution, for details about the copyright. # +## **Note:** Import `std/sha1` to use this module. +## +## [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. +## +## Basic usage +## =========== +## +runnableExamples: + let accessName = secureHash("John Doe") + assert $accessName == "AE6E4D1209F17B460503904FAD297B31E9CF6362" -## **Note:** Import ``std/sha1`` to use this module -## -## 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 +## a = secureHashFile("myFile.nim") +## b = parseSecureHash("10DFAEBF6BFDBC7939957068E2EFACEC4972933C") ## -## let accessName = secureHash("John Doe") -## assert $accessName == "AE6E4D1209F17B460503904FAD297B31E9CF6362" +## if a == b: +## echo "Files match" ## -## .. 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 +## See also +## ======== +## * `base64 module`_ implements a Base64 encoder and decoder ## * `hashes module`_ for efficient computations of hash values for diverse Nim types ## * `md5 module`_ implements the MD5 checksum algorithm -import strutils -from endians import bigEndian32, bigEndian64 +import std/strutils +from std/endians import bigEndian32, bigEndian64 const Sha1DigestSize = 20 type - Sha1Digest* = array[0 .. Sha1DigestSize-1, uint8] + Sha1Digest* = array[0 .. Sha1DigestSize - 1, uint8] SecureHash* = distinct Sha1Digest type @@ -49,10 +48,14 @@ type state: array[5, uint32] buf: array[64, byte] -# This implementation of the SHA1 algorithm was ported from the Chromium OS one +# This implementation of the SHA-1 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 @@ -146,6 +149,10 @@ 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 @@ -177,6 +184,10 @@ 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") @@ -195,31 +206,32 @@ proc finalize*(ctx: var Sha1State): Sha1Digest = # Public API proc secureHash*(str: openArray[char]): SecureHash = - ## Generates a ``SecureHash`` from a ``str``. + ## Generates a `SecureHash` from `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`` + ## * `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, 0, BufferLength) + let length = readChars(f, buffer) if length == 0: break buffer.setLen(length) @@ -231,33 +243,35 @@ proc secureHashFile*(filename: string): SecureHash = SecureHash(state.finalize()) 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 ``SecureHash``. + ## Converts a string `hash` to a `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") @@ -265,5 +279,6 @@ 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) diff --git a/lib/std/socketstreams.nim b/lib/std/socketstreams.nim new file mode 100644 index 0000000000..5c882858db --- /dev/null +++ b/lib/std/socketstreams.nim @@ -0,0 +1,181 @@ +# +# +# 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(tags: []).}: + 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/strbasics.nim b/lib/std/strbasics.nim new file mode 100644 index 0000000000..9232204abe --- /dev/null +++ b/lib/std/strbasics.nim @@ -0,0 +1,115 @@ +# +# +# The Nim Compiler +# (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. + +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/std/sums.nim b/lib/std/sums.nim index cc964b91a7..b68858ef7d 100644 --- a/lib/std/sums.nim +++ b/lib/std/sums.nim @@ -6,12 +6,37 @@ # See the file "copying.txt", included in this # distribution, for details about the copyright. -## Fast sumation functions. +## Accurate summation functions. +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 expense. + ## of a considerable increase in computational cost. + ## + ## See: + ## * https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements if len(x) == 0: return var sum = x[0] var c = T(0) @@ -35,13 +60,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.: - ## * http://en.wikipedia.org/wiki/Pairwise_summation - ## Higham, Nicholas J. (1993), "The accuracy of floating point + ## * https://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 @@ -49,14 +74,5 @@ 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) - - -runnableExamples: - static: - block: - const data = [1, 2, 3, 4, 5, 6, 7, 8, 9] - doAssert sumKbn(data) == 45 - doAssert sumPairs(data) == 45 diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim new file mode 100644 index 0000000000..c9908143c8 --- /dev/null +++ b/lib/std/sysrand.nim @@ -0,0 +1,321 @@ +# +# +# 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 also called Cryptographically secure pseudorandom number generator. +## It should be unpredictable enough for cryptographic applications, +## though its exact quality depends on the OS implementation. +## +## | Targets | Implementation| +## | :--- | ----: | +## | Windows | `BCryptGenRandom`_ | +## | Linux | `getrandom`_ | +## | MacOSX | `getentropy`_ | +## | IOS | `SecRandomCopyBytes`_ | +## | OpenBSD | `getentropy openbsd`_ | +## | FreeBSD | `getrandom freebsd`_ | +## | JS(Web Browser) | `getRandomValues`_ | +## | Nodejs | `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 +## + +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/os + +when defined(posix): + import std/posix + +const + batchImplOS = defined(freebsd) or defined(openbsd) or (defined(macosx) and not defined(ios)) + 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 cuchar + 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): + # TODO using let, pending bootstrap >= 1.4.0 + var SYS_getrandom {.importc: "SYS_getrandom", header: "".}: clong + const syscallHeader = """#include +#include """ + + proc syscall( + n: clong, buf: pointer, bufLen: cint, flags: cuint + ): clong {.importc: "syscall", 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(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): + {.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]) + +elif defined(macosx): + const sysrandomHeader = """#include +#include +""" + + proc getentropy(p: pointer, size: csize_t): cint {.importc: "getentropy", header: sysrandomHeader.} + # getentropy() fills a buffer with random data, which can be used as input + # for process-context pseudorandom generators like arc4random(3). + # The maximum buffer size permitted is 256 bytes. + + proc getRandomImpl(p: pointer, size: int): int {.inline.} = + result = getentropy(p, csize_t(size)).int + +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 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/time_t.nim b/lib/std/time_t.nim index 5fd2752c70..7fb6e6d468 100644 --- a/lib/std/time_t.nim +++ b/lib/std/time_t.nim @@ -11,7 +11,7 @@ when defined(nimdoc): type Impl = distinct int64 Time* = Impl ## \ - ## Wrapper for ``time_t``. On posix, this is an alias to ``posix.Time``. + ## 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/with.nim b/lib/std/with.nim index e6784478c6..79afd61a4b 100644 --- a/lib/std/with.nim +++ b/lib/std/with.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -## This module implements the ``with`` macro for easy +## 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. diff --git a/lib/std/wrapnils.nim b/lib/std/wrapnils.nim index 71205c887e..3ff48fbfea 100644 --- a/lib/std/wrapnils.nim +++ b/lib/std/wrapnils.nim @@ -1,9 +1,8 @@ ## This module allows chains of field-access and indexing where the LHS can be nil. ## This simplifies code by reducing need for if-else branches around intermediate values -## that maybe be nil. +## that may be nil. ## -## Note: experimental module and relies on {.experimental: "dotOperators".} -## Unstable API. +## Note: experimental module, unstable API. runnableExamples: type Foo = ref object @@ -19,91 +18,91 @@ runnableExamples: assert ?.f2.x1 == "a" # same as f2.x1 (no nil LHS in this chain) assert ?.Foo(x1: "a").x1 == "a" # can use constructor inside - # when you know a sub-expression is not nil, you can scope it as follows: - assert ?.(f2.x2.x2).x3[] == 0 # because `f` is nil + # when you know a sub-expression doesn't involve a `nil` (e.g. `f2.x2.x2`), + # you can scope it as follows: + assert ?.(f2.x2.x2).x3[] == 0 -type Wrapnil[T] = object - valueImpl: T - validImpl: bool + assert (?.f2.x2.x2).x3 == nil # this terminates ?. early -proc wrapnil[T](a: T): Wrapnil[T] = - ## See top-level example. - Wrapnil[T](valueImpl: a, validImpl: true) +from std/options import Option, isSome, get, option, unsafeGet, UnpackDefect +export options.get, options.isSome, options.isNone -template unwrap(a: Wrapnil): untyped = - ## See top-level example. - a.valueImpl - -{.push experimental: "dotOperators".} - -template `.`*(a: Wrapnil, b): untyped = +template fakeDot*(a: Option, b): untyped = ## See top-level example. let a1 = a # to avoid double evaluations - let a2 = a1.valueImpl - type T = Wrapnil[type(a2.b)] - if a1.validImpl: - when type(a2) is ref|ptr: + type T = Option[typeof(unsafeGet(a1).b)] + if isSome(a1): + let a2 = unsafeGet(a1) + when typeof(a2) is ref|ptr: if a2 == nil: default(T) else: - wrapnil(a2.b) + option(a2.b) else: - wrapnil(a2.b) + option(a2.b) else: # nil is "sticky"; this is needed, see tests default(T) -{.pop.} +# xxx this should but doesn't work: func `[]`*[T, I](a: Option[T], i: I): Option {.inline.} = -proc isValid(a: Wrapnil): bool = - ## Returns true if `a` didn't contain intermediate `nil` values (note that - ## `a.valueImpl` itself can be nil even in that case) - a.validImpl - -template `[]`*[I](a: Wrapnil, i: I): untyped = +func `[]`*[T, I](a: Option[T], i: I): auto {.inline.} = ## See top-level example. - let a1 = a # to avoid double evaluations - if a1.validImpl: + if isSome(a): # correctly will raise IndexDefect if a is valid but wraps an empty container - wrapnil(a1.valueImpl[i]) - else: - default(Wrapnil[type(a1.valueImpl[i])]) + result = option(a.unsafeGet[i]) -template `[]`*(a: Wrapnil): untyped = +func `[]`*[U](a: Option[U]): auto {.inline.} = ## See top-level example. - let a1 = a # to avoid double evaluations - let a2 = a1.valueImpl - type T = Wrapnil[type(a2[])] - if a1.validImpl: - if a2 == nil: - default(T) - else: - wrapnil(a2[]) - else: - default(T) + if isSome(a): + let a2 = a.unsafeGet + if a2 != nil: + result = option(a2[]) import std/macros -proc replace(n: NimNode): NimNode = - if n.kind == nnkPar: +func replace(n: NimNode): NimNode = + if n.kind == nnkDotExpr: + result = newCall(bindSym"fakeDot", replace(n[0]), n[1]) + elif n.kind == nnkPar: doAssert n.len == 1 - newCall(bindSym"wrapnil", n[0]) + result = newCall(bindSym"option", n[0]) elif n.kind in {nnkCall, nnkObjConstr}: - newCall(bindSym"wrapnil", n) + result = newCall(bindSym"option", n) elif n.len == 0: - newCall(bindSym"wrapnil", n) + result = newCall(bindSym"option", n) else: n[0] = replace(n[0]) - n + result = n -macro `?.`*(a: untyped): untyped = +proc safeGet[T](a: Option[T]): T {.inline.} = + get(a, default(T)) + +macro `?.`*(a: untyped): auto = ## Transforms `a` into an expression that can be safely evaluated even in ## presence of intermediate nil pointers/references, in which case a default ## value is produced. - #[ - Using a template like this wouldn't work: - template `?.`*(a: untyped): untyped = wrapnil(a)[] - ]# result = replace(a) result = quote do: - `result`.valueImpl + # `result`.val # TODO: expose a way to do this directly in std/options, e.g.: `getAsIs` + safeGet(`result`) + +macro `??.`*(a: untyped): Option = + ## Same as `?.` but returns an `Option`. + runnableExamples: + type Foo = ref object + x1: ref int + x2: int + # `?.` can't distinguish between a valid vs invalid default value, but `??.` can: + var f1 = Foo(x1: int.new, x2: 2) + doAssert (??.f1.x1[]).get == 0 # not enough to tell when the chain was valid. + doAssert (??.f1.x1[]).isSome # a nil didn't occur in the chain + doAssert (??.f1.x2).get == 2 + + var f2: Foo + doAssert not (??.f2.x1[]).isSome # f2 was nil + from std/options import UnpackDefect + doAssertRaises(UnpackDefect): discard (??.f2.x1[]).get + doAssert ?.f2.x1[] == 0 # in contrast, this returns default(int) + + result = replace(a) diff --git a/lib/system.nim b/lib/system.nim index fb008dc452..5740431259 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -14,7 +14,7 @@ ## ## Each module implicitly imports the System module; it must not be listed ## explicitly. Because of this there cannot be a user-defined module named -## ``system``. +## `system`. ## ## System module ## ============= @@ -33,7 +33,7 @@ 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`` + 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. @@ -46,7 +46,7 @@ type void* {.magic: "VoidType".} ## Meta type to denote the absence of any type. auto* {.magic: Expr.} ## Meta type for automatic type determination. - any* = distinct auto ## Meta type for any supported type. + 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 @@ -57,7 +57,14 @@ include "system/basic_types" proc compileOption*(option: string): bool {. magic: "CompileOption", noSideEffect.} - ## Can be used to determine an `on|off` compile-time option. Example: + ## 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 `_ + ## + ## Example: ## ## .. code-block:: Nim ## when compileOption("floatchecks"): @@ -65,7 +72,14 @@ proc compileOption*(option: string): bool {. proc compileOption*(option, arg: string): bool {. magic: "CompileOptionArg", noSideEffect.} - ## Can be used to determine an enum compile-time option. Example: + ## 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 `_ + ## + ## Example: ## ## .. code-block:: Nim ## when compileOption("opt", "size") and compileOption("gc", "boehm"): @@ -95,6 +109,11 @@ proc defined*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} ## Special compile-time procedure that checks whether `x` is ## defined. ## + ## See also: + ## * `compileOption <#compileOption,string>`_ for `on|off` options + ## * `compileOption <#compileOption,string,string>`_ for enum options + ## * `define pragmas `_ + ## ## `x` is an external symbol introduced through the compiler's ## `-d:x switch `_ to enable ## build time conditionals: @@ -116,39 +135,35 @@ else: OrdinalImpl[T] {.magic: Ordinal.} Ordinal* = OrdinalImpl | uint | uint64 -when defined(nimHasRunnableExamples): - 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. - ## - ## 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 - ## runnableExamples "-d:foo -b:cpp": - ## import std/compilesettings - ## doAssert querySetting(backend) == "cpp" - ## runnableExamples "-r:off": ## this one is only compiled - ## import std/browsers - ## openDefaultBrowser "https://forum.nim-lang.org/" -else: - template runnableExamples*(doccmd = "", body: untyped) = - discard +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. + ## + ## 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 + ## runnableExamples "-d:foo -b:cpp": + ## import std/compilesettings + ## doAssert querySetting(backend) == "cpp" + ## runnableExamples "-r:off": ## this one is only compiled + ## import std/browsers + ## openDefaultBrowser "https://forum.nim-lang.org/" when defined(nimHasDeclaredMagic): proc declared*(x: untyped): bool {.magic: "Declared", noSideEffect, compileTime.} @@ -192,7 +207,7 @@ proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} = proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} = ## Builtin `addr` operator for taking the address of a memory - ## location. This works even for ``let`` variables or parameters + ## 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>`_. ## @@ -203,37 +218,45 @@ proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} = ## 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 + `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 + `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`. -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. +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 +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. + runnableExamples: + proc myFoo(): float = 0.0 + iterator myFoo(): string = yield "abc" + iterator myFoo2(): string = yield "abc" + iterator myFoo3(): string {.closure.} = yield "abc" + doAssert type(myFoo()) is string + doAssert typeof(myFoo()) is string + doAssert typeof(myFoo(), typeOfIter) is string + doAssert typeof(myFoo3) is "iterator" + doAssert typeof(myFoo(), typeOfProc) is float + doAssert typeof(0.0, typeOfProc) is float + doAssert typeof(myFoo3, typeOfProc) is "iterator" + doAssert not compiles(typeof(myFoo2(), typeOfProc)) + # this would give: Error: attempting to call routine: 'myFoo2' + # since `typeOfProc` expects a typed expression and `myFoo2()` can + # only be used in a `for` context. const ThisIsSystem = true @@ -243,8 +266,8 @@ proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.} 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``. + ## 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 @@ -276,14 +299,9 @@ type seq*[T]{.magic: "Seq".} ## Generic type to construct sequences. set*[T]{.magic: "Set".} ## Generic type to construct bit sets. -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 + UncheckedArray*[T]{.magic: "UncheckedArray".} + ## Array with no bounds checking. type sink*[T]{.magic: "BuiltinType".} type lent*[T]{.magic: "BuiltinType".} @@ -303,7 +321,7 @@ proc high*[T: Ordinal|enum|range](x: T): T {.magic: "High", noSideEffect, 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)` is Nim's way of writing `INT_MAX`:idx: or `MAX_INT`:idx:. ## ## See also: ## * `low(typedesc) <#low,typedesc[T]>`_ @@ -375,7 +393,7 @@ proc low*[T: Ordinal|enum|range](x: T): T {.magic: "Low", noSideEffect, 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)` is Nim's way of writing `INT_MIN`:idx: or `MIN_INT`:idx:. ## ## See also: ## * `high(typedesc) <#high,typedesc[T]>`_ @@ -442,34 +460,33 @@ proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".} ## There is a reason why the default assignment does a deep copy of sequences ## and strings. -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: sink S) {.noSideEffect, magic: "ArrPut".} - proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".} +# :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 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, magic: "Asgn".} = - ## Generic `sink`:idx: implementation that can be overridden. - shallowCopy(x, y) +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` + ## 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 @@ -481,19 +498,13 @@ proc `..`*[T, U](a: sink T, b: sink U): HSlice[T, U] {.noSideEffect, inline, mag result = HSlice[T, U](a: a, b: b) proc `..`*[T](b: sink T): HSlice[int, T] {.noSideEffect, inline, magic: "DotDot".} = - ## Unary `slice`:idx: operator that constructs an interval ``[default(int), b]``. + ## 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: @@ -541,7 +552,7 @@ when notJSnotNims: 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)] @@ -568,10 +579,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! ## @@ -579,17 +590,17 @@ 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. ## @@ -597,29 +608,27 @@ proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.} ## sizeof('A') # => 1 ## sizeof(2) # => 8 -when defined(nimHasalignOf): - proc alignof*[T](x: T): int {.magic: "AlignOf", noSideEffect.} - proc alignof*(x: typedesc): int {.magic: "AlignOf", noSideEffect.} +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.} -when defined(nimtypedescfixed): - proc sizeof*(x: typedesc): int {.magic: "SizeOf", noSideEffect.} +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. @@ -636,7 +645,7 @@ proc newSeq*[T](s: var seq[T], len: Natural) {.magic: "NewSeq", noSideEffect.} ## #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 @@ -657,8 +666,8 @@ proc newSeq*[T](len = 0.Natural): seq[T] = proc newSeqOfCap*[T](cap: Natural): seq[T] {. magic: "NewSeqOfCap", noSideEffect.} = - ## Creates a new sequence of type ``seq[T]`` with length zero and capacity - ## ``cap``. + ## Creates a new sequence of type `seq[T]` with length zero and capacity + ## `cap`. ## ## .. code-block:: Nim ## var x = newSeqOfCap[int](5) @@ -669,7 +678,7 @@ proc newSeqOfCap*[T](cap: Natural): seq[T] {. 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 @@ -686,65 +695,80 @@ when not defined(js): var s = cast[PGenericSeq](result) s.len = len -proc len*[TOpenArray: openArray|varargs](x: TOpenArray): int {. - magic: "LengthOpenArray", noSideEffect.} +func len*[TOpenArray: openArray|varargs](x: TOpenArray): int {.magic: "LengthOpenArray".} = ## Returns the length of an openArray. - ## - ## .. code-block:: Nim - ## var s = [1, 1, 1, 1, 1] - ## echo len(s) # => 5 + runnableExamples: + proc bar[T](a: openArray[T]): int = len(a) + assert bar([1,2]) == 2 + assert [1,2].len == 2 -proc len*(x: string): int {.magic: "LengthStr", noSideEffect.} +func len*(x: string): int {.magic: "LengthStr".} = ## Returns the length of a string. - ## - ## .. code-block:: Nim - ## var str = "Hello world!" - ## echo len(str) # => 12 + 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 sometimes - ## an O(n) operation. +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`. - ## - ## .. code-block:: Nim - ## var str: cstring = "Hello world!" - ## len(str) # => 12 + 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 -proc len*(x: (type array)|array): int {.magic: "LengthArray", noSideEffect.} +func len*(x: (type array)|array): int {.magic: "LengthArray".} = ## Returns the length of an array or an array type. - ## 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 + ## 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 -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 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 +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 -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 - +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) # floating point operations: proc `+`*(x: float32): float32 {.magic: "UnaryPlusF64", noSideEffect.} @@ -814,7 +838,7 @@ 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 = not (x is y) - ## Negated version of `is <#is,T,S>`_. Equivalent to ``not(x is y)``. + ## Negated version of `is <#is,T,S>`_. Equivalent to `not(x is y)`. ## ## .. code-block:: Nim ## assert 42 isnot float @@ -827,15 +851,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: @@ -844,7 +868,7 @@ 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) @@ -853,15 +877,15 @@ 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: @@ -879,14 +903,31 @@ template disarm*(x: typed) = ## experimental API! x = nil -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(FloatingPointDefect of Exception) - ## assert(DivByZeroDefect of Exception) +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 + + 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 = ## Generic compare proc. @@ -900,7 +941,7 @@ proc cmp*[T](x, y: T): int = ## This generic implementation uses the `==` and `<` operators. ## ## .. code-block:: Nim - ## import algorithm + ## import std/algorithm ## echo sorted(@[4, 2, 6, 5, 8, 7], cmp[int]) if x == y: return 0 if x < y: return -1 @@ -912,44 +953,49 @@ proc cmp*(x, y: string): int {.noSideEffect.} ## **Note**: The precise result values depend on the used C runtime library and ## can differ between operating systems! -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 `@`* [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 {.magic: "Default", noSideEffect.} - ## returns the default value of the type ``T``. +proc default*(T: typedesc): 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 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 reset*[T](obj: var T) {.noSideEffect.} = + ## Resets an object `obj` to its default value. + obj = default(typeof(obj)) 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] @@ -964,7 +1010,7 @@ proc setLen*(s: var string, newlen: Natural) {. ## Sets the length of string `s` to `newlen`. ## ## If the current length is greater than the new length, - ## ``s`` will be truncated. + ## `s` will be truncated. ## ## .. code-block:: Nim ## var myS = "Nim is great!!" @@ -973,19 +1019,19 @@ proc setLen*(s: var string, newlen: Natural) {. 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, merge.} @@ -1023,15 +1069,16 @@ proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.} ## 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. ## - ## .. code-block:: Nim - ## var tmp = "" - ## tmp.add("ab") - ## tmp.add("cd") - ## assert(tmp == "abcd") - + ## See also `strbasics.add`. + runnableExamples: + var tmp = "" + tmp.add("ab") + tmp.add("cd") + assert tmp == "abcd" type Endianness* = enum ## Type describing the endianness of a processor. @@ -1044,11 +1091,11 @@ const 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. + ## `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. + ## `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 @@ -1078,12 +1125,11 @@ const 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): @@ -1101,22 +1147,8 @@ when defined(boehmgc): const boehmLib = "libgc.so.1" {.pragma: boehmGC, noconv, dynlib: boehmLib.} -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. +type TaintedString* {.deprecated: "Deprecated since 1.5".} = string - 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.} @@ -1153,17 +1185,17 @@ when defined(nimdoc): ## ## Before stopping the program the "exit procedures" are called in the ## opposite order they were added with `addExitProc `_. - ## ``quit`` never returns and ignores any exception that may have been raised + ## `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 + ## 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)``. + ## equivalent to calling `quit(QuitFailure)`. ## - ## Note that this is a *runtime* call and using ``quit`` inside a macro won't + ## 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. @@ -1269,7 +1301,7 @@ else: 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. ## @@ -1284,7 +1316,7 @@ proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} = setLen(x, xl) 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. + ## Deletes the item at index `i` by moving all `x[i+1..]` items by one position. ## ## This is an `O(n)` operation. ## @@ -1354,78 +1386,78 @@ type BiggestFloat* = float64 ## is an alias for the biggest floating point type the Nim - ## compiler supports. Currently this is ``float64``, but it is + ## 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 + ## 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 + ## 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*. + ## 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*. + ## 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*. + ## 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*. + ## 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*. + ## 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*. + ## 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*. + ## 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*. + ## 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. + ## 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*. + ## 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*. + ## 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*. + ## 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*. + ## 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 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*. + ## 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*. + ## 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*. + ## 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*. + ## 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 + ## 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]``. + ## 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``. + 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``. + ## Converts an integer `i` into a `float`. ## ## If the conversion fails, `ValueError` is raised. ## However, on most platforms the conversion cannot fail. @@ -1439,11 +1471,11 @@ proc toFloat*(i: int): float {.noSideEffect, inline.} = float(i) proc toBiggestFloat*(i: BiggestInt): BiggestFloat {.noSideEffect, inline.} = - ## Same as `toFloat <#toFloat,int>`_ but for ``BiggestInt`` to ``BiggestFloat``. + ## 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``. + ## Converts a floating point number `f` into an `int`. ## ## Conversion rounds `f` half away from 0, see ## `Round half away from zero @@ -1459,27 +1491,26 @@ proc toInt*(f: float): int {.noSideEffect.} = 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``. + ## 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: "", deprecated: "use exitprocs.addExitProc".} ## Adds/registers a quit procedure. ## - ## Each call to ``addQuitProc`` registers another quit procedure. Up to 30 + ## 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 + ## `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. + # 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``. + ## This is often more efficient than `tmp = a; a = b; b = tmp`. ## Particularly useful for sorting algorithms. ## ## .. code-block:: Nim @@ -1508,7 +1539,7 @@ 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 `classify` procedure + ## and expect a reasonable result - use the `isNaN` or `classify` procedure ## in the `math module `_ for checking for NaN. @@ -1522,10 +1553,26 @@ 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 + +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) + 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.} = @@ -1553,36 +1600,26 @@ proc len*[U: Ordinal; V: Ordinal](x: HSlice[U, V]): int {.noSideEffect, inline.} ## 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.} +when true: # PRTEMP: remove? + proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil", error.} + ## 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: 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*(x: string): bool {.noSideEffect, magic: "IsNil", error.} + ## See also: + ## * `isNil(seq[T]) <#isNil,seq[T]>`_ 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]>`_ 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`. proc `@`*[T](a: openArray[T]): seq[T] = @@ -1697,12 +1734,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: ## ## .. code-block:: nim - ## import strutils + ## import std/strutils ## ## template testException(exception, code: untyped): typed = ## try: @@ -1735,8 +1772,8 @@ proc compiles*(x: untyped): bool {.magic: "Compiles", noSideEffect, compileTime. discard when notJSnotNims: - import "system/ansi_c" - import "system/memory" + import system/ansi_c + import system/memory {.push stackTrace: off.} @@ -1767,7 +1804,7 @@ when notJSnotNims and defined(nimSeqsV2): when not defined(nimscript): 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! @@ -1811,7 +1848,7 @@ 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`. @@ -1824,7 +1861,7 @@ proc contains*[T](a: openArray[T], item: T): bool {.inline.}= 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. runnableExamples: var a = @[1, 3, 5, 7] @@ -1841,14 +1878,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) @@ -1857,7 +1894,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) @@ -1872,9 +1909,8 @@ include "system/gc_interface" const NimStackTrace = compileOption("stacktrace") 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): + when defined(sparc) or defined(ELATE) or defined(boehmgc) or defined(gogc) or + defined(nogc) or defined(gcRegions) or defined(gcMarkAndSweep): false else: true @@ -1903,10 +1939,9 @@ when notJSnotNims: ## 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. + ## .. 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 + ## 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.} @@ -1914,10 +1949,9 @@ when notJSnotNims: ## 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. + ## .. warning:: Ordinary application code should never set this hook! You better know what you do when setting this. ## - ## If ``localRaiseHook`` returns false, the exception + ## If `localRaiseHook` returns false, the exception ## is caught and does not propagate further through the call stack. outOfMemHook*: proc () {.nimcall, tags: [], benign, raises: [].} @@ -1960,8 +1994,14 @@ type when NimStackTraceMsgs: frameMsgLen*: int ## end position in frameMsgBuf for this frame. -when defined(js): +when defined(js) or defined(nimdoc): 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; @@ -1970,7 +2010,15 @@ when defined(js): `x`[off+i] = `y`.charCodeAt(i); } """ - proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} + 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") elif hasAlloc: {.push stackTrace: off, profiler: off.} @@ -1982,38 +2030,32 @@ elif hasAlloc: inc(i) {.pop.} -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 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 - ## `_. -else: - proc echo*(x: varargs[untyped, `$`]) {.magic: "Echo", tags: [WriteIOEffect], - benign, sideEffect.} - proc debugEcho*(x: varargs[untyped, `$`]) {.magic: "Echo", noSideEffect, - tags: [], raises: [].} +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 + ## `_. template newException*(exceptn: typedesc, message: string; parentException: ref Exception = nil): untyped = - ## Creates an exception object of type ``exceptn`` and sets its ``msg`` field + ## 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) @@ -2040,7 +2082,7 @@ func abs*(x: int32): int32 {.magic: "AbsI", inline.} = 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), + ## 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.} @@ -2182,6 +2224,8 @@ 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) when not defined(js): proc cmp(x, y: string): int = @@ -2198,14 +2242,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) @@ -2263,7 +2307,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): @@ -2295,6 +2339,7 @@ when notJSnotNims: when hostOS != "standalone" and hostOS != "any": include "system/dyncalls" + import system/countbits_impl include "system/sets" when defined(gogc): @@ -2321,7 +2366,7 @@ when notJSnotNims: 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) + # n.sons[n.len] contains the `else` part (but may be nil) else: result = n.sons[n.len] @@ -2341,7 +2386,7 @@ when notJSnotNims and hasAlloc: include "system/repr" when notJSnotNims and hasThreadSupport and hostOS != "standalone": - include "system/channels" + include "system/channels_builtin" when notJSnotNims and hostOS != "standalone": @@ -2362,7 +2407,7 @@ 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 @@ -2376,22 +2421,31 @@ 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. - {.emit: """ - `result` = `x`.ClP_0; - """.} + when T is "closure": + {.emit: """ + `result` = `x`.ClP_0; + """.} + else: + {.error: "Only closure function and iterator are allowed!".} proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} = ## Retrieves the raw environment pointer of the closure `x`. This is ## useful for interfacing closures with C. - {.emit: """ - `result` = `x`.ClE_0; - """.} + when T is "closure": + {.emit: """ + `result` = `x`.ClE_0; + """.} + else: + {.error: "Only closure function and iterator are allowed!".} 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; - """.} + ## 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!".} when defined(js): include "system/jssys" @@ -2405,7 +2459,7 @@ when defined(js) or defined(nimscript): 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: @@ -2431,13 +2485,13 @@ proc `/`*(x, y: int): float {.inline, noSideEffect.} = result = toFloat(x) / toFloat(y) type - BackwardsIndex* = distinct int ## Type that is constructed by ``^`` for + 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]``. + ## `a[^x]` is a shortcut for `a[a.len-x]`. ## ## .. code-block:: Nim ## let @@ -2481,7 +2535,7 @@ template `^^`(s, i: untyped): untyped = 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.} = +proc `[]`*[T, U: Ordinal](s: string, x: HSlice[T, U]): string {.inline.} = ## Slice operation for strings. ## Returns the inclusive range `[s[x.a], s[x.b]]`: ## @@ -2493,10 +2547,10 @@ proc `[]`*[T, U](s: string, x: HSlice[T, U]): string {.inline.} = 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) = +proc `[]=`*[T, U: Ordinal](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 + ## If `b.len` is not exactly the number of elements that are referred to ## by `x`, a `splice`:idx: is performed: ## runnableExamples: @@ -2511,7 +2565,7 @@ proc `[]=`*[T, U](s: var string, x: HSlice[T, U], b: string) = else: spliceImpl(s, a, L, b) -proc `[]`*[Idx, T, U, V](a: array[Idx, T], x: HSlice[U, V]): seq[T] = +proc `[]`*[Idx, T; U, V: Ordinal](a: array[Idx, T], x: HSlice[U, V]): seq[T] = ## Slice operation for arrays. ## Returns the inclusive range `[a[x.a], a[x.b]]`: ## @@ -2523,7 +2577,7 @@ proc `[]`*[Idx, T, U, V](a: array[Idx, T], x: HSlice[U, V]): seq[T] = result = newSeq[T](L) for i in 0..`_ proc for easy ## `resource`:idx: embedding: ## - ## The maximum file size limit that ``staticRead`` and ``slurp`` can read is + ## 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. ## ## .. code-block:: Nim ## const myResource = staticRead"mydatafile.bin" ## - ## `slurp <#slurp,string>`_ is an alias for ``staticRead``. + ## `slurp <#slurp,string>`_ is an alias for `staticRead`. proc gorge*(command: string, input = "", cache = ""): string {. magic: "StaticExec".} = discard @@ -2617,17 +2671,17 @@ proc staticExec*(command: string, input = "", cache = ""): string {. ## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") & ## "\nCompiled on " & staticExec("uname -v") ## - ## `gorge <#gorge,string,string,string>`_ is an alias for ``staticExec``. + ## `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 + ## 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``: + ## use versioning information for `cache`: ## ## .. code-block:: Nim ## const stateMachine = staticExec("dfaoptimizer", "input", "0.8.0") @@ -2672,8 +2726,8 @@ proc `&=`*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} template `&=`*(x, y: typed) = ## Generic 'sink' operator for Nim. ## - ## For files an alias for ``write``. - ## 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) @@ -2682,13 +2736,13 @@ 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()``. + ## `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``. + ## for an example to see the distinction between the `currentSourcePath` + ## and `getProjectPath`. ## ## See also: ## * `getCurrentDir proc `_ @@ -2696,15 +2750,12 @@ template currentSourcePath*: string = instantiationInfo(-1, true).filename 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") else: template rangeCheck*(cond) = discard -when not defined(nimhygiene): - {.pragma: inject.} - 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`. @@ -2776,19 +2827,19 @@ 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 ``\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. + ## * 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. ## ## The procedure has been designed so that its output is usable for many ## different common syntaxes. @@ -2798,10 +2849,10 @@ proc addEscapedChar*(s: var string, c: char) {.noSideEffect, inline.} = of '\a': s.add "\\a" # \x07 of '\b': s.add "\\b" # \x08 of '\t': s.add "\\t" # \x09 - of '\L': s.add "\\n" # \x0A + of '\n': s.add "\\n" # \x0A of '\v': s.add "\\v" # \x0B of '\f': s.add "\\f" # \x0C - of '\c': s.add "\\c" # \x0D + of '\r': (when defined(nimLegacyAddEscapedCharx0D): s.add "\\c" else: s.add "\\r") # \x0D of '\e': s.add "\\e" # \x1B of '\\': s.add("\\\\") of '\'': s.add("\\'") @@ -2820,9 +2871,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. @@ -2868,7 +2919,7 @@ 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 @@ -2894,10 +2945,10 @@ when hasAlloc and notJSnotNims: ## 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 the implementation of `spawn`. ## - ## For ``--gc:arc`` or ``--gc:orc`` deepcopy support has to be enabled - ## via ``--deepcopy:on``. + ## For `--gc:arc` or `--gc:orc` deepcopy support has to be enabled + ## via `--deepcopy:on`. discard proc deepCopy*[T](y: T): T = @@ -2925,19 +2976,16 @@ 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 +when true: # xxx PRTEMP remove + # bug #9149; ensure that 'typeof(nil)' does not match *too* well by using 'typeof(nil) | typeof(nil)', + # especially for converters, see tests/overload/tconverter_to_string.nim + # Eventually we will be able to remove this hack completely. + proc `==`*(x: string; y: typeof(nil) | typeof(nil)): bool {. + error: "'nil' is now invalid for 'string'".} = + discard + proc `==`*(x: typeof(nil) | typeof(nil); y: string): bool {. + error: "'nil' is now invalid for 'string'".} = + discard template closureScope*(body: untyped): untyped = ## Useful when creating a closure in a loop to capture local loop variables by @@ -2989,9 +3037,9 @@ proc substr*(s: string, first, last: int): string = ## 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" @@ -3047,11 +3095,11 @@ when defined(genode): ## ## 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.quit(programResult) # No native Genode application initialization, @@ -3070,3 +3118,16 @@ export io when not defined(createNimHcr) and not defined(nimscript): 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 diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 4839407c12..7e156eaab6 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -12,8 +12,6 @@ # 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: "".} @@ -42,6 +40,7 @@ else: C_JmpBuf* {.importc: "jmp_buf", header: "".} = object +type CSighandlerT = proc (a: cint) {.noconv.} when defined(windows): const SIGABRT* = cint(22) @@ -50,6 +49,7 @@ 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 @@ -62,6 +62,7 @@ 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) @@ -71,6 +72,7 @@ elif defined(haiku): SIGSEGV* = cint(11) SIGTERM* = cint(15) SIGPIPE* = cint(7) + SIG_DFL* = cast[CSighandlerT](0) else: when NoFakeVars: {.error: "SIGABRT not ported to your platform".} @@ -81,6 +83,7 @@ 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 @@ -107,9 +110,9 @@ else: proc c_setjmp*(jmpb: C_JmpBuf): cint {. header: "", importc: "setjmp".} -type CSighandlerT = proc (a: cint) {.noconv.} -proc c_signal*(sign: cint, handler: proc (a: cint) {.noconv.}): CSighandlerT {. +proc c_signal*(sign: cint, handler: CSighandlerT): CSighandlerT {. importc: "signal", header: "", discardable.} +proc c_raise*(sign: cint): cint {.importc: "raise", header: "".} type CFile {.importc: "FILE", header: "", diff --git a/lib/system/arc.nim b/lib/system/arc.nim index 9ee367543e..ed5e9f5cae 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -163,7 +163,7 @@ proc nimRawDispose(p: pointer, alignment: int) {.compilerRtl.} = let hdrSize = align(sizeof(RefHeader), alignment) alignedDealloc(p -! hdrSize, alignment) -template dispose*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x), T.alignOf) +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: [].} = @@ -218,15 +218,15 @@ proc GC_ref*[T](x: ref T) = when not defined(gcOrc): template GC_fullCollect* = - ## Forces a full garbage collection pass. With ``--gc:arc`` a nop. + ## Forces a full garbage collection pass. With `--gc:arc` a nop. discard template setupForeignThreadGc* = - ## With ``--gc:arc`` a nop. + ## With `--gc:arc` a nop. discard template tearDownForeignThreadGc* = - ## With ``--gc:arc`` a nop. + ## With `--gc:arc` a nop. discard proc isObj(obj: PNimTypeV2, subclass: cstring): bool {.compilerRtl, inl.} = diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim index 64caddce8d..158f401779 100644 --- a/lib/system/arithm.nim +++ b/lib/system/arithm.nim @@ -155,7 +155,7 @@ proc absInt(a: int): int {.compilerproc, inline.} = raiseOverflow() const - asmVersion = defined(I386) and (defined(vcc) or defined(wcc) or + 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 diff --git a/lib/system/arithmetics.nim b/lib/system/arithmetics.nim index f6c1b69ff7..0dd329495f 100644 --- a/lib/system/arithmetics.nim +++ b/lib/system/arithmetics.nim @@ -1,48 +1,44 @@ -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>`_. +proc succ*[T: Ordinal](x: T, y = 1): T {.magic: "Succ", noSideEffect.} = + ## Returns the `y`-th successor (default: 1) of the value `x`. ## - ## If such a value does not exist, ``OverflowDefect`` is raised + ## If such a value does not exist, `OverflowDefect` is raised ## or a compile time error occurs. - ## - ## .. code-block:: Nim - ## let x = 5 - ## echo succ(5) # => 6 - ## echo succ(5, 3) # => 8 + runnableExamples: + assert succ(5) == 6 + assert 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>`_. +proc pred*[T: Ordinal](x: T, y = 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 + ## If such a value does not exist, `OverflowDefect` is raised ## or a compile time error occurs. - ## - ## .. code-block:: Nim - ## let x = 5 - ## echo pred(5) # => 4 - ## echo pred(5, 3) # => 2 + runnableExamples: + assert pred(5) == 4 + assert pred(5, 3) == 2 -proc inc*[T: Ordinal](x: var T, y = 1) {.magic: "Inc", noSideEffect.} - ## Increments the ordinal ``x`` by ``y``. +proc inc*[T: Ordinal](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 = succ(x, y)``. - ## - ## .. code-block:: Nim - ## var i = 2 - ## inc(i) # i <- 3 - ## inc(i, 3) # i <- 6 + ## 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 -proc dec*[T: Ordinal](x: var T, y = 1) {.magic: "Dec", noSideEffect.} - ## Decrements the ordinal ``x`` by ``y``. +proc dec*[T: Ordinal](x: var T, y = 1) {.magic: "Dec", noSideEffect.} = + ## Decrements 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)``. - ## - ## .. code-block:: Nim - ## var i = 2 - ## dec(i) # i <- 1 - ## dec(i, 3) # i <- -2 + ## 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 @@ -51,38 +47,38 @@ proc dec*[T: Ordinal](x: var T, y = 1) {.magic: "Dec", noSideEffect.} when defined(nimNoZeroExtendMagic): proc ze*(x: int8): int {.deprecated.} = - ## zero extends a smaller integer type to ``int``. This treats `x` as + ## 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 + ## 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 + ## 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 + ## 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 + ## 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``. + ## 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))) @@ -94,46 +90,46 @@ when defined(nimNoZeroExtendMagic): cast[int8](x) proc toU16*(x: int): int16 {.deprecated.} = - ## treats `x` as unsigned and converts it to an ``int16`` by taking the last + ## 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 + ## 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 + ## 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 + ## 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 + ## 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 + ## 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 + ## 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``. + ## 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. @@ -143,12 +139,12 @@ elif not defined(js): ## **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 + ## 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 + ## 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. @@ -167,20 +163,13 @@ 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`. - ## - ## .. 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 + runnableExamples: + assert not 0'u8 == 255 + assert not 0'i8 == -1 + assert not 1000'u16 == 64535 + assert not 1000'i16 == -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.} @@ -207,40 +196,38 @@ 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 ``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 + ## 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 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``. - ## - ## .. code-block:: Nim - ## ( 7 mod 5) == 2 - ## (-7 mod 5) == -2 - ## ( 7 mod -5) == 2 - ## (-7 mod -5) == -2 + ## 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 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) or not defined(nimAshr): +when defined(nimOldShiftRight): 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.} @@ -248,7 +235,7 @@ when defined(nimOldShiftRight) or not defined(nimAshr): 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. ## @@ -256,87 +243,77 @@ else: ## is different than in *C*. ## ## See also: - ## * `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 + ## * `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 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*. - ## - ## .. code-block:: Nim - ## 1'i32 shl 4 == 0x0000_0010 - ## 1'i64 shl 4 == 0x0000_0000_0000_0010 + runnableExamples: + assert 1'i32 shl 4 == 0x0000_0010 + assert 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.} -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.} - ## Computes the `bitwise and` of numbers `x` and `y`. +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. ## - ## .. code-block:: Nim - ## (0b0011 and 0b0101) == 0b0001 - ## (0b0111 and 0b1100) == 0b0100 + ## 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.} + +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 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`. - ## - ## .. code-block:: Nim - ## (0b0011 or 0b0101) == 0b0111 - ## (0b0111 or 0b1100) == 0b1111 + runnableExamples: + assert (0b0011 or 0b0101) == 0b0111 + assert (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`. - ## - ## .. code-block:: Nim - ## (0b0011 xor 0b0101) == 0b0110 - ## (0b0111 xor 0b1100) == 0b1011 + runnableExamples: + assert (0b0011 xor 0b0101) == 0b0110 + assert (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.} @@ -408,7 +385,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.} @@ -416,7 +393,7 @@ 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.} diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim index 4c25d2a567..cf705dd6ed 100644 --- a/lib/system/assertions.nim +++ b/lib/system/assertions.nim @@ -1,3 +1,37 @@ +## This module provides various assertion utilities. +## +## **Note:** This module is reexported by `system` and thus does not need to be +## imported directly (with `system/assertions`). + +runnableExamples: + # assert + assert 1 == 1 + + # onFailedAssert + block: + 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): + var e = new(MyError) + e.msg = msg + e.lineinfo = instantiationInfo(-2) + raise e + + # doAssert + doAssert 1 == 1 # generates code even when built with `-d:danger` or `--assertions:off` + + # doAssertRaises + doAssertRaises(ValueError): + raise newException(ValueError, "Hello World") + +runnableExamples("--assertions:off"): + assert 1 == 2 # no code generated + +# xxx pending bug #16993: move runnableExamples to respective templates + when not declared(sysFatal): include "system/fatal" @@ -12,7 +46,7 @@ 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) + result.toLocation(info.filename, info.line, info.column + 1) # --------------------------------------------------------------------------- @@ -20,13 +54,17 @@ when not defined(nimHasSinkInference): {.pragma: nosinks.} proc raiseAssert*(msg: string) {.noinline, noreturn, nosinks.} = + ## Raises an `AssertionDefect` with `msg`. sysFatal(AssertionDefect, msg) proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = - # trick the compiler to not list ``AssertionDefect`` when called - # by ``assert``. - type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, - 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]) = @@ -41,52 +79,28 @@ template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool] 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 + ## 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. ## - ## 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 `_. - ## - ## .. code-block:: nim - ## static: assert 1 == 9, "This assertion generates code when not built with -d:danger or --assertions:off" - const expr = astToStr(cond) - assertImpl(cond, msg, expr, compileOption("assertions")) + ## No code will be generated for `assert` when passing `-d:danger` (implied by `--assertions:off`). + ## See `command line switches `_. + assertImpl(cond, msg, astToStr(cond), compileOption("assertions")) template doAssert*(cond: untyped, msg = "") = - ## Similar to ``assert`` but is always turned on regardless of ``--assertions``. - ## - ## .. code-block:: nim - ## static: doAssert 1 == 9, "This assertion generates code when built with/without -d:danger or --assertions:off" - const expr = astToStr(cond) - assertImpl(cond, msg, expr, true) + ## Similar to `assert <#assert.t,untyped,string>`_ but is always turned on regardless of `--assertions`. + 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 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 - ## + ## statements following `onFailedAssert` in the current scope. template failedAssertImpl(msgIMPL: string): untyped {.dirty.} = let msg = msgIMPL code template doAssertRaises*(exception: typedesc, code: untyped) = - ## Raises ``AssertionDefect`` if specified ``code`` does not raise `exception`. - ## Example: - ## - ## .. code-block:: nim - ## doAssertRaises(ValueError): - ## raise newException(ValueError, "Hello World") + ## Raises `AssertionDefect` if specified `code` does not raise `exception`. var wrong = false const begin = "expected raising '" & astToStr(exception) & "', instead" const msgEnd = " by: " & astToStr(code) diff --git a/lib/system/assign.nim b/lib/system/assign.nim index a809fa423e..faf16fc902 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -122,7 +122,11 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = # 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) + 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)[] of tyTuple: genericAssignAux(dest, src, mt.node, shallow) diff --git a/lib/system/basic_types.nim b/lib/system/basic_types.nim index 9db81d1c44..7779e1ce90 100644 --- a/lib/system/basic_types.nim +++ b/lib/system/basic_types.nim @@ -16,8 +16,8 @@ type # we need to start a new type section here, so that ``0`` can have a 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 SomeSignedInt* = int|int8|int16|int32|int64 @@ -35,7 +35,7 @@ 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 + ## supports. Currently this is `int64`, but it is platform-dependent ## in general. @@ -43,20 +43,20 @@ type {.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/cellsets.nim b/lib/system/cellsets.nim index ea00176b53..779f1a91ff 100644 --- a/lib/system/cellsets.nim +++ b/lib/system/cellsets.nim @@ -13,7 +13,8 @@ when defined(gcOrc) or defined(gcArc): type PCell = Cell - include bitmasks + when not declaredInScope(PageShift): + include bitmasks else: type diff --git a/lib/system/channels.nim b/lib/system/channels_builtin.nim similarity index 95% rename from lib/system/channels.nim rename to lib/system/channels_builtin.nim index e4b172c167..c7a445766f 100644 --- a/lib/system/channels.nim +++ b/lib/system/channels_builtin.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. @@ -30,7 +30,7 @@ ## # Be sure to compile with --threads:on. ## # The channels and threads modules are part of system and should not be ## # imported. -## import os +## import std/os ## ## # Channels can either be: ## # - declared at the module level, or @@ -101,7 +101,7 @@ ## 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 @@ -109,7 +109,7 @@ ## 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 @@ -151,7 +151,7 @@ type region: MemRegion PRawChannel = ptr RawChannel LoadStoreMode = enum mStore, mLoad - Channel* {.gcsafe.}[TMsg] = RawChannel ## a channel for thread communication + Channel*[TMsg] {.gcsafe.} = RawChannel ## a channel for thread communication const ChannelDeadMask = -2 @@ -248,7 +248,7 @@ when not usesDestructors: 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](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), mt.base, t, mode) @@ -265,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) @@ -410,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): diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim index c57cfa9655..2e5664a958 100644 --- a/lib/system/comparisons.nim +++ b/lib/system/comparisons.nim @@ -126,15 +126,15 @@ proc `<`*[T](x, y: ptr T): bool {.magic: "LtPtr", noSideEffect.} proc `<`*(x, y: pointer): bool {.magic: "LtPtr", noSideEffect.} template `!=`*(x, y: untyped): untyped = - ## Unequals operator. This is a shorthand for ``not (x == y)``. + ## Unequals operator. This is a shorthand for `not (x == y)`. not (x == y) template `>=`*(x, y: untyped): untyped = - ## "is greater or equals" operator. This is the same as ``y <= x``. + ## "is greater or equals" operator. This is the same as `y <= x`. y <= x template `>`*(x, y: untyped): untyped = - ## "is greater" operator. This is the same as ``y < x``. + ## "is greater" operator. This is the same as `y < x`. y < x @@ -160,14 +160,14 @@ 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``. + ## 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``. + ## 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.} @@ -175,7 +175,7 @@ proc `<`*(x, y: uint64): bool {.magic: "LtU", noSideEffect.} proc `<=%`*(x, y: int): bool {.inline.} = ## Treats `x` and `y` as unsigned and compares them. - ## Returns true if ``unsigned(x) <= unsigned(y)``. + ## 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) @@ -184,7 +184,7 @@ proc `<=%`*(x, y: int64): bool {.inline.} = cast[uint64](x) <= cast[uint64](y) proc `<%`*(x, y: int): bool {.inline.} = ## Treats `x` and `y` as unsigned and compares them. - ## Returns true if ``unsigned(x) < unsigned(y)``. + ## 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) @@ -193,11 +193,11 @@ proc `<%`*(x, y: int64): bool {.inline.} = cast[uint64](x) < cast[uint64](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. @@ -235,13 +235,13 @@ proc max*(x, y: int64): int64 {.magic: "MaxI", noSideEffect.} = 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] @@ -251,9 +251,12 @@ 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 fatser than `max(a, min(b, x))`. + ## This proc is equivalent to but faster than `max(a, min(b, x))`. ## - ## **Note:** `a <= b` is assumed and will not be checked. + ## .. warning:: `a <= b` is assumed and will not be checked (currently). + ## + ## **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 @@ -282,12 +285,8 @@ 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: - when not defined(nimNoNil): - if x.isNil and y.isNil: - return true - else: - if x.len == 0 and y.len == 0: - return true + if x.len == 0 and y.len == 0: + return true else: when not defined(js): proc seqToPtr[T](x: seq[T]): pointer {.inline, noSideEffect.} = @@ -303,10 +302,6 @@ 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/countbits_impl.nim b/lib/system/countbits_impl.nim new file mode 100644 index 0000000000..d3c003ff7a --- /dev/null +++ b/lib/system/countbits_impl.nim @@ -0,0 +1,94 @@ +# +# +# 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/vmutils import forwardImpl, toUnsigned + + +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 + +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 + when x is SomeSignedInt: + let x = x.toUnsigned + 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/dollars.nim b/lib/system/dollars.nim index e87c237ad2..ce4e8e0cad 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -1,44 +1,54 @@ -import std/private/since - 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 + ## converted to a decimal string. `$` is Nim's general way of ## spelling `toString`:idx:. +template dollarImpl(x: uint | uint64, result: var string) = + type destTyp = typeof(x) + if x == 0: + result = "0" + else: + result = newString(60) + var i = 0 + var n = x + while n != 0: + let nn = n div destTyp(10) + result[i] = char(n - destTyp(10) * 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(js): + import std/private/since since (1, 3): proc `$`*(x: uint): string = ## Caveat: currently implemented as $(cast[int](x)), tied to current ## semantics of js' Number type. # for c, see strmantle.`$` - $(cast[int](x)) + when nimvm: + dollarImpl(x, result) + else: + result = $(int(x)) proc `$`*(x: uint64): string = ## Compatibility note: ## the results may change in future releases if/when js target implements ## 64bit ints. # pending https://github.com/nim-lang/RFCs/issues/187 - $(cast[int](x)) + when nimvm: + dollarImpl(x, result) + else: + result = $(cast[int](x)) else: 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]) + dollarImpl(x, result) proc `$`*(x: int64): string {.magic: "Int64ToStr", noSideEffect.} ## The stringify operator for an integer argument. Returns `x` @@ -66,19 +76,19 @@ 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 @@ -104,7 +114,7 @@ else: proc `$`*[T: tuple|object](x: T): string = - ## Generic ``$`` operator for tuples that is lifted from the components + ## Generic `$` operator for tuples that is lifted from the components ## of `x`. Example: ## ## .. code-block:: Nim @@ -154,7 +164,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 @@ -162,7 +172,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 @@ -170,7 +180,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 @@ -182,11 +192,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 1b0a3e64c2..b0f326bb5b 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -161,10 +161,7 @@ elif defined(windows) or defined(dos): dec(m) k = k div 10 if k == 0: break - when defined(nimNoArrayToCstringConversion): - result = getProcAddress(cast[THINSTANCE](lib), addr decorated) - else: - result = getProcAddress(cast[THINSTANCE](lib), decorated) + result = getProcAddress(cast[THINSTANCE](lib), addr decorated) if result != nil: return procAddrError(name) diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim index c4f15a3360..258558c3f6 100644 --- a/lib/system/embedded.nim +++ b/lib/system/embedded.nim @@ -44,3 +44,13 @@ 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") diff --git a/lib/system/exceptions.nim b/lib/system/exceptions.nim index fc8bd89f72..b5f4fc3255 100644 --- a/lib/system/exceptions.nim +++ b/lib/system/exceptions.nim @@ -39,7 +39,7 @@ type 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. + ## `raise` statement. msg* {.exportc: "message".}: string ## The exception's message. Not ## providing an exception message ## is bad style. @@ -52,7 +52,7 @@ type 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. + ## a `quit` / `trap` / `exit` operation. CatchableError* = object of Exception ## \ ## Abstract class for all exceptions that are catchable. @@ -110,13 +110,13 @@ type ## Raised if an object gets assigned to its parent's object. ObjectConversionDefect* = 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. + ## You can use `of` operator to check if conversion will succeed. FloatingPointDefect* = object of Defect ## \ ## Base class for floating point exceptions. FloatInvalidOpDefect* = object of FloatingPointDefect ## \ ## Raised by invalid operations according to IEEE. ## - ## Raised by ``0.0/0.0``, for example. + ## Raised by `0.0/0.0`, for example. FloatDivByZeroDefect* = object of FloatingPointDefect ## \ ## Raised by division by zero. ## @@ -134,13 +134,13 @@ type ## 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 ## \ ## Raised if it is attempted to send a message to a dead thread. NilAccessDefect* = object of Defect ## \ - ## Raised on dereferences of ``nil`` pointers. + ## Raised on dereferences of `nil` pointers. ## ## This is only raised if the `segfaults module `_ was imported! diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index aec25e3f3e..06fa450977 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -242,7 +242,7 @@ template addFrameEntry(s: var string, f: StackTraceEntry|PFrame) = for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ') add(s, f.procname) when NimStackTraceMsgs: - when type(f) is StackTraceEntry: + when typeof(f) is StackTraceEntry: add(s, f.frameMsg) else: var first = if f.prev == nil: 0 else: f.prev.frameMsgLen @@ -351,7 +351,7 @@ var onUnhandledException*: (proc (errorMsg: string) {. nimcall, gcsafe.}) ## Set this error \ ## handler to override the existing behaviour on an unhandled exception. ## - ## The default is to write a stacktrace to ``stderr`` and then call ``quit(1)``. + ## The default is to write a stacktrace to `stderr` and then call `quit(1)`. ## Unstable API. proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} = @@ -378,7 +378,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} = # ugly, but avoids heap allocations :-) template xadd(buf, s, slen) = if L + slen < high(buf): - copyMem(addr(buf[L]), cstring(s), slen) + copyMem(addr(buf[L]), (when s is cstring: s else: cstring(s)), slen) inc L, slen template add(buf, s) = xadd(buf, s, s.len) @@ -393,23 +393,16 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} = add(buf, " [") xadd(buf, e.name, e.name.len) add(buf, "]\n") - when defined(nimNoArrayToCstringConversion): - template tbuf(): untyped = addr buf - else: - template tbuf(): untyped = buf - if onUnhandledException != nil: - onUnhandledException($tbuf()) + onUnhandledException($buf.addr) else: - showErrorMessage(tbuf(), L) + showErrorMessage(buf.addr, L) proc reportUnhandledError(e: ref Exception) {.nodestroy.} = if unhandledExceptionHook != nil: unhandledExceptionHook(e) when hostOS != "any": reportUnhandledErrorAux(e) - else: - discard () proc nimLeaveFinally() {.compilerRtl.} = when defined(cpp) and not defined(noCppExceptions) and not gotoBasedExceptions: @@ -428,7 +421,7 @@ when gotoBasedExceptions: result = addr(nimInErrorMode) proc nimTestErrorFlag() {.compilerRtl.} = - ## This proc must be called before ``currException`` is destroyed. + ## This proc must be called before `currException` is destroyed. ## It also must be called at the end of every thread to ensure no ## error is swallowed. if nimInErrorMode and currException != nil: @@ -531,8 +524,8 @@ proc getStackTrace(e: ref Exception): string = result = "" 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. + ## 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: @@ -574,7 +567,7 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and type StdException {.importcpp: "std::exception", header: "".} = object - proc what(ex: StdException): cstring {.importcpp: "((char *)#.what())".} + proc what(ex: StdException): cstring {.importcpp: "((char *)#.what())", nodecl.} proc setTerminate(handler: proc() {.noconv.}) {.importc: "std::set_terminate", header: "".} @@ -647,7 +640,17 @@ when not defined(noSignalHandler) and not defined(useNimRtl): # unless there's a good reason to use cstring in signal handler to avoid # using gc? showErrorMessage(msg, msg.len) - quit(1) # always quit when SIGABRT + + 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: + quit(1) proc registerSignalHandler() = c_signal(SIGINT, signalHandler) diff --git a/lib/system/fatal.nim b/lib/system/fatal.nim index 761e0dd69b..64ec9cda3f 100644 --- a/lib/system/fatal.nim +++ b/lib/system/fatal.nim @@ -30,16 +30,20 @@ elif (defined(nimQuirky) or defined(nimPanics)) and not defined(nimscript): proc name(t: typedesc): string {.magic: "TypeTrait".} 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 + when nimvm: + # TODO when doAssertRaises works in CT, add a test for it + raise (ref exceptn)(msg: message & arg) + else: + 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 proc sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} = sysFatal(exceptn, message, "") diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim index 09388b6e88..45d467051e 100644 --- a/lib/system/gc2.nim +++ b/lib/system/gc2.nim @@ -7,6 +7,9 @@ # distribution, for details about the copyright. # +# xxx deadcode, consider removing unless something could be reused. + + # Garbage Collector # # The basic algorithm is an incremental mark diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index 658c5d0256..7596de6fbe 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -166,16 +166,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): @@ -432,10 +432,10 @@ proc prepareDealloc(cell: PCell) = 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: diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim index d80980c72f..0bc51d693e 100644 --- a/lib/system/inclrtl.nim +++ b/lib/system/inclrtl.nim @@ -44,10 +44,7 @@ else: {.pragma: inl, inline.} {.pragma: compilerRtl, compilerproc.} -when defined(nimlocks): - {.pragma: benign, gcsafe, locks: 0.} -else: - {.pragma: benign, gcsafe.} +{.pragma: benign, gcsafe, locks: 0.} when defined(nimHasSinkInference): {.push sinkInference: on.} diff --git a/lib/system/io.nim b/lib/system/io.nim index 22059c0a8b..300e7ea3f7 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -## This is a part of ``system.nim``, you should not manually import it. +## This is a part of `system.nim`, you should not manually import it. include inclrtl @@ -143,13 +143,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) @@ -169,19 +169,23 @@ proc readBuffer*(f: File, buffer: pointer, 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.} = - ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns + 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 ## 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) @@ -201,7 +205,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) @@ -209,7 +213,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) @@ -321,7 +325,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. @@ -329,7 +333,7 @@ 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)) @@ -339,7 +343,7 @@ proc getOsFileHandle*(f: File): FileHandle = 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 + ## `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 @@ -358,14 +362,14 @@ when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(w result = setHandleInformation(cast[IoHandle](f), HANDLE_FLAG_INHERIT, inheritable.WinDWORD) != 0 -proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], +proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect], benign.} = ## 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: "".} @@ -420,35 +424,35 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], if buffer[i].uint16 == 26: #Ctrl+Z close(f) #has the same effect as setting EOF if i == 0: - line = TaintedString("") + line = "" return false numberOfCharsRead = i break buffer[numberOfCharsRead] = 0.Utf16Char when defined(nimv2): - line = TaintedString($toWideCString(buffer)) + line = $toWideCString(buffer) else: - line = TaintedString($buffer) + line = $buffer return(true) var pos = 0 # Use the currently reserved space for a first try - var sp = max(line.string.len, 80) - line.string.setLen(sp) + var sp = max(line.len, 80) + line.setLen(sp) while true: # memset to \L so that we can tell how far fgets wrote, even on EOF, where # fgets doesn't append an \L - for i in 0.. 0 and line.string[last-1] == '\c': - line.string.setLen(last-1) + var last = cast[ByteAddress](m) - cast[ByteAddress](addr line[0]) + if last > 0 and line[last-1] == '\c': + line.setLen(last-1) return last > 1 or fgetsSuccess # 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. - elif last > 0 and line.string[last-1] == '\0': - if last < pos + sp - 1 and line.string[last+1] != '\0': + elif last > 0 and line[last-1] == '\0': + if last < pos + sp - 1 and line[last+1] != '\0': dec last - line.string.setLen(last) + line.setLen(last) return last > 0 or fgetsSuccess else: # fgets will have inserted a null byte at the end of the string. @@ -477,13 +481,13 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], # No \l found: Increase buffer and read more inc pos, sp sp = 128 # read in 128 bytes at a time - line.string.setLen(pos+sp) + line.setLen(pos+sp) -proc readLine*(f: File): TaintedString {.tags: [ReadIOEffect], benign.} = +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 + ## A line of text may be delimited by `LF` or `CRLF`. The newline ## character(s) are not part of the returned string. - result = TaintedString(newStringOfCap(80)) + result = newStringOfCap(80) if not readLine(f, result): raiseEOF() proc write*(f: File, i: int) {.tags: [WriteIOEffect], benign.} = @@ -563,7 +567,7 @@ proc readAllFile(file: File): string = var len = rawFileSize(file) result = readAllFile(file, len) -proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], benign.} = +proc readAll*(file: File): string {.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 @@ -576,9 +580,9 @@ proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], benign.} = else: let len = rawFileSize(file) if len > 0: - result = readAllFile(file, len).TaintedString + result = readAllFile(file, len) else: - result = readAllBuffer(file).TaintedString + result = readAllBuffer(file) proc writeLine*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, tags: [WriteIOEffect], benign.} = @@ -676,7 +680,7 @@ proc open*(f: var File, filename: string, ## Default mode is readonly. Returns true if 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. + ## The file handle associated with the resulting `File` is not inheritable. var p = fopen(filename, FormatOpen[mode]) if p != nil: var f2 = cast[File](p) @@ -720,7 +724,7 @@ proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {. 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. ## @@ -736,10 +740,10 @@ 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. + ## The file handle associated with the resulting `File` is not inheritable. if not open(result, filename, mode, bufSize): sysFatal(IOError, "cannot open: " & filename) @@ -783,7 +787,7 @@ when declared(stdout): not defined(nintendoswitch) and not defined(freertos) and hostOS != "any" - const echoDoRaise = not defined(nimLegacyEchoNoRaise) # see PR #16366 + const echoDoRaise = not defined(nimLegacyEchoNoRaise) and not defined(guiapp) # see PR #16366 template checkErrMaybe(succeeded: bool): untyped = if not succeeded: @@ -841,7 +845,7 @@ when defined(windows) and appType == "console" and discard setConsoleOutputCP(Utf8codepage) discard setConsoleCP(Utf8codepage) -proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.} = +proc readFile*(filename: string): string {.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 @@ -882,15 +886,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[TaintedString] = +proc readLines*(filename: string, n: Natural): seq[string] = ## 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 if open(f, filename): try: - result = newSeq[TaintedString](n) + result = newSeq[string](n) for i in 0 .. n - 1: if not readLine(f, result[i]): raiseEOF() @@ -899,31 +903,31 @@ proc readLines*(filename: string, n: Natural): seq[TaintedString] = else: sysFatal(IOError, "cannot open: " & filename) -template readLines*(filename: string): seq[TaintedString] {.deprecated: "use readLines with two arguments".} = +template readLines*(filename: string): seq[string] {.deprecated: "use readLines with two arguments".} = readLines(filename, 1) -iterator lines*(filename: string): TaintedString {.tags: [ReadIOEffect].} = +iterator lines*(filename: string): string {.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: ## ## .. code-block:: nim - ## import strutils + ## import std/strutils ## ## proc transformLetters(filename: string) = ## var buffer = "" ## for line in filename.lines: - ## buffer.add(line.replace("a", "0") & '\x0A') + ## buffer.add(line.replace("a", "0") & '\n') ## writeFile(filename, buffer) var f = open(filename, bufSize=8000) try: - var res = TaintedString(newStringOfCap(80)) + var res = newStringOfCap(80) while f.readLine(res): yield res finally: close(f) -iterator lines*(f: File): TaintedString {.tags: [ReadIOEffect].} = +iterator lines*(f: File): string {.tags: [ReadIOEffect].} = ## Iterate over any line in the file `f`. ## ## The trailing newline character(s) are removed from the iterated lines. @@ -936,5 +940,5 @@ iterator lines*(f: File): TaintedString {.tags: [ReadIOEffect].} = ## if letter == '0': ## result.zeros += 1 ## result.lines += 1 - var res = TaintedString(newStringOfCap(80)) + var res = newStringOfCap(80) while f.readLine(res): yield res diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim index c8c0edbd41..d8af4eed56 100644 --- a/lib/system/iterators.nim +++ b/lib/system/iterators.nim @@ -56,60 +56,96 @@ iterator items*[T](a: set[T]): T {.inline.} = iterator items*(a: cstring): char {.inline.} = ## Iterates over each item of `a`. - when defined(js): + 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() = var i = 0 - var L = len(a) - while i < L: + let n = len(a) + while i < n: yield a[i] inc(i) + when defined(js): impl() else: - var i = 0 - while a[i] != '\0': - yield a[i] - inc(i) + when nimvm: + # xxx `cstring` should behave like c backend instead. + impl() + else: + 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. - when defined(js): - var i = 0 - var L = len(a) - while i < L: - yield a[i] - inc(i) - else: - var i = 0 - while a[i] != '\0': - yield a[i] - inc(i) + # xxx this should give CT error in js RT. + runnableExamples: + from std/sugar import collect + var a = "abc\0def" + 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" -iterator items*[T: enum](E: typedesc[T]): T = - ## Iterates over the values of the enum ``E``. + template impl() = + var i = 0 + let n = len(a) + while i < n: + 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) + +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] for v in low(E) .. high(E): yield v -iterator items*[T](s: HSlice[T, T]): T = +iterator items*[T: Ordinal](s: Slice[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. + ## Iterates over each item of `a`. Yields `(index, a[index])` pairs. var i = low(IX) if i <= high(IX): while true: @@ -118,8 +154,8 @@ iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} = 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. + ## 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: @@ -128,7 +164,7 @@ iterator mpairs*[IX, T](a: var array[IX, T]): tuple[key: IX, val: var T] {.inlin 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: @@ -137,8 +173,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: @@ -147,7 +183,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: @@ -156,8 +192,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: @@ -166,7 +202,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) @@ -180,8 +216,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) @@ -235,24 +271,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(type(v)) + for v in fields(t): v = default(typeof(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(type(t1)) + var t2 = default(typeof(t1)) for v1, v2 in fields(t1, t2): v2 = v1 doAssert t1 == t2 @@ -261,16 +297,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 @@ -289,9 +325,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 2bc58c2b77..be61fd62ce 100644 --- a/lib/system/iterators_1.nim +++ b/lib/system/iterators_1.nim @@ -12,7 +12,7 @@ iterator countdown*[T](a, b: T, step: Positive = 1): T {.inline.} = ## **Note**: This fails to count to `low(int)` if T = int for ## efficiency reasons. runnableExamples: - import sugar + import std/sugar let x = collect(newSeq): for i in countdown(7, 3): i @@ -49,7 +49,7 @@ iterator countup*[T](a, b: T, step: Positive = 1): T {.inline.} = ## **Note**: This fails to count to `high(int)` if T = int for ## efficiency reasons. runnableExamples: - import sugar + import std/sugar let x = collect(newSeq): for i in countup(3, 7): i @@ -78,7 +78,7 @@ iterator `..`*[T](a, b: T): T {.inline.} = ## See also: ## * [..<](#..<.i,T,T) runnableExamples: - import sugar + import std/sugar let x = collect(newSeq): for i in 3 .. 7: diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 7848a435e3..ef06437e51 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -189,9 +189,8 @@ proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} = proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} = {.emit: """ - var ln = `c`.length; - var result = new Array(ln); - for (var i = 0; i < ln; ++i) { + var result = []; + for (var i = 0; i < `c`.length; ++i) { result[i] = `c`.charCodeAt(i); } return result; @@ -496,11 +495,13 @@ proc negInt64(a: int64): int64 {.compilerproc.} = proc nimFloatToString(a: float): cstring {.compilerproc.} = ## 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" + if (Number.isSafeInteger(`a`)) + `result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0" else { `result` = `a`+"" if(nimOnlyDigitsOrMinus(`result`)){ @@ -644,7 +645,7 @@ proc genericReset(x: JSRef, ti: PNimType): JSRef {.compilerproc.} = asm "`result` = {m_type: `ti`};" else: asm "`result` = {};" - of tySequence, tyOpenArray: + of tySequence, tyOpenArray, tyString: asm """ `result` = []; """ diff --git a/lib/system/memalloc.nim b/lib/system/memalloc.nim index f5e8b2363a..fca1db91dd 100644 --- a/lib/system/memalloc.nim +++ b/lib/system/memalloc.nim @@ -1,38 +1,51 @@ when notJSnotNims: proc zeroMem*(p: pointer, size: Natural) {.inline, noSideEffect, tags: [], locks: 0, raises: [].} - ## Overwrites the contents of the memory at ``p`` with the value 0. + ## 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: [], locks: 0, raises: [].} - ## Copies the contents from the memory at ``source`` to the memory - ## at ``dest``. - ## Exactly ``size`` bytes will be copied. The memory + ## 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: [], locks: 0, raises: [].} - ## Copies the contents from the memory at ``source`` to the memory - ## at ``dest``. + ## 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: [], locks: 0, raises: [].} - ## Compares the memory blocks ``a`` and ``b``. ``size`` bytes will + ## 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: [], locks: 0, 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: [].} @@ -75,7 +88,7 @@ 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>`_ ## or `dealloc(block) <#dealloc,pointer>`_. @@ -91,7 +104,7 @@ when hasAlloc and not defined(js): 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>`_. @@ -106,7 +119,7 @@ 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>`_ ## or `dealloc(block) <#dealloc,pointer>`_. @@ -119,7 +132,7 @@ when hasAlloc and not defined(js): 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>`_. @@ -134,8 +147,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>`_. ## @@ -148,8 +161,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>`_. ## @@ -165,9 +178,9 @@ 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 @@ -175,8 +188,8 @@ when hasAlloc and not defined(js): 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`` or - ## ``realloc``. + ## 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 @@ -190,7 +203,7 @@ 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>`_ @@ -200,14 +213,14 @@ when hasAlloc and not defined(js): ## to it is undefined behaviour! ## ## See also: - ## `allocShared0 <#allocShared0.t,Natural>`_. + ## * `allocShared0 <#allocShared0.t,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 @@ -222,7 +235,7 @@ 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>`_ @@ -236,7 +249,7 @@ when hasAlloc and not defined(js): 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 @@ -251,9 +264,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) @@ -265,9 +278,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) @@ -276,16 +289,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 @@ -295,8 +308,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 @@ -304,7 +317,7 @@ when hasAlloc and not defined(js): ## or other memory may be corrupted. deallocShared(p) - include bitmasks + include bitmasks template `+!`(p: pointer, s: SomeInteger): pointer = cast[pointer](cast[int](p) +% int(s)) @@ -318,7 +331,7 @@ when hasAlloc and not defined(js): result = allocShared(size) else: result = alloc(size) - else: + else: # allocate (size + align - 1) necessary for alignment, # plus 2 bytes to store offset when compileOption("threads"): @@ -326,7 +339,7 @@ when hasAlloc and not defined(js): 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, + # 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) @@ -338,7 +351,7 @@ when hasAlloc and not defined(js): result = allocShared0(size) else: result = alloc0(size) - else: + else: # see comments for alignedAlloc when compileOption("threads"): let base = allocShared0(size + align - 1 + sizeof(uint16)) @@ -348,13 +361,13 @@ when hasAlloc and not defined(js): cast[ptr uint16](base +! (offset - sizeof(uint16)))[] = uint16(offset) result = base +! offset - proc alignedDealloc(p: pointer, align: int) {.compilerproc.} = + proc alignedDealloc(p: pointer, align: int) {.compilerproc.} = if align <= MemAlign: when compileOption("threads"): deallocShared(p) else: dealloc(p) - else: + else: # read offset at p - 2 bytes, then deallocate (p - offset) pointer let offset = cast[ptr uint16](p -! sizeof(uint16))[] when compileOption("threads"): diff --git a/lib/system/memory.nim b/lib/system/memory.nim index 50faa3d862..ebda60d8d1 100644 --- a/lib/system/memory.nim +++ b/lib/system/memory.nim @@ -2,9 +2,6 @@ const useLibC = not defined(nimNoLibc) -when not defined(nimHasHotCodeReloading): - {.pragma: nonReloadable.} - when useLibC: import ansi_c diff --git a/lib/system/memtracker.nim b/lib/system/memtracker.nim index 115d4a973b..f0c83f1fa6 100644 --- a/lib/system/memtracker.nim +++ b/lib/system/memtracker.nim @@ -100,6 +100,7 @@ proc logPendingOps() {.noconv.} = gLogger(gLog) gLog.count = 0 -addQuitProc logPendingOps +import std/exitprocs +addExitProc logPendingOps {.pop.} diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 8589b678dd..96dc86bfd2 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -68,9 +68,7 @@ else: include "system/cellsets" when not leakDetector and not useCellIds and not defined(nimV2): sysAssert(sizeof(Cell) == sizeof(FreeCell), "sizeof FreeCell") - when compileOption("gc", "v2"): - include "system/gc2" - elif defined(gcRegions): + when defined(gcRegions): # XXX due to bootstrapping reasons, we cannot use compileOption("gc", "stack") here include "system/gc_regions" elif defined(nimV2) or usesDestructors: diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index 498faca3f9..9ece10e3ea 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 @@ -57,7 +57,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 +66,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 +82,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 +112,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].} = @@ -159,16 +159,29 @@ proc toDll*(filename: string): string = proc strip(s: string): string = var i = 0 - while s[i] in {' ', '\c', '\L'}: inc i + while s[i] in {' ', '\c', '\n'}: inc i result = s.substr(i) + if result[0] == '"' and result[^1] == '"': + result = result[1..^2] template `--`*(key, val: untyped) = - ## A shortcut for ``switch(astToStr(key), astToStr(val))``. - switch(astToStr(key), strip astToStr(val)) + ## 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))) template `--`*(key: untyped) = - ## A shortcut for ``switch(astToStr(key)``. - switch(astToStr(key), "") + ## A shortcut for `switch <#switch,string,string>`_ + ## Example: + ## + ## .. code-block:: nim + ## + ## --listCmd # same as switch("listCmd") + switch(strip(astToStr(key))) type ScriptMode* {.pure.} = enum ## Controls the behaviour of the script. @@ -252,7 +265,7 @@ proc exec*(command: string) {. ## 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: @@ -273,7 +286,7 @@ proc exec*(command: string, input: string, cache = "") {. proc selfExec*(command: string) {. 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: @@ -310,9 +323,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].} = @@ -356,25 +369,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(): TaintedString {. +proc stdinReadLine(): string {. tags: [ReadIOEffect], raises: [IOError].} = builtin -proc stdinReadAll(): TaintedString {. +proc stdinReadAll(): string {. tags: [ReadIOEffect], raises: [IOError].} = builtin -proc readLineFromStdin*(): TaintedString {.raises: [IOError].} = +proc readLineFromStdin*(): string {.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*(): TaintedString {.raises: [IOError].} = +proc readAllFromStdin*(): string {.raises: [IOError].} = ## Reads all data from stdin - blocks until EOF which happens when stdin is closed log "readAllFromStdin": result = stdinReadAll() @@ -391,8 +404,8 @@ when not defined(nimble): ## 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 + ## 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: diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 803f3d4103..8a62ef4bb0 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -407,14 +407,14 @@ proc GC_runOrc* = collectCycles() 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. + ## 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. + ## 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) @@ -424,16 +424,16 @@ 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``. + ## 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``. + ## For `--gc:orc` an alias for `GC_enableOrc`. GC_enableOrc() proc GC_disableMarkAndSweep*() = - ## For ``--gc:orc`` an alias for ``GC_disableOrc``. + ## For `--gc:orc` an alias for `GC_disableOrc`. GC_disableOrc() when optimizedOrc: diff --git a/lib/system/repr.nim b/lib/system/repr.nim index ae51a4aabf..7424500ebd 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -16,14 +16,9 @@ proc reprInt(x: int64): string {.compilerproc.} = return $x proc reprFloat(x: float): string {.compilerproc.} = return $x proc reprPointer(x: pointer): string {.compilerproc.} = - 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 + result = newString(60) + let n = c_sprintf(addr result[0], "%p", x) + setLen(result, n) proc reprStrAux(result: var string, s: cstring; len: int) = if cast[pointer](s) == nil: diff --git a/lib/system/sets.nim b/lib/system/sets.nim index 42c4488486..103c8d343e 100644 --- a/lib/system/sets.nim +++ b/lib/system/sets.nim @@ -12,22 +12,6 @@ type NimSet = array[0..4*2048-1, uint8] -# 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 diff --git a/lib/system/stacktraces.nim b/lib/system/stacktraces.nim index 6c7b1433c3..8142f8c7b8 100644 --- a/lib/system/stacktraces.nim +++ b/lib/system/stacktraces.nim @@ -19,7 +19,7 @@ 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. + ## This is the same as the type `uintptr_t` in C. StackTraceOverrideGetTracebackProc* = proc (): string {. nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.} diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index b5d275e25d..42ea9d2260 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -24,26 +24,26 @@ const digitsTable = "0001020304050607080910111213141516171819" & # else: # res.add $i # doAssert res == digitsTable - + func digits10(num: uint64): int {.noinline.} = - if num < 10: + if num < 10'u64: result = 1 - elif num < 100: + elif num < 100'u64: result = 2 - elif num < 1_000: + elif num < 1_000'u64: result = 3 - elif num < 10_000: + elif num < 10_000'u64: result = 4 - elif num < 100_000: + elif num < 100_000'u64: result = 5 - elif num < 1_000_000: + elif num < 1_000_000'u64: result = 6 - elif num < 10_000_000: + elif num < 10_000_000'u64: result = 7 - elif num < 100_000_000: + elif num < 100_000_000'u64: result = 8 - elif num < 1_000_000_000: + elif num < 1_000_000_000'u64: result = 9 elif num < 10_000_000_000'u64: result = 10 @@ -329,11 +329,7 @@ proc nimParseBiggestFloat(s: string, 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 - - when defined(nimNoArrayToCstringConversion): - number = c_strtod(addr t, nil) - else: - number = c_strtod(t, nil) + number = c_strtod(addr t, nil) when defined(nimHasInvariant): {.pop.} # staticBoundChecks diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index fe117997bf..6944cdc589 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -168,3 +168,10 @@ proc nimPrepareStrMutationImpl(s: var NimStringV2) = proc nimPrepareStrMutationV2(s: var NimStringV2) {.compilerRtl, inline.} = 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)[]) diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim index 07fb9cb8ab..51dbfd3a29 100644 --- a/lib/system/syslocks.nim +++ b/lib/system/syslocks.nim @@ -11,7 +11,7 @@ {.push stackTrace: off.} -when defined(Windows): +when defined(windows): type Handle = int diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 06e605a7bb..49fff41e9e 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -304,7 +304,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericS when not defined(boehmGC) and not defined(nogc) and not defined(gcMarkAndSweep) and not defined(gogc) and not defined(gcRegions): - when false: # compileOption("gc", "v2"): + when false: # deadcode: was used by `compileOption("gc", "v2")` for i in newLen..result.len-1: let len0 = gch.tempStack.len forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i), diff --git a/lib/system/threadlocalstorage.nim b/lib/system/threadlocalstorage.nim index 117af4c25e..922150fff7 100644 --- a/lib/system/threadlocalstorage.nim +++ b/lib/system/threadlocalstorage.nim @@ -208,7 +208,7 @@ when emulatedThreadVars: # 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: +# We use `float` for proper alignment: const nimTlsSize {.intdefine.} = 16000 type ThreadLocalStorage = array[0..(nimTlsSize div sizeof(float)), float] diff --git a/lib/system/threads.nim b/lib/system/threads.nim index cd1cf5e298..def35c2388 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -11,7 +11,7 @@ ## ## **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. +## 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 @@ -24,7 +24,7 @@ ## ## .. code-block:: Nim ## -## import locks +## import std/locks ## ## var ## thr: array[0..4, Thread[tuple[a,b: int]]] @@ -97,7 +97,7 @@ 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 + ## 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. threadDestructionHandlers.add handler @@ -261,7 +261,7 @@ when hostOS == "windows": ## 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 + ## `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))) @@ -310,7 +310,7 @@ else: ## 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 + ## `TArg` can be `void` if you ## don't need to pass any data to the thread. t.core = cast[PGcThread](allocShared0(sizeof(GcThread))) diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index 955fab46a5..16bc3f3cae 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -75,8 +75,8 @@ const UNI_REPLACEMENT_CHAR = Utf16Char(0xFFFD'i16) UNI_MAX_BMP = 0x0000FFFF UNI_MAX_UTF16 = 0x0010FFFF - UNI_MAX_UTF32 = 0x7FFFFFFF - UNI_MAX_LEGAL_UTF32 = 0x0010FFFF + # UNI_MAX_UTF32 = 0x7FFFFFFF + # UNI_MAX_LEGAL_UTF32 = 0x0010FFFF halfShift = 10 halfBase = 0x0010000 @@ -91,7 +91,7 @@ const 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`` + ## 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 @@ -142,6 +142,9 @@ iterator runes(s: cstring, L: int): int = 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 diff --git a/lib/system_overview.rst b/lib/system_overview.rst index 2e437e5960..d6cbe1a35f 100644 --- a/lib/system_overview.rst +++ b/lib/system_overview.rst @@ -1,3 +1,5 @@ +.. default-role:: code + The System module imports several separate modules, and their documentation is in separate files: @@ -12,8 +14,9 @@ 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. -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. +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. Strings and characters @@ -35,7 +38,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 diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 1334a85d54..1cdb20fe73 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -25,6 +25,7 @@ when useWinUnicode: else: type WinChar* = char +# See https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types type Handle* = int LONG* = int32 @@ -33,6 +34,7 @@ type 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,6 +42,7 @@ type PULONG_PTR* = ptr uint HDC* = Handle HGLRC* = Handle + BYTE* = cuchar SECURITY_ATTRIBUTES* {.final, pure.} = object nLength*: int32 @@ -136,6 +139,10 @@ const 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 {. @@ -1119,7 +1126,7 @@ proc SwitchToFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kerne 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 @@ -1129,5 +1136,42 @@ 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/linenoise/linenoise.c b/lib/wrappers/linenoise/linenoise.c index ae185fece9..be792b96b0 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) +static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt, linenoiseData* data) { struct linenoiseState l; @@ -827,6 +827,7 @@ 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 */ @@ -839,6 +840,7 @@ 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; @@ -979,7 +981,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) { +static int linenoiseRaw(char *buf, size_t buflen, const char *prompt, linenoiseData* data) { int count; if (buflen == 0) { @@ -988,7 +990,7 @@ static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) { } if (enableRawMode(STDIN_FILENO) == -1) return -1; - count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt); + count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt, data); disableRawMode(STDIN_FILENO); printf("\n"); return count; @@ -1035,7 +1037,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 *linenoise(const char *prompt) { +char *linenoiseExtra(const char *prompt, linenoiseData* data) { char buf[LINENOISE_MAX_LINE]; int count; @@ -1056,12 +1058,18 @@ char *linenoise(const char *prompt) { } return strdup(buf); } else { - count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt); + count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt, data); 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 ed20232c57..aa86ccb78a 100644 --- a/lib/wrappers/linenoise/linenoise.h +++ b/lib/wrappers/linenoise/linenoise.h @@ -48,6 +48,16 @@ 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 *); @@ -57,6 +67,7 @@ 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 a6260eb128..5b1fa71907 100644 --- a/lib/wrappers/linenoise/linenoise.nim +++ b/lib/wrappers/linenoise/linenoise.nim @@ -9,14 +9,14 @@ type Completions* = object - len*: csize + len*: csize_t cvec*: cstringArray CompletionCallback* = proc (a2: cstring; a3: ptr Completions) {.cdecl.} {.compile: "linenoise.c".} -proc setCompletionCallback*(a2: ptr CompletionCallback) {. +proc setCompletionCallback*(a2: CompletionCallback) {. importc: "linenoiseSetCompletionCallback".} proc addCompletion*(a2: ptr Completions; a3: cstring) {. importc: "linenoiseAddCompletion".} @@ -32,3 +32,41 @@ proc printKeyCodes*() {.importc: "linenoisePrintKeyCodes".} proc free*(s: cstring) {.importc: "free", header: "".} +when defined nimExperimentalLinenoiseExtra: + # 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 index 209f63c21b..2fefe4a8b7 100644 --- a/lib/wrappers/mysql.nim +++ b/lib/wrappers/mysql.nim @@ -11,14 +11,14 @@ when defined(nimHasStyleChecks): {.push styleChecks: off.} -when defined(Unix): +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): +when defined(windows): const lib = "(libmysql.dll|libmariadb.dll)" type diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 694152db1a..313ce7d199 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -12,9 +12,9 @@ ## 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. +## 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``. +## define the `openssl10` symbol via `-d:openssl10`. ## ## Build and test examples: ## @@ -25,7 +25,7 @@ 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.0.0 # See: #10281, #10230 @@ -475,11 +475,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: DLLSSLName, importc.} + dynlib: DLLUtilName, 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: DLLSSLName, importc.} + dynlib: DLLUtilName, 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 = @@ -497,14 +497,14 @@ when not defined(nimfix): proc BIO_free*(b: BIO): cint{.cdecl, dynlib: DLLUtilName, importc.} -proc ERR_print_errors_fp*(fp: File){.cdecl, dynlib: DLLSSLName, importc.} +proc ERR_print_errors_fp*(fp: File){.cdecl, dynlib: DLLUtilName, importc.} proc ERR_error_string*(e: culong, 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 OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.} +proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLUtilName, importc.} proc OPENSSL_sk_num*(stack: PSTACK): int {.cdecl, dynlib: DLLSSLName, importc.} @@ -512,10 +512,10 @@ proc OPENSSL_sk_value*(stack: PSTACK, index: int): pointer {.cdecl, dynlib: DLLSSLName, importc.} proc d2i_X509*(px: ptr PX509, i: ptr ptr cuchar, len: cint): PX509 {.cdecl, - dynlib: DLLSSLName, importc.} + dynlib: DLLUtilName, importc.} proc i2d_X509*(cert: PX509; o: ptr ptr cuchar): cint {.cdecl, - dynlib: DLLSSLName, importc.} + dynlib: DLLUtilName, importc.} proc d2i_X509*(b: string): PX509 = ## decode DER/BER bytestring into X.509 certificate struct @@ -586,7 +586,7 @@ 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 @@ -646,34 +646,34 @@ 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: DLLSSLName, importc.} - + dynlib: DLLUtilName, importc.} +proc PEM_read_RSA_PUBKEY*(fp: pointer; x: ptr PRSA; cb: pem_password_cb, u: pointer): PRSA {.cdecl, + dynlib: DLLUtilName, importc.} proc RSA_verify*(kind: cint, origMsg: pointer, origMsgLen: cuint, signature: pointer, - signatureLen: cuint, rsa: PRSA): cint {.cdecl, dynlib: DLLSSLName, importc.} + 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: DLLSSLName, importc.} + dynlib: DLLUtilName, importc.} proc PEM_read_RSAPublicKey*(fp: pointer; x: ptr PRSA; cb: pem_password_cb, u: pointer): PRSA {.cdecl, - dynlib: DLLSSLName, importc.} + dynlib: DLLUtilName, importc.} proc PEM_read_bio_RSAPublicKey*(bp: BIO, x: ptr PRSA, cb: pem_password_cb, u: pointer): PRSA {.cdecl, - dynlib: DLLSSLName, importc.} + dynlib: DLLUtilName, importc.} proc PEM_read_bio_RSAPrivateKey*(bp: BIO, x: ptr PRSA, cb: pem_password_cb, u: pointer): PRSA {.cdecl, - dynlib: DLLSSLName, importc.} + dynlib: DLLUtilName, importc.} proc RSA_private_encrypt*(flen: cint, fr: ptr cuchar, to: ptr cuchar, rsa: PRSA, padding: PaddingType): cint {.cdecl, - dynlib: DLLSSLName, importc.} + dynlib: DLLUtilName, importc.} proc RSA_public_encrypt*(flen: cint, fr: ptr cuchar, to: ptr cuchar, rsa: PRSA, padding: PaddingType): cint {.cdecl, - dynlib: DLLSSLName, importc.} + dynlib: DLLUtilName, importc.} proc RSA_private_decrypt*(flen: cint, fr: ptr cuchar, to: ptr cuchar, rsa: PRSA, padding: PaddingType): cint {.cdecl, - dynlib: DLLSSLName, importc.} + dynlib: DLLUtilName, importc.} proc RSA_public_decrypt*(flen: cint, fr: ptr cuchar, to: ptr cuchar, rsa: PRSA, padding: PaddingType): cint {.cdecl, - dynlib: DLLSSLName, importc.} -proc RSA_free*(rsa: PRSA) {.cdecl, dynlib: DLLSSLName, importc.} -proc RSA_size*(rsa: PRSA): cint {.cdecl, dynlib: DLLSSLName, importc.} + dynlib: DLLUtilName, importc.} +proc RSA_free*(rsa: PRSA) {.cdecl, dynlib: DLLUtilName, importc.} +proc RSA_size*(rsa: PRSA): cint {.cdecl, dynlib: DLLUtilName, importc.} # sha types proc EVP_md_null*(): EVP_MD {.cdecl, importc.} @@ -760,7 +760,7 @@ proc md5_File*(file: string): string {.raises: [IOError,Exception].} = ctx: MD5_CTX discard md5_Init(ctx) - while(let bytes = f.readChars(buf, 0, sz); bytes > 0): + while (let bytes = f.readChars(buf); bytes > 0): discard md5_Update(ctx, buf[0].addr, cast[csize_t](bytes)) discard md5_Final(buf[0].addr, ctx) diff --git a/lib/wrappers/postgres.nim b/lib/wrappers/postgres.nim index 24eac54f91..0bde3f1e6e 100644 --- a/lib/wrappers/postgres.nim +++ b/lib/wrappers/postgres.nim @@ -53,7 +53,8 @@ type 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 + PGRES_COPY_IN, PGRES_BAD_RESPONSE, PGRES_NONFATAL_ERROR, PGRES_FATAL_ERROR, + PGRES_COPY_BOTH, PGRES_SINGLE_TUPLE PGlobjfuncs*{.pure, final.} = object fn_lo_open*: Oid fn_lo_close*: Oid @@ -69,7 +70,8 @@ type ConnStatusType* = enum CONNECTION_OK, CONNECTION_BAD, CONNECTION_STARTED, CONNECTION_MADE, CONNECTION_AWAITING_RESPONSE, CONNECTION_AUTH_OK, CONNECTION_SETENV, - CONNECTION_SSL_STARTUP, CONNECTION_NEEDED + CONNECTION_SSL_STARTUP, CONNECTION_NEEDED, CONNECTION_CHECK_WRITABLE, + CONNECTION_CONSUME, CONNECTION_GSS_STARTUP, CONNECTION_CHECK_TARGET PGconn*{.pure, final.} = object pghost*: cstring pgtty*: cstring @@ -114,7 +116,7 @@ type PQTRANS_UNKNOWN PPGVerbosity* = ptr PGVerbosity PGVerbosity* = enum - PQERRORS_TERSE, PQERRORS_DEFAULT, PQERRORS_VERBOSE + PQERRORS_TERSE, PQERRORS_DEFAULT, PQERRORS_VERBOSE, PQERRORS_SQLSTATE PPGNotify* = ptr pgNotify pgNotify*{.pure, final.} = object relname*: cstring @@ -238,6 +240,7 @@ proc pqexecPrepared*(conn: PPGconn, stmtName: cstring, nParams: int32, cdecl, dynlib: dllName, importc: "PQexecPrepared".} proc pqsendQuery*(conn: PPGconn, query: cstring): int32{.cdecl, dynlib: dllName, importc: "PQsendQuery".} + ## See also https://www.postgresql.org/docs/current/libpq-async.html proc pqsendQueryParams*(conn: PPGconn, command: cstring, nParams: int32, paramTypes: POid, paramValues: cstringArray, paramLengths, paramFormats: ptr int32, @@ -248,6 +251,9 @@ proc pqsendQueryPrepared*(conn: PPGconn, stmtName: cstring, nParams: int32, paramLengths, paramFormats: ptr int32, resultFormat: int32): int32{.cdecl, dynlib: dllName, importc: "PQsendQueryPrepared".} +proc pqSetSingleRowMode*(conn: PPGconn): int32{.cdecl, dynlib: dllName, + importc: "PQsetSingleRowMode".} + ## See also https://www.postgresql.org/docs/current/libpq-single-row-mode.html proc pqgetResult*(conn: PPGconn): PPGresult{.cdecl, dynlib: dllName, importc: "PQgetResult".} proc pqisBusy*(conn: PPGconn): int32{.cdecl, dynlib: dllName, diff --git a/lib/wrappers/sqlite3.nim b/lib/wrappers/sqlite3.nim index 6fc6c7aa74..71921c10b7 100644 --- a/lib/wrappers/sqlite3.nim +++ b/lib/wrappers/sqlite3.nim @@ -26,7 +26,7 @@ else: when defined(staticSqlite): {.pragma: mylib.} - {.compile: "sqlite3.c".} + {.compile("sqlite3.c", "-O3").} else: {.pragma: mylib, dynlib: Lib.} diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index a95fac0bd9..23d1920097 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -215,7 +215,7 @@ stmt = IND{>} stmt ^+ IND{=} DED # list of statements

    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.

    +

    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.

    diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index 35a5dfb56d..4646732f1f 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -98,7 +98,7 @@ window.addEventListener('DOMContentLoaded', main);
        foo
      • foo
      • + title="foo()">foo()
      diff --git a/nimdoc/tester.nim b/nimdoc/tester.nim index 15dd32ec7d..5262952224 100644 --- a/nimdoc/tester.nim +++ b/nimdoc/tester.nim @@ -1,5 +1,5 @@ # Small program that runs the test cases for 'nim doc'. -# To run this, cd to the git repo root, and run "nim c -r nimdoc/tester.nim". +# 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:fixup import strutils, os diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css new file mode 100644 index 0000000000..db9a7ce979 --- /dev/null +++ b/nimdoc/testproject/expected/nimdoc.out.css @@ -0,0 +1,954 @@ +/* +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; + --raw-data: #a4255b; +} + +[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; + --raw-data: #8be9fd; +} + +.theme-switch-wrapper { + display: flex; + align-items: center; +} + +.theme-switch-wrapper em { + margin-left: 10px; + font-size: 1rem; +} + +.theme-switch { + display: inline-block; + height: 22px; + position: relative; + width: 50px; +} + +.theme-switch input { + display: none; +} + +.slider { + background-color: #ccc; + bottom: 0; + cursor: pointer; + left: 0; + position: absolute; + right: 0; + top: 0; + transition: .4s; +} + +.slider:before { + background-color: #fff; + bottom: 4px; + content: ""; + height: 13px; + left: 4px; + position: absolute; + transition: .4s; + width: 13px; +} + +input:checked + .slider { + background-color: #66bb6a; +} + +input:checked + .slider:before { + transform: translateX(26px); +} + +.slider.round { + border-radius: 17px; +} + +.slider.round:before { + border-radius: 50%; +} + +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%; +} + +.column:first-child, +.columns:first-child { + margin-left: 0; } + +.three.columns { + width: 22%; +} + +.nine.columns { + width: 77.0%; } + +.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 */ +/* 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.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; +} + +blockquote { + font-size: 0.9em; + font-style: italic; + padding-left: 0.5em; + margin-left: 0; + border-left: 5px solid #bbc; +} + +.pre { + 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; +} + +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; } + +.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.option { + white-space: nowrap; } + +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.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 27cef017b5..cb80f2873c 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -112,7 +112,7 @@ window.addEventListener('DOMContentLoaded', main);
          someType
        • someType_2
        • + title="someType(): SomeType">someType(): SomeType
        @@ -121,12 +121,21 @@ window.addEventListener('DOMContentLoaded', main);
      • Templates
      • diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 2bf8855c73..48b3094e7e 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -148,154 +148,159 @@ window.addEventListener('DOMContentLoaded', main);
            z10
          • z10
          • + title="z10()">z10()
            tripleStrLitTest
          • tripleStrLitTest
          • + title="tripleStrLitTest()">tripleStrLitTest()
            z17
          • z17
          • + title="z17()">z17()
            asyncFun3
          • asyncFun3
          • + title="asyncFun3(): owned(Future[void])">asyncFun3(): owned(Future[void])
            z2
          • z2
          • + title="z2()">z2()
            bar
          • bar,T,T
          • + title="bar[T](a, b: T): T">bar[T](a, b: T): T
            fromUtils3
          • fromUtils3
          • + title="fromUtils3()">fromUtils3()
            isValid
          • isValid,T
          • + title="isValid[T](x: T): bool">isValid[T](x: T): bool
            z6
          • z6
          • + title="z6(): int">z6(): int + +
          +
            low
          • low,T
          • + title="low[T: Ordinal | enum | range](x: T): T">low[T: Ordinal | enum | range](x: T): T
            p1
          • p1
          • + title="p1()">p1()
            z11
          • z11
          • + title="z11()">z11()
            buzz
          • buzz,T,T
          • + title="buzz[T](a, b: T): T">buzz[T](a, b: T): T
            low2
          • low2,T
          • + title="low2[T: Ordinal | enum | range](x: T): T">low2[T: Ordinal | enum | range](x: T): T
            z7
          • z7
          • + title="z7(): int">z7(): int
            z13
          • z13
          • + title="z13()">z13()
            baz
          • baz,T,T
          • + title="baz[T](a, b: T): T">baz[T](a, b: T): T
          • baz
          • + title="baz()">baz()
            addfBug14485
          • addfBug14485
          • + title="addfBug14485()">addfBug14485()
            c_printf
          • c_printf,cstring
          • + title="c_printf(frmt: cstring): cint">c_printf(frmt: cstring): cint
            z12
          • z12
          • + title="z12(): int">z12(): int
            z3
          • z3
          • + title="z3()">z3()
            z9
          • z9
          • + title="z9()">z9()
            z4
          • z4
          • + title="z4()">z4()
            someFunc
          • someFunc
          • + title="someFunc()">someFunc()
            z8
          • z8
          • + title="z8(): int">z8(): int
            z1
          • z1
          • + title="z1(): Foo">z1(): Foo
            z5
          • z5
          • + title="z5(): int">z5(): int
            asyncFun2
          • asyncFun2
          • + title="asyncFun2(): owned(Future[void])">asyncFun2(): owned(Future[void])
            c_nonexistant
          • c_nonexistant,cstring
          • + title="c_nonexistant(frmt: cstring): cint">c_nonexistant(frmt: cstring): cint
            asyncFun1
          • asyncFun1
          • + title="asyncFun1(): Future[int]">asyncFun1(): Future[int]
          @@ -304,56 +309,104 @@ window.addEventListener('DOMContentLoaded', main);
        • Methods
        • Iterators
        • Macros
        • Templates
        • @@ -794,6 +847,13 @@ ok1

          Example:

          discard
          ok1 + + +
          proc anything() {...}{.raises: [], tags: [].}
          +
          + +There is no block quote after blank lines at the beginning. +
          diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx index 5714efac04..1d8be99dac 100644 --- a/nimdoc/testproject/expected/testproject.idx +++ b/nimdoc/testproject/expected/testproject.idx @@ -59,3 +59,4 @@ Circle testproject.html#Circle Shapes.Circle Triangle testproject.html#Triangle Shapes.Triangle Rectangle testproject.html#Rectangle Shapes.Rectangle Shapes testproject.html#Shapes testproject: Shapes +anything testproject.html#anything testproject: anything() diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index 978560e0f9..81370d115c 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -78,6 +78,10 @@ window.addEventListener('DOMContentLoaded', main);
        • utils: aEnum(): untyped
        +
        anything:
        asyncFun1:
        • testproject: asyncFun1(): Future[int]
        • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index eea399f82c..69edb0d235 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -375,3 +375,9 @@ when true: # issue #15702 Circle, ## A circle Triangle, ## A three-sided shape Rectangle ## A four-sided shape + +when true: # issue #15184 + proc anything* = + ## + ## There is no block quote after blank lines at the beginning. + discard diff --git a/nimpretty/tests/exhaustive.nim b/nimpretty/tests/exhaustive.nim index 2ba885d9ad..30cfc47a98 100644 --- a/nimpretty/tests/exhaustive.nim +++ b/nimpretty/tests/exhaustive.nim @@ -418,9 +418,9 @@ proc isValid1*[A](s: HashSet[A]): bool {.deprecated: result = s.data.len > 0 # bug #11468 -assert $type(a) == "Option[system.int]" -foo(a, $type(b), c) -foo(type(b), c) # this is ok +assert $typeof(a) == "Option[system.int]" +foo(a, $typeof(b), c) +foo(typeof(b), c) # this is ok proc `<`*[A](s, t: A): bool = discard proc `==`*[A](s, t: HashSet[A]): bool = discard @@ -843,3 +843,7 @@ 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 cfe9a43faf..82927a11cf 100644 --- a/nimpretty/tests/expected/exhaustive.nim +++ b/nimpretty/tests/expected/exhaustive.nim @@ -423,9 +423,9 @@ proc isValid1*[A](s: HashSet[A]): bool {.deprecated: result = s.data.len > 0 # bug #11468 -assert $type(a) == "Option[system.int]" -foo(a, $type(b), c) -foo(type(b), c) # this is ok +assert $typeof(a) == "Option[system.int]" +foo(a, $typeof(b), c) +foo(typeof(b), c) # this is ok proc `<`*[A](s, t: A): bool = discard proc `==`*[A](s, t: HashSet[A]): bool = discard @@ -856,3 +856,8 @@ 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/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 2e28a09eeb..c139b8b172 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -195,7 +195,7 @@ 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(conf, u) + listUsages(graph, u) else: localError(conf, conf.m.trackPos, "found no symbol at this position " & (conf $ conf.m.trackPos)) @@ -319,7 +319,7 @@ proc replTcp(x: ThreadParams) {.thread.} = else: server.bindAddr(x.port, x.address) server.listen() - var inp = "".TaintedString + var inp = "" var stdoutSocket: Socket while true: accept(server, stdoutSocket) diff --git a/nimsuggest/tester.nim b/nimsuggest/tester.nim index 019181810b..425430ede8 100644 --- a/nimsuggest/tester.nim +++ b/nimsuggest/tester.nim @@ -18,10 +18,12 @@ const template tpath(): untyped = getAppDir() / "tests" +import std/compilesettings + proc parseTest(filename: string; epcMode=false): Test = const cursorMarker = "#[!]#" let nimsug = curDir & addFileExt("nimsuggest", ExeExt) - let libpath = findExe("nim").splitFile().dir /../ "lib" + const libpath = querySetting(libPath) result.filename = filename result.dest = getTempDir() / extractFilename(filename) result.cmd = nimsug & " --tester " & result.dest @@ -329,7 +331,7 @@ proc main() = failures += runTest(xx) failures += runEpcTest(xx) else: - for x in walkFiles(getAppDir() / "tests/t*.nim"): + for x in walkFiles(tpath() / "t*.nim"): echo "Test ", x let xx = expandFilename x when not defined(windows): diff --git a/nimsuggest/tests/fixtures/mclass_macro.nim b/nimsuggest/tests/fixtures/mclass_macro.nim new file mode 100644 index 0000000000..cfca0bf3f3 --- /dev/null +++ b/nimsuggest/tests/fixtures/mclass_macro.nim @@ -0,0 +1,164 @@ + +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/dep_v1.nim b/nimsuggest/tests/fixtures/mdep_v1.nim similarity index 100% rename from nimsuggest/tests/dep_v1.nim rename to nimsuggest/tests/fixtures/mdep_v1.nim diff --git a/nimsuggest/tests/dep_v2.nim b/nimsuggest/tests/fixtures/mdep_v2.nim similarity index 100% rename from nimsuggest/tests/dep_v2.nim rename to nimsuggest/tests/fixtures/mdep_v2.nim diff --git a/nimsuggest/tests/fixtures/mfakeassert.nim b/nimsuggest/tests/fixtures/mfakeassert.nim new file mode 100644 index 0000000000..765831ba75 --- /dev/null +++ b/nimsuggest/tests/fixtures/mfakeassert.nim @@ -0,0 +1,5 @@ +# 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 new file mode 100644 index 0000000000..5fa9e51426 --- /dev/null +++ b/nimsuggest/tests/fixtures/minclude_import.nim @@ -0,0 +1,15 @@ +# 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 new file mode 100644 index 0000000000..23f9892cc0 --- /dev/null +++ b/nimsuggest/tests/fixtures/minclude_include.nim @@ -0,0 +1,4 @@ +# 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 new file mode 100644 index 0000000000..3e85ee5404 --- /dev/null +++ b/nimsuggest/tests/fixtures/minclude_types.nim @@ -0,0 +1,6 @@ +# 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 new file mode 100644 index 0000000000..d6f25571b3 --- /dev/null +++ b/nimsuggest/tests/fixtures/mstrutils.nim @@ -0,0 +1,19 @@ +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/tchk1.nim b/nimsuggest/tests/tchk1.nim index 2b60ed0945..c28b88b9b3 100644 --- a/nimsuggest/tests/tchk1.nim +++ b/nimsuggest/tests/tchk1.nim @@ -15,14 +15,13 @@ proc main = #[!]# discard """ -disabled:true $nimsuggest --tester $file >chk $1 -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;;;;Hint;;???;;0;;-1;;"tchk1 [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;;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;;"\'tchk1.main()[declared in tchk1.nim(14, 5)]\' is declared but not used [XDeclaredButNotUsed]";;0 +chk;;skUnknown;;;;Hint;;$file;;14;;5;;"\'main\' is declared but not used [XDeclaredButNotUsed]";;0 """ diff --git a/nimsuggest/tests/tcon1.nim b/nimsuggest/tests/tcon1.nim index 262dd51510..627e7f400f 100644 --- a/nimsuggest/tests/tcon1.nim +++ b/nimsuggest/tests/tcon1.nim @@ -1,13 +1,43 @@ +## 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;;1;;5;;"";;100 +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 $2 -con;;skProc;;tcon1.testB;;proc (a: string, b: string);;$file;;2;;5;;"";;100 +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 """ diff --git a/nimsuggest/tests/tdef2.nim b/nimsuggest/tests/tdef2.nim new file mode 100644 index 0000000000..299b83a3da --- /dev/null +++ b/nimsuggest/tests/tdef2.nim @@ -0,0 +1,13 @@ +# 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/tdot3.nim b/nimsuggest/tests/tdot3.nim index 15fc1cd1c1..30dd60591b 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 dep_v1.nim dep.nim +!copy fixtures/mdep_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 dep_v2.nim dep.nim +!copy fixtures/mdep_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 762534310f..e1ff96553a 100644 --- a/nimsuggest/tests/tdot4.nim +++ b/nimsuggest/tests/tdot4.nim @@ -1,17 +1,21 @@ -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 -""" +# Test that already used suggestions are prioritized -import strutils +from system import string, echo +import fixtures/mstrutils 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, locks: 0.};;*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/tinclude.nim b/nimsuggest/tests/tinclude.nim index 0fda43911c..b67440b9e3 100644 --- a/nimsuggest/tests/tinclude.nim +++ b/nimsuggest/tests/tinclude.nim @@ -1,8 +1,25 @@ +# 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 """ -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 +$nimsuggest --tester $file +>def $path/tinclude.nim:7:14 +def;;skProc;;minclude_import.create;;proc (greeting: string, subject: string): Greet{.noSideEffect, gcsafe, locks: 0.};;*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 """ + +# TODO test/fix if the first `def` is not first or repeated we get no results diff --git a/nimsuggest/tests/tstrutils.nim b/nimsuggest/tests/tstrutils.nim deleted file mode 100644 index 9462c3d99e..0000000000 --- a/nimsuggest/tests/tstrutils.nim +++ /dev/null @@ -1,10 +0,0 @@ -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 new file mode 100644 index 0000000000..97a225f168 --- /dev/null +++ b/nimsuggest/tests/tsug_enum.nim @@ -0,0 +1,18 @@ +## 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 1607f52448..2aff3fe94f 100644 --- a/nimsuggest/tests/tsug_regression.nim +++ b/nimsuggest/tests/tsug_regression.nim @@ -16,14 +16,19 @@ proc main = 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 $file +$nimsuggest --tester --maxresults:4 $file >sug $1 -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 -* +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 """ + +# 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 0f258fcc6f..15615f0afb 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, 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 +sug;;skMacro;;tsug_template.tmpb;;macro (){.noSideEffect, gcsafe, locks: 0.};;$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 """ diff --git a/nimsuggest/tests/tsug_typedecl.nim b/nimsuggest/tests/tsug_typedecl.nim new file mode 100644 index 0000000000..833043d31d --- /dev/null +++ b/nimsuggest/tests/tsug_typedecl.nim @@ -0,0 +1,26 @@ +# 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.nim;;*;;*;;*;;100;;Prefix +sug;;skType;;system.seq;;seq;;*lib/system.nim;;*;;*;;*;;100;;Prefix +""" \ No newline at end of file diff --git a/nimsuggest/tests/disabled_ttemplate_highlight.nim b/nimsuggest/tests/ttemplate_highlight.nim similarity index 100% rename from nimsuggest/tests/disabled_ttemplate_highlight.nim rename to nimsuggest/tests/ttemplate_highlight.nim diff --git a/nimsuggest/tests/ttype_decl.nim b/nimsuggest/tests/ttype_decl.nim index 6d9817ed2f..6022392d00 100644 --- a/nimsuggest/tests/ttype_decl.nim +++ b/nimsuggest/tests/ttype_decl.nim @@ -1,10 +1,9 @@ discard """ -disabled:true $nimsuggest --tester --maxresults:3 $file >sug $1 -sug;;skType;;ttype_decl.Other;;Other;;$file;;11;;2;;"";;0;;None -sug;;skType;;system.int;;int;;$lib/system/basic_types.nim;;2;;2;;"";;0;;None -sug;;skType;;system.string;;string;;$lib/system.nim;;34;;2;;"";;0;;None +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.nim;;34;;2;;"";;100;;None """ import strutils type diff --git a/nimsuggest/tests/tuse.nim b/nimsuggest/tests/tuse.nim new file mode 100644 index 0000000000..89a9c151a9 --- /dev/null +++ b/nimsuggest/tests/tuse.nim @@ -0,0 +1,22 @@ +# 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, locks: 0.};;$file;;9;;5;;"";;100 +use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0.};;$file;;12;;0;;"";;100 +>use $2 +def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"";;100 +use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0.};;$file;;12;;0;;"";;100 +""" diff --git a/nimsuggest/tests/twithin_macro.nim b/nimsuggest/tests/twithin_macro.nim index 9c36ffd0f1..d79dae1be0 100644 --- a/nimsuggest/tests/twithin_macro.nim +++ b/nimsuggest/tests/twithin_macro.nim @@ -1,166 +1,5 @@ - -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) - -# --- +from system import string, int, seq, `&`, `$`, `*`, `@`, echo, add, items, RootObj +import fixtures/mclass_macro class Animal of RootObj: var name: string @@ -202,13 +41,11 @@ echo r.age_human_yrs() echo r discard """ -disabled:true -$nimsuggest --tester $file +$nimsuggest --tester --maxresults:5 $file >sug $1 -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* +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 """ diff --git a/nimsuggest/tests/twithin_macro_prefix.nim b/nimsuggest/tests/twithin_macro_prefix.nim index 1402b762ae..dd38108183 100644 --- a/nimsuggest/tests/twithin_macro_prefix.nim +++ b/nimsuggest/tests/twithin_macro_prefix.nim @@ -1,166 +1,5 @@ - -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) - -# --- +from system import string, int, seq, `&`, `$`, `*`, `@`, echo, add, RootObj +import fixtures/mclass_macro class Animal of RootObj: var name: string @@ -202,9 +41,8 @@ echo r.age_human_yrs() echo r discard """ -disabled:true $nimsuggest --tester $file >sug $1 -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 +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 """ diff --git a/readme.md b/readme.md index bfd153143b..fa7a2d86d5 100644 --- a/readme.md +++ b/readme.md @@ -204,7 +204,7 @@ Nim. You are explicitly permitted to develop commercial applications using Nim. Please read the [copying.txt](copying.txt) file for more details. -Copyright © 2006-2020 Andreas Rumpf, all rights reserved. +Copyright © 2006-2021 Andreas Rumpf, all rights reserved. [nim-site]: https://nim-lang.org [nim-forum]: https://forum.nim-lang.org diff --git a/testament/backend.nim b/testament/backend.nim index 0a6d7d8b92..1770c66573 100644 --- a/testament/backend.nim +++ b/testament/backend.nim @@ -13,7 +13,6 @@ type CommitId = distinct string proc `$`*(id: MachineId): string {.borrow.} -#proc `$`(id: CommitId): string {.borrow.} # not used var thisMachine: MachineId @@ -21,10 +20,10 @@ var thisBranch: string proc getMachine*(): MachineId = - var name = execProcess("hostname").string.strip + var name = execProcess("hostname").strip if name.len == 0: - name = when defined(posix): getEnv("HOSTNAME").string - else: getEnv("COMPUTERNAME").string + name = when defined(posix): getEnv("HOSTNAME") + else: getEnv("COMPUTERNAME") if name.len == 0: quit "cannot determine the machine name" @@ -32,8 +31,8 @@ proc getMachine*(): MachineId = proc getCommit(): CommitId = const commLen = "commit ".len - let hash = execProcess("git log -n 1").string.strip[commLen..commLen+10] - thisBranch = execProcess("git symbolic-ref --short HEAD").string.strip + let hash = execProcess("git log -n 1").strip[commLen..commLen+10] + thisBranch = execProcess("git symbolic-ref --short HEAD").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 30383bddb6..01e402e07a 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 = TaintedString("") + var line = "" 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 = TaintedString("") + line = "" 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 = TaintedString("") + var project = "" if f.readLine(project): var s = startNimSession(script.parentDir / project.string, script, mode) - tline = TaintedString("") + tline = "" ln = 1 while f.readLine(tline): @@ -175,7 +175,7 @@ when isMainModule: verbose = false for i in 0..paramCount() - 1: - let param = string(paramStr(i + 1)) + let param = paramStr(i + 1) case param of "verbose": verbose = true else: filter = param diff --git a/testament/categories.nim b/testament/categories.nim index c894bc9f99..acb3ee0a87 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -13,6 +13,7 @@ # included from testament.nim import important_packages +import std/strformat const specialCategories = [ @@ -29,11 +30,10 @@ const "lib", "longgc", "manyloc", - "nimble-packages-1", - "nimble-packages-2", + "nimble-packages", "niminaction", "threads", - "untestable", + "untestable", # see trunner_special "testdata", "nimcache", "coroutines", @@ -47,49 +47,6 @@ 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) = @@ -132,11 +89,11 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) = 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).string + var libpath = getEnv(libpathenv) # Temporarily add the lib directory to LD_LIBRARY_PATH: putEnv(libpathenv, "tests/dll" & (if libpath.len > 0: ":" & libpath else: "")) defer: putEnv(libpathenv, libpath) @@ -216,6 +173,7 @@ proc gcTests(r: var TResults, cat: Category, options: string) = test "stackrefleak" test "cyclecollector" + test "trace_globals" proc longGCTests(r: var TResults, cat: Category, options: string) = when defined(windows): @@ -264,7 +222,7 @@ proc debuggerTests(r: var TResults, cat: Category, options: string) = 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 } + t.spec.targets = {targetC} testSpec r, t # ------------------------- JS tests ------------------------------------------ @@ -291,8 +249,6 @@ 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) @@ -383,7 +339,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[.. ^(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 @@ -428,7 +384,7 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) = files.sort # reproducible order for testFile in files: - let contents = readFile(testFile).string + let contents = readFile(testFile) var testObj = makeTest(testFile, options, cat) #[ todo: @@ -443,111 +399,69 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) = testSpec r, testObj # ----------------------------- nimble ---------------------------------------- - -var nimbleDir = getEnv("NIMBLE_DIR").string -if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble" -let - nimbleExe = findExe("nimble") - packageIndex = nimbleDir / "packages_official.json" - -type - PkgPart = enum - ppOne - ppTwo - -iterator listPackages(part: PkgPart): tuple[name, cmd, url: string, useHead: bool] = +proc listPackages(packageFilter: string): seq[NimblePackage] = + # xxx document `packageFilter`, seems like a bad API (at least should be a regex; a substring match makes no sense) + var nimbleDir = getEnv("NIMBLE_DIR") + if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble" + let packageIndex = nimbleDir / "packages_official.json" let packageList = parseFile(packageIndex) - let importantList = - case part - of ppOne: important_packages.packages1 - of ppTwo: important_packages.packages2 - for n, cmd, url, useHead in importantList.items: - if url.len != 0: - yield (n, cmd, url, useHead) - else: - var found = false - for package in packageList.items: - let name = package["name"].str - if name == n: - found = true - let pUrl = package["url"].str - yield (name, cmd, pUrl, useHead) - break - if not found: - raise newException(ValueError, "Cannot find package '$#'." % n) + proc findPackage(name: string): JsonNode = + for a in packageList: + if a["name"].str == name: return a + for pkg in important_packages.packages.items: + if isCurrentBatch(testamentData0, pkg.name) and packageFilter in pkg.name: + 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 makeSupTest(test, options: string, cat: Category): TTest = +proc makeSupTest(test, options: string, cat: Category, debugInfo = ""): TTest = result.cat = cat result.name = test result.options = options + result.debugInfo = debugInfo result.startTime = epochTime() -const maxRetries = 3 -template retryCommand(call): untyped = - var res: typeof(call) - var backoff = 1 - for i in 0.. 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: @@ -52,8 +51,18 @@ Options: 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 @@ -66,6 +75,7 @@ type args: seq[string] spec: TSpec startTime: float + debugInfo: string # ---------------------------------------------------------------------------- @@ -86,14 +96,13 @@ 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: `--listFullPaths`). + # 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(): @@ -101,7 +110,7 @@ proc getFileDir(filename: string): string = proc execCmdEx2(command: string, args: openArray[string]; workingDir, input: string = ""): tuple[ cmdLine: string, - output: TaintedString, + output: string, exitCode: int] {.tags: [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} = @@ -109,8 +118,8 @@ proc execCmdEx2(command: string, args: openArray[string]; workingDir, input: str for arg in args: result.cmdLine.add ' ' result.cmdLine.add quoteShell(arg) - 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 @@ -120,12 +129,12 @@ proc execCmdEx2(command: string, args: openArray[string]; workingDir, input: str instream.write(input) close instream - result.exitCode = -1 - var line = newStringOfCap(120).TaintedString + result.exitCode = -1 + var line = newStringOfCap(120) while true: if outp.readLine(line): - result.output.string.add(line.string) - result.output.string.add("\n") + result.output.add line + result.output.add '\n' else: result.exitCode = peekExitCode(p) if result.exitCode != -1: break @@ -138,10 +147,10 @@ proc nimcacheDir(filename, options: string, target: TTarget): string = proc prepareTestArgs(cmdTemplate, filename, options, nimcache: string, target: TTarget, extraOptions = ""): seq[string] = - var options = target.defaultOptions & " " & options + var options = target.defaultOptions & ' ' & options # improve pending https://github.com/nim-lang/Nim/issues/14343 - if nimcache.len > 0: options.add " " & ("--nimCache:" & nimcache).quoteShell - options.add " " & extraOptions + if nimcache.len > 0: options.add ' ' & ("--nimCache:" & nimcache).quoteShell + options.add ' ' & extraOptions result = parseCmdLine(cmdTemplate % ["target", targetToCmd[target], "options", options, "file", filename.quoteShell, "filedir", filename.getFileDir(), "nim", compilerPrefix]) @@ -151,8 +160,8 @@ proc callCompiler(cmdTemplate, filename, options, nimcache: string, let c = prepareTestArgs(cmdTemplate, filename, options, nimcache, target, extraOptions) result.cmd = quoteShellCommand(c) - var p = startProcess(command=c[0], args=c[1 .. ^1], - options={poStdErrToStdOut, poUsePath}) + var p = startProcess(command = c[0], args = c[1 .. ^1], + options = {poStdErrToStdOut, poUsePath}) let outp = p.outputStream var suc = "" var err = "" @@ -160,8 +169,8 @@ proc callCompiler(cmdTemplate, filename, options, nimcache: string, var x = newStringOfCap(120) result.nimout = "" while true: - if outp.readLine(x.TaintedString): - result.nimout.add(x & "\n") + if outp.readLine(x): + result.nimout.add(x & '\n') if x =~ pegOfInterest: # `err` should contain the last error/warning message err = x @@ -199,8 +208,8 @@ proc callCompiler(cmdTemplate, filename, options, nimcache: string, proc callCCompiler(cmdTemplate, filename, options: string, target: TTarget): TSpec = let c = prepareTestArgs(cmdTemplate, filename, options, nimcache = "", target) - var p = startProcess(command="gcc", args=c[5 .. ^1], - options={poStdErrToStdOut, poUsePath}) + var p = startProcess(command = "gcc", args = c[5 .. ^1], + options = {poStdErrToStdOut, poUsePath}) let outp = p.outputStream var x = newStringOfCap(120) result.nimout = "" @@ -209,8 +218,8 @@ proc callCCompiler(cmdTemplate, filename, options: string, result.output = "" result.line = -1 while true: - if outp.readLine(x.TaintedString): - result.nimout.add(x & "\n") + if outp.readLine(x): + result.nimout.add(x & '\n') elif not running(p): break close(p) @@ -223,8 +232,6 @@ proc initResults: TResults = result.skipped = 0 result.data = "" -import macros - macro ignoreStyleEcho(args: varargs[typed]): untyped = let typForegroundColor = bindSym"ForegroundColor".getType let typBackgroundColor = bindSym"BackgroundColor".getType @@ -258,8 +265,8 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, # test.name is easier to find than test.name.extractFilename # A bit hacky but simple and works with tests/testament/tshould_not_work.nim var name = test.name.replace(DirSep, '/') - name.add " " & $target - if test.options.len > 0: name.add " " & test.options + name.add ' ' & $target + if test.options.len > 0: name.add ' ' & test.options let duration = epochTime() - test.startTime let success = if test.spec.timeout > 0.0 and duration > test.spec.timeout: reTimeout @@ -276,9 +283,9 @@ proc addResult(r: var TResults, test: TTest, target: TTarget, given = given) r.data.addf("$#\t$#\t$#\t$#", name, expected, given, $success) template disp(msg) = - maybeStyledEcho styleDim, fgYellow, msg & " ", styleBright, fgCyan, name + maybeStyledEcho styleDim, fgYellow, msg & ' ', styleBright, fgCyan, name if success == reSuccess: - maybeStyledEcho fgGreen, "PASS: ", fgCyan, alignLeft(name, 60), fgBlue, " (", durationStr, " sec)" + maybeStyledEcho fgGreen, "PASS: ", fgCyan, test.debugInfo, alignLeft(name, 60), fgBlue, " (", durationStr, " sec)" elif success == reDisabled: if test.spec.inCurrentBatch: disp("SKIP:") else: disp("NOTINBATCH:") @@ -305,18 +312,18 @@ 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) @@ -344,7 +351,7 @@ proc checkForInlineErrors(r: var TResults, expected, given: TSpec, test: TTest, for j in 0..high(expected.inlineErrors): if j notin covered: var e = test.name - e.add "(" + e.add '(' e.addInt expected.inlineErrors[j].line if expected.inlineErrors[j].col > 0: e.add ", " @@ -402,7 +409,7 @@ proc codegenCheck(test: TTest, target: TTarget, spec: TSpec, expectedMsg: var st given: var TSpec) = try: let genFile = generatedFile(test, target) - let contents = readFile(genFile).string + let contents = readFile(genFile) for check in spec.ccodeCheck: if check.len > 0 and check[0] == '\\': # little hack to get 'match' support: @@ -439,12 +446,12 @@ proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec, 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, expectedmsg, givenmsg, given.err) proc getTestSpecTarget(): TTarget = - if getEnv("NIM_COMPILE_TO_CPP", "false").string == "true": + if getEnv("NIM_COMPILE_TO_CPP", "false") == "true": result = targetCpp else: result = targetC @@ -477,7 +484,7 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, var given = callCompiler(expected.getCmd, test.name, test.options, nimcache, target, extraOptions) if given.err != reSuccess: - r.addResult(test, target, "", "$ " & given.cmd & "\n" & given.nimout, given.err) + 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) @@ -494,7 +501,8 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, var args = test.args if isJsTarget: exeCmd = nodejs - args = concat(@[exeFile], args) + # see D20210217T215950 + args = @["--unhandled-rejections=strict", exeFile] & args else: exeCmd = exeFile.dup(normalizeExe) if expected.useValgrind != disabled: @@ -503,19 +511,20 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec, valgrindOptions.add "--leak-check=yes" args = valgrindOptions & exeCmd & args exeCmd = "valgrind" + # xxx honor `testament --verbose` here var (_, buf, exitCode) = execCmdEx2(exeCmd, args, input = expected.input) # Treat all failure codes from nodejs as 1. Older versions of nodejs used # to return other codes, but for us it is sufficient to know that it's not 0. if exitCode != 0: exitCode = 1 let bufB = if expected.sortoutput: - var buf2 = buf.string + var buf2 = buf buf2.stripLineEnd var x = splitLines(buf2) sort(x, system.cmp) - join(x, "\n") & "\n" + join(x, "\n") & '\n' else: - buf.string + buf if exitCode != expected.exitCode: r.addResult(test, target, "exitcode: " & $expected.exitCode, "exitcode: " & $exitCode & "\n\nOutput:\n" & @@ -564,7 +573,7 @@ proc testSpec(r: var TResults, test: TTest, targets: set[TTarget] = {}) = else: targetHelper(r, test, expected) -proc testSpecWithNimcache(r: var TResults, test: TTest; nimcache: string) = +proc testSpecWithNimcache(r: var TResults, test: TTest; nimcache: string) {.used.} = if not checkDisabled(r, test): return for target in test.spec.targets: inc(r.total) @@ -598,7 +607,7 @@ proc testExec(r: var TResults, test: TTest) = given.err = reSuccess else: given.err = reExitcodesDiffer - given.msg = outp.string + given.msg = outp if given.err == reSuccess: inc(r.passed) r.addResult(test, targetC, "", given.msg, given.err) @@ -610,7 +619,7 @@ 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 = +proc makeRawTest(test, options: string, cat: Category): TTest {.used.} = result.cat = cat result.name = test result.options = options @@ -657,7 +666,7 @@ 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() = @@ -673,20 +682,20 @@ proc main() = var p = initOptParser() p.next() while p.kind in {cmdLongOption, cmdShortOption}: - case p.key.string.normalize + case p.key.normalize of "print", "verbose": optPrintResults = true of "failing": optFailing = true - of "pedantic": discard "now always enabled" + of "pedantic": discard # deadcode refs https://github.com/nim-lang/Nim/issues/16731 of "targets": - targetsStr = p.val.string + targetsStr = p.val gTargets = parseTargets(targetsStr) targetsSet = true of "nim": - compilerPrefix = addFileExt(p.val.string.absolutePath, ExeExt) + compilerPrefix = addFileExt(p.val.absolutePath, ExeExt) of "directory": - setCurrentDir(p.val.string) + setCurrentDir(p.val) of "colors": - case p.val.string: + case p.val: of "on": useColors = true of "off": @@ -705,7 +714,7 @@ proc main() = of "simulate": simulate = true of "megatest": - case p.val.string: + case p.val: of "on": useMegatest = true of "off": @@ -713,7 +722,7 @@ proc main() = else: quit Usage of "backendlogging": - case p.val.string: + case p.val: of "on": backendLogging = true of "off": @@ -721,18 +730,18 @@ proc main() = else: quit Usage of "skipfrom": - skipFrom = p.val.string + skipFrom = p.val else: quit Usage p.next() if p.kind != cmdArgument: quit Usage - var action = p.key.string.normalize + var action = p.key.normalize p.next() var r = initResults() case action of "all": - #processCategory(r, Category"megatest", p.cmdLineRest.string, testsDir, runJoinableTests = false) + #processCategory(r, Category"megatest", p.cmdLineRest, testsDir, runJoinableTests = false) var myself = quoteShell(getAppFilename()) if targetsStr.len > 0: @@ -746,13 +755,14 @@ proc main() = myself &= " " & quoteShell("--skipFrom:" & skipFrom) var cats: seq[string] - let rest = if p.cmdLineRest.string.len > 0: " " & p.cmdLineRest.string else: "" + let rest = if p.cmdLineRest.len > 0: " " & p.cmdLineRest 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 - cats.add AdditionalCategories + if isNimRepoTests(): + cats.add AdditionalCategories if useMegatest: cats.add MegaTestCat var cmds: seq[string] @@ -767,14 +777,14 @@ proc main() = skips = loadSkipFrom(skipFrom) for i, cati in cats: progressStatus(i) - processCategory(r, Category(cati), p.cmdLineRest.string, testsDir, runJoinableTests = false) + processCategory(r, Category(cati), p.cmdLineRest, testsDir, runJoinableTests = false) else: - addQuitProc azure.finalize + addExitProc 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.string, testsDir, runJoinableTests = true) + processCategory(r, cat, p.cmdLineRest, testsDir, runJoinableTests = true) of "pcat": skips = loadSkipFrom(skipFrom) # 'pcat' is used for running a category in parallel. Currently the only @@ -783,23 +793,15 @@ proc main() = isMainProcess = false var cat = Category(p.key) p.next - processCategory(r, cat, p.cmdLineRest.string, testsDir, runJoinableTests = false) + processCategory(r, cat, p.cmdLineRest, testsDir, runJoinableTests = false) of "p", "pat", "pattern": skips = loadSkipFrom(skipFrom) let pattern = p.key p.next - processPattern(r, pattern, p.cmdLineRest.string, simulate) + processPattern(r, pattern, p.cmdLineRest, simulate) of "r", "run": - # "/pathto/tests/stdlib/nre/captures.nim" -> "stdlib" + "tests/stdlib/nre/captures.nim" - var subPath = p.key.string - let nimRoot = currentSourcePath / "../.." - # makes sure points to this regardless of cwd or which nim is used to compile this. - doAssert existsDir(nimRoot/testsDir) # sanity check - if subPath.isAbsolute: subPath = subPath.relativePath(nimRoot) - # at least one directory is required in the path, to use as a category name - let pathParts = subPath.relativePath(testsDir).split({DirSep, AltSep}) - let cat = Category(pathParts[0]) - processSingleTest(r, cat, p.cmdLineRest.string, subPath, gTargets, targetsSet) + let (cat, path) = splitTestFile(p.key) + processSingleTest(r, cat.Category, p.cmdLineRest, path, gTargets, targetsSet) of "html": generateHtml(resultsFile, optFailing) else: diff --git a/testament/testament.nim.cfg b/testament/testament.nim.cfg index f1fcd95f3b..c97284129e 100644 --- a/testament/testament.nim.cfg +++ b/testament/testament.nim.cfg @@ -1,3 +1,5 @@ +# 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: diff --git a/testament/tests/shouldfail/tmsg.nim b/testament/tests/shouldfail/tmsg.nim deleted file mode 100644 index 4ad17fa951..0000000000 --- a/testament/tests/shouldfail/tmsg.nim +++ /dev/null @@ -1,6 +0,0 @@ -discard """ -msg: "Hello World" -""" - -static: - echo "something else" diff --git a/tests/arc/t14383.nim b/tests/arc/t14383.nim index 85f90d1c8e..96b5051669 100644 --- a/tests/arc/t14383.nim +++ b/tests/arc/t14383.nim @@ -125,4 +125,93 @@ proc main = let rankdef = avals echo avals.len, " ", rankdef.len -main() \ No newline at end of file +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/t17025.nim b/tests/arc/t17025.nim new file mode 100644 index 0000000000..a64c59ac1e --- /dev/null +++ b/tests/arc/t17025.nim @@ -0,0 +1,56 @@ +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 new file mode 100644 index 0000000000..0acd886a24 --- /dev/null +++ b/tests/arc/t17173.nim @@ -0,0 +1,10 @@ +discard """ + matrix: "--gc:refc; --gc:arc" +""" + +import std/strbasics + + +var a = " vhellov " +strip(a) +doAssert a == "vhellov" diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 8d857921ef..55803085f2 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -135,8 +135,8 @@ let n = @["c", "b"] q = @[("c", "2"), ("b", "1")] -assert n.sortedByIt(it) == @["b", "c"], "fine" -assert q.sortedByIt(it[0]) == @[("b", "1"), ("c", "2")], "fails under arc" +doAssert n.sortedByIt(it) == @["b", "c"], "fine" +doAssert q.sortedByIt(it[0]) == @[("b", "1"), ("c", "2")], "fails under arc" #------------------------------------------------------------------------------ diff --git a/tests/arc/tasyncawait.nim b/tests/arc/tasyncawait.nim index f29b8d2b2d..75d9bc9b58 100644 --- a/tests/arc/tasyncawait.nim +++ b/tests/arc/tasyncawait.nim @@ -62,7 +62,7 @@ proc main = let mem = getOccupiedMem() main() -assert msgCount == swarmSize * messagesToSend +doAssert msgCount == swarmSize * messagesToSend echo "result: ", msgCount GC_fullCollect() echo "memory: ", formatSize(getOccupiedMem() - mem) diff --git a/tests/arc/tasyncleak2.nim b/tests/arc/tasyncleak2.nim index 4d8486b3b4..87d7e73f9d 100644 --- a/tests/arc/tasyncleak2.nim +++ b/tests/arc/tasyncleak2.nim @@ -57,7 +57,7 @@ proc main(): Future[void] = template await[T](f_gensym12: Future[T]): auto {.used.} = var internalTmpFuture_gensym12: FutureBase = f_gensym12 yield internalTmpFuture_gensym12 - (cast[type(f_gensym12)](internalTmpFuture_gensym12)).read() + (cast[typeof(f_gensym12)](internalTmpFuture_gensym12)).read() var retFuture = newFuture[void]("main") iterator mainIter(): FutureBase {.closure.} = @@ -84,5 +84,5 @@ proc main(): Future[void] = for i in 0..9: waitFor main() GC_fullCollect() - assert getOccupiedMem() < 1024 + doAssert getOccupiedMem() < 1024 echo "success" diff --git a/tests/arc/tcomputedgoto.nim b/tests/arc/tcomputedgoto.nim index 8af17b56ea..541a748c62 100644 --- a/tests/arc/tcomputedgoto.nim +++ b/tests/arc/tcomputedgoto.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --newruntime $file''' + cmd: '''nim c --gc:arc $file''' output: '''2 2''' """ diff --git a/tests/arc/tcomputedgotocopy.nim b/tests/arc/tcomputedgotocopy.nim index 78cb6c5c00..8337123ba0 100644 --- a/tests/arc/tcomputedgotocopy.nim +++ b/tests/arc/tcomputedgotocopy.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --newruntime $file''' + cmd: '''nim c --gc:arc $file''' output: '''2 2''' """ diff --git a/tests/arc/tcstring.nim b/tests/arc/tcstring.nim deleted file mode 100644 index 79c8a7fcf0..0000000000 --- a/tests/arc/tcstring.nim +++ /dev/null @@ -1,16 +0,0 @@ -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_on_localvar.nim b/tests/arc/tcursor_on_localvar.nim index 81b48271fe..0f53c5efa5 100644 --- a/tests/arc/tcursor_on_localvar.nim +++ b/tests/arc/tcursor_on_localvar.nim @@ -4,7 +4,10 @@ discard """ Section: local Param: Str Param: Bool - Param: Floats2''' + Param: Floats2 +destroy Foo +destroy Foo +''' cmd: '''nim c --gc:arc $file''' """ @@ -123,4 +126,36 @@ when isMainModule: 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/tmovebug.nim b/tests/arc/tmovebug.nim index 61105b44e9..888027186b 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -73,6 +73,40 @@ 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 +destroy +copy +(f: 1) +destroy +destroy +part-to-whole assigment: +sink +(children: @[]) +destroy +sink +(children: @[]) +destroy +copy +destroy ''' """ @@ -556,4 +590,183 @@ let w2 = newWrapper2(1) echo $w2[] let w3 = newWrapper2(-1) -echo $w3[] \ No newline at end of file +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() # <- when firstWrite tries to find this node to start its analysis it fails, because injectdestructors uses copyTree/shallowCopy + result.b = initC() + +discard pair() + diff --git a/tests/arc/topt_cursor.nim b/tests/arc/topt_cursor.nim index a8020e72b8..5c35b454fb 100644 --- a/tests/arc/topt_cursor.nim +++ b/tests/arc/topt_cursor.nim @@ -4,21 +4,18 @@ discard """ nimout: '''--expandArc: main var + x_cursor :tmpD - :tmpD_1 - :tmpD_2 try: - var x_cursor = ("hi", 5) - x_cursor = if cond: - :tmpD = ("different", 54) - :tmpD else: - :tmpD_1 = ("string here", 80) - :tmpD_1 + x_cursor = ("hi", 5) + if cond: + x_cursor = ("different", 54) else: + x_cursor = ("string here", 80) echo [ - :tmpD_2 = `$`(x_cursor) - :tmpD_2] + :tmpD = `$`(x_cursor) + :tmpD] finally: - `=destroy`(:tmpD_2) + `=destroy`(:tmpD) -- end of expandArc ------------------------ --expandArc: sio @@ -28,7 +25,7 @@ block :tmp: try: var res try: - res = TaintedString(newStringOfCap(80)) + res = newStringOfCap(80) block :tmp_1: while readLine(f, res): x_cursor = res diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index 3d37e6269d..f1eb8575a5 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -3,8 +3,12 @@ discard """ doing shady stuff... 3 6 -(@[1], @[2])''' - cmd: '''nim c --gc:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off $file''' +(@[1], @[2]) +192.168.0.1 +192.168.0.1 +192.168.0.1 +192.168.0.1''' + cmd: '''nim c --gc:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off --assertions:off --expandArc:extractConfig $file''' nimout: '''--expandArc: newTarget var @@ -52,19 +56,20 @@ _ = ( blitTmp, ";") lvalue = _[0] lnext = _[1] -`=sink`(result.value, move lvalue) +result.value = move lvalue `=destroy`(lnext) `=destroy_1`(lvalue) -- end of expandArc ------------------------ --expandArc: tt var + it_cursor a :tmpD :tmpD_1 :tmpD_2 try: - var it_cursor = x + it_cursor = x a = ( wasMoved(:tmpD) `=copy`(:tmpD, it_cursor.key) @@ -78,6 +83,31 @@ try: 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 ------------------------''' """ @@ -194,3 +224,56 @@ proc plus(input: string) = (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() diff --git a/tests/arc/topt_refcursors.nim b/tests/arc/topt_refcursors.nim index 372fc18bf6..f097150a34 100644 --- a/tests/arc/topt_refcursors.nim +++ b/tests/arc/topt_refcursors.nim @@ -3,17 +3,21 @@ discard """ cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file''' nimout: '''--expandArc: traverse -var it_cursor = root +var + it_cursor + jt_cursor +it_cursor = root block :tmp: while ( not (it_cursor == nil)): echo [it_cursor.s] it_cursor = it_cursor.ri -var jt_cursor = root +jt_cursor = root block :tmp_1: while ( not (jt_cursor == nil)): - let ri_1_cursor = jt_cursor.ri + var ri_1_cursor + ri_1_cursor = jt_cursor.ri echo [jt_cursor.s] jt_cursor = ri_1_cursor -- end of expandArc ------------------------''' diff --git a/tests/arc/torcmisc.nim b/tests/arc/torcmisc.nim new file mode 100644 index 0000000000..20dd18fb31 --- /dev/null +++ b/tests/arc/torcmisc.nim @@ -0,0 +1,34 @@ +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" + diff --git a/tests/arc/trepr.nim b/tests/arc/trepr.nim index 3c1e4129c3..50d433208b 100644 --- a/tests/arc/trepr.nim +++ b/tests/arc/trepr.nim @@ -71,3 +71,19 @@ proc p2 = 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() diff --git a/tests/arc/trtree.nim b/tests/arc/trtree.nim index 5659a5bdcf..683403a626 100644 --- a/tests/arc/trtree.nim +++ b/tests/arc/trtree.nim @@ -71,8 +71,8 @@ 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, type(r[0].a)] = - var res: BoxCenter[r.len, type(r[0].a)] +proc center(r: Box): auto =#BoxCenter[r.len, typeof(r[0].a)] = + var res: BoxCenter[r.len, typeof(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 @@ -82,13 +82,13 @@ proc center(r: Box): auto =#BoxCenter[r.len, type(r[0].a)] = return res proc distance(c1, c2: BoxCenter): auto = - var res: type(c1[0]) + var res: typeof(c1[0]) for i in 0 .. c1.high: res += (c1[i] - c2[i]) * (c1[i] - c2[i]) return res proc overlap(r1, r2: Box): auto = - result = type(r1[0].a)(1) + result = typeof(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 = #type(r[0].a) = - result = type(r[0].a)(1) +proc area(r: Box): auto = #typeof(r[0].a) = + result = typeof(r[0].a)(1) for i in 0 .. r.high: result *= r[i].b - r[i].a -proc margin(r: Box): auto = #type(r[0].a) = - result = type(r[0].a)(0) +proc margin(r: Box): auto = #typeof(r[0].a) = + result = typeof(r[0].a)(0) for i in 0 .. r.high: result += r[i].b - r[i].a @@ -142,7 +142,7 @@ proc chooseSubtree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]; lev while it.level > level: let nn = Node[M, D, RT, LT](it) var i0 = 0 # selected index - var minLoss = type(b[0].a).high + 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: let nx = union(nn.a[i].b, b) @@ -179,8 +179,8 @@ proc chooseSubtree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]; lev 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: type(bx) - var largestWaste = type(bx[0].a).low + var bi, bj: typeof(bx) + var largestWaste = typeof(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 +200,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 = type(a1).low + var d = typeof(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 +220,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]): type(n) = - type NL = type(lx) - var nBest: type(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]): typeof(n) = + type NL = typeof(lx) + var nBest: typeof(n) new nBest var lx = lx when n is Node[M, D, RT, LT]: lx.n.parent = n - var lxbest: type(lx) - var m0 = lx.b[0].a.high + var lxbest: typeof(lx) + var m0 = lx.b[0].a.typeof.high for d2 in 0 ..< 2 * D: let d = d2 div 2 if d2 mod 2 == 0: @@ -251,8 +251,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.high - for i in t.m - 1 .. n.a.high - t.m + 1: + var o0 = lx.b[0].a.typeof.high + for i in t.m - 1 .. n.a.typeof.high - t.m + 1: var b1 = lxbest.b for j in 0 ..< i: b1 = union(nbest.a[j].b, b1) @@ -277,8 +277,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]): type(n) = - var n1, n2: type(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]): typeof(n) = + var n1, n2: typeof(n) var s1, s2: int new n1 new n2 @@ -341,7 +341,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]): type(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]): typeof(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 +361,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: type(p.a[0].b) + var b: typeof(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) @@ -427,9 +427,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 = type(lx) + type NL = typeof(lx) var lx = lx - var buf: type(n.a) + var buf: typeof(n.a) let p = Node[M, D, RT, LT](n.parent) var i = 0 while p.a[i].n != n: @@ -449,7 +449,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]): type(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]): typeof(n) = if n.level != t.root.level and t.firstOverflow[n.level]: t.firstOverflow[n.level] = false reInsert(t, n, lx) diff --git a/tests/arithm/tarithm.nim b/tests/arithm/tarithm.nim index 99306b3e84..d0943d225d 100644 --- a/tests/arithm/tarithm.nim +++ b/tests/arithm/tarithm.nim @@ -22,10 +22,10 @@ import typetraits block tand: # bug #5216 - echo(name type((0x0A'i8 and 0x7F'i32) shl 7'i32)) + echo(name typeof((0x0A'i8 and 0x7F'i32) shl 7'i32)) let i8 = 0x0A'i8 - echo(name type((i8 and 0x7F'i32) shl 7'i32)) + echo(name typeof((i8 and 0x7F'i32) shl 7'i32)) echo((0x0A'i8 and 0x7F'i32) shl 7'i32) diff --git a/tests/arithm/tdiv.nim b/tests/arithm/tdiv.nim new file mode 100644 index 0000000000..5d8eed84dc --- /dev/null +++ b/tests/arithm/tdiv.nim @@ -0,0 +1,19 @@ +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/t9932.nim b/tests/array/t9932.nim index 1e09c487b9..e3c8abba37 100644 --- a/tests/array/t9932.nim +++ b/tests/array/t9932.nim @@ -1,9 +1,9 @@ discard """ cmd: "nim check $file" -errormsg: "invalid type: 'type int' in this context: 'array[0..0, type int]' for var" +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: 'type int' in this context: 'array[0..0, type int]' for var +t9932.nim(11, 5) Error: invalid type: 'typedesc[int]' in this context: 'array[0..0, typedesc[int]]' for var ''' """ diff --git a/tests/array/tarray.nim b/tests/array/tarray.nim index eadb53ac19..81a43f203e 100644 --- a/tests/array/tarray.nim +++ b/tests/array/tarray.nim @@ -344,11 +344,11 @@ block troofregression: if $a != b: echo "Failure ", a, " != ", b - 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]" + 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]" var rot = 8 diff --git a/tests/assert/tassert_c.nim b/tests/assert/tassert_c.nim index c6a2eadb19..5c8f529adf 100644 --- a/tests/assert/tassert_c.nim +++ b/tests/assert/tassert_c.nim @@ -6,9 +6,9 @@ discard """ const expected = """ tassert_c.nim(35) tassert_c tassert_c.nim(34) foo -assertions.nim(30) failedAssertImpl -assertions.nim(23) raiseAssert -fatal.nim(49) sysFatal""" +assertions.nim(*) failedAssertImpl +assertions.nim(*) raiseAssert +fatal.nim(*) sysFatal""" proc tmatch(x, p: string): bool = var i = 0 diff --git a/tests/assign/tassign.nim b/tests/assign/tassign.nim index 0589b02148..da097ca83f 100644 --- a/tests/assign/tassign.nim +++ b/tests/assign/tassign.nim @@ -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)) - assert(tup[0] == "example") + doAssert(tup[0] == "example") ret.add(tup) - assert(ret[ret.len()-1][0] == "example") + doAssert(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] '=' ", type(T).name + echo "GenericT[T] '=' ", typeof(T).name var ag: GenericT[int] var bg: GenericT[int] diff --git a/tests/assign/tobject_assign.nim b/tests/assign/tobject_assign.nim new file mode 100644 index 0000000000..8e39ead534 --- /dev/null +++ b/tests/assign/tobject_assign.nim @@ -0,0 +1,49 @@ +# 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/async/t12221.nim b/tests/async/t12221.nim index 70e192356f..e8bd9c11ad 100644 --- a/tests/async/t12221.nim +++ b/tests/async/t12221.nim @@ -5,9 +5,9 @@ proc doubleSleep(hardSleep: int) {.async.} = sleep(hardSleep) template assertTime(target, timeTook: float): untyped {.dirty.} = - assert(timeTook*1000 > target - 1000, "Took too short, should've taken " & + doAssert(timeTook*1000 > target - 1000, "Took too short, should've taken " & $target & "ms, but took " & $(timeTook*1000) & "ms") - assert(timeTook*1000 < target + 1000, "Took too long, should've taken " & + doAssert(timeTook*1000 < target + 1000, "Took too long, should've taken " & $target & "ms, but took " & $(timeTook*1000) & "ms") var diff --git a/tests/async/tasync_gcsafe.nim b/tests/async/tasync_gcsafe.nim index 89df6456a7..bc0eb42710 100644 --- a/tests/async/tasync_gcsafe.nim +++ b/tests/async/tasync_gcsafe.nim @@ -7,7 +7,7 @@ discard """ ''' """ -assert compileOption("threads"), "this test will not do anything useful without --threads:on" +doAssert 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 55b66aaefc..00c92b109d 100644 --- a/tests/async/tasync_gcunsafe.nim +++ b/tests/async/tasync_gcunsafe.nim @@ -4,7 +4,7 @@ discard """ file: "asyncmacro.nim" """ -assert compileOption("threads"), "this test will not do anything useful without --threads:on" +doAssert compileOption("threads"), "this test will not do anything useful without --threads:on" import asyncdispatch diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim index aec4ce5231..f658a15ed1 100644 --- a/tests/async/tasyncawait.nim +++ b/tests/async/tasyncawait.nim @@ -52,5 +52,5 @@ while true: poll() if clientCount == swarmSize: break -assert msgCount == swarmSize * messagesToSend +doAssert msgCount == swarmSize * messagesToSend doAssert msgCount == 2000 diff --git a/tests/async/tasynceagain.nim b/tests/async/tasynceagain.nim index aebd4ef169..94c3645dc7 100644 --- a/tests/async/tasynceagain.nim +++ b/tests/async/tasynceagain.nim @@ -21,12 +21,12 @@ proc runServer() {.async.} = var lastN = 0 while true: let frame = await client.recv(FrameSize) - assert frame.len == 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}!" - assert n == lastN + 1 + doAssert n == lastN + 1 lastN = n await sleepAsync 100 diff --git a/tests/async/tasyncnetudp.nim b/tests/async/tasyncnetudp.nim index 3494def374..ef6dfc5e19 100644 --- a/tests/async/tasyncnetudp.nim +++ b/tests/async/tasyncnetudp.nim @@ -84,7 +84,7 @@ while true: if recvCount == swarmSize * messagesToSend: break -assert msgCount == swarmSize * messagesToSend -assert sendports == recvports +doAssert msgCount == swarmSize * messagesToSend +doAssert sendports == recvports echo msgCount \ No newline at end of file diff --git a/tests/async/tasyncssl.nim b/tests/async/tasyncssl.nim index c948ee9b7b..a582818eb3 100644 --- a/tests/async/tasyncssl.nim +++ b/tests/async/tasyncssl.nim @@ -69,5 +69,5 @@ when defined(ssl): elif defined(linux) and int.sizeof == 8: # currently: msgCount == 10 flakyAssert cond() - assert msgCount > 0 - else: assert cond(), $msgCount + doAssert msgCount > 0 + else: doAssert cond(), $msgCount diff --git a/tests/benchmarks/readme.md b/tests/benchmarks/readme.md new file mode 100644 index 0000000000..1e744fc40b --- /dev/null +++ b/tests/benchmarks/readme.md @@ -0,0 +1,5 @@ +# 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 new file mode 100644 index 0000000000..f5314850f7 --- /dev/null +++ b/tests/benchmarks/ttls.nim @@ -0,0 +1,30 @@ +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/ccgbugs/t16374.nim b/tests/ccgbugs/t16374.nim new file mode 100644 index 0000000000..8ccfa4815c --- /dev/null +++ b/tests/ccgbugs/t16374.nim @@ -0,0 +1,38 @@ +discard """ + matrix: "--gc:refc; --gc:orc" +""" + +block: + iterator mvalues(t: var seq[seq[int]]): var seq[int] = + yield t[0] + + var t: seq[seq[int]] + + while false: + for v in t.mvalues: + discard + + proc ok = + while false: + for v in t.mvalues: + discard + + ok() + +block: + iterator mvalues(t: var seq[seq[int]]): lent seq[int] = + yield t[0] + + var t: seq[seq[int]] + + while false: + for v in t.mvalues: + discard + + proc ok = + while false: + for v in t.mvalues: + discard + + ok() + diff --git a/tests/ccgbugs/t6756.nim b/tests/ccgbugs/t6756.nim index 5170a99f4c..5990eba58a 100644 --- a/tests/ccgbugs/t6756.nim +++ b/tests/ccgbugs/t6756.nim @@ -10,7 +10,7 @@ type v: T template templ(o: A, op: untyped): untyped = - type T = type(o.v) + type T = typeof(o.v) var res: A[T] diff --git a/tests/ccgbugs/t9286.nim b/tests/ccgbugs/t9286.nim index 8a45a7bf60..2fec233079 100644 --- a/tests/ccgbugs/t9286.nim +++ b/tests/ccgbugs/t9286.nim @@ -7,7 +7,7 @@ type Foo = ref object i: int proc next(foo: Foo): Option[Foo] = - try: assert(foo.i == 0) + try: doAssert(foo.i == 0) except: return # 2º: none return some(foo) # 1º: some @@ -17,6 +17,6 @@ proc test = while isSome(opt) and foo.i < 10: inc(foo.i) opt = next(foo) # 2º None - assert foo.i == 1, $foo.i + doAssert foo.i == 1, $foo.i test() diff --git a/tests/ccgbugs/t9655.nim b/tests/ccgbugs/t9655.nim new file mode 100644 index 0000000000..29fb903a45 --- /dev/null +++ b/tests/ccgbugs/t9655.nim @@ -0,0 +1,30 @@ +discard """ + action: "compile" +""" + +import std/[asynchttpserver, asyncdispatch] +import std/[strformat] + +proc main() = + let local = "123" + + proc serveIndex(req: Request) {.async, gcsafe.} = + await req.respond(Http200, &"{local}") + + proc serve404(req: Request) {.async, gcsafe.} = + echo req.url.path + await req.respond(Http404, "not found") + + proc serve(req: Request) {.async, gcsafe.} = + let handler = case req.url.path: + of "/": + serveIndex + else: + serve404 + await handler(req) + + let server = newAsyncHttpServer() + waitFor server.serve(Port(8080), serve, address = "127.0.0.1") + +when isMainModule: + main() diff --git a/tests/ccgbugs/tassign_nil_strings.nim b/tests/ccgbugs/tassign_nil_strings.nim index 07d2c2aeb9..f6fab7baac 100644 --- a/tests/ccgbugs/tassign_nil_strings.nim +++ b/tests/ccgbugs/tassign_nil_strings.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim $target --nilseqs:off $options $file" + cmd: "nim $target $options $file" output: "Hello" ccodecheck: "\\i@'a = ((NimStringDesc*) NIM_NIL)'" """ diff --git a/tests/ccgbugs/tissues.nim b/tests/ccgbugs/tissues.nim index 7a8ede9589..a0c402cc07 100644 --- a/tests/ccgbugs/tissues.nim +++ b/tests/ccgbugs/tissues.nim @@ -26,3 +26,13 @@ type 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/t14160.nim b/tests/ccgbugs/tlvalueconv.nim similarity index 50% rename from tests/ccgbugs/t14160.nim rename to tests/ccgbugs/tlvalueconv.nim index be7088e291..b2cb11eefb 100644 --- a/tests/ccgbugs/t14160.nim +++ b/tests/ccgbugs/tlvalueconv.nim @@ -1,3 +1,9 @@ +discard """ + matrix: "--gc:refc; --gc:arc" +""" + +# bug #14160 + type TPassContext = object of RootObj PPassContext = ref TPassContext @@ -11,5 +17,16 @@ type 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/tuple_canon.nim b/tests/ccgbugs/tuple_canon.nim index aa9605d4ba..fbb9718614 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 : type(evenSharingOffsets[i]) + #var offset : typeof(evenSharingOffsets[i]) # #if odd(col): # offset = oddSharingOffsets[i] diff --git a/tests/ccgbugs/twrong_tupleconv.nim b/tests/ccgbugs/twrong_tupleconv.nim index 7b1e58083d..7a887d1835 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) - assert(len(a) == L, "the length of the seq changed while iterating over it") + doAssert(len(a) == L, "the length of the seq changed while iterating over it") # Works fine var xs = @[1,2,3] diff --git a/tests/closure/tnested.nim b/tests/closure/tnested.nim index 7a1881a602..ca8d0e08b4 100644 --- a/tests/closure/tnested.nim +++ b/tests/closure/tnested.nim @@ -190,7 +190,7 @@ proc foo() = let f = (proc() = myDiscard (proc() = echo a) ) - echo name(type(f)) + echo name(typeof(f)) foo() diff --git a/tests/collections/tseq.nim b/tests/collections/tseq.nim index 263a571bf3..a7a0c724ec 100644 --- a/tests/collections/tseq.nim +++ b/tests/collections/tseq.nim @@ -24,7 +24,7 @@ block tseq2: # multiply two int sequences: for i in 0..len(a)-1: result[i] = a[i] * b[i] - assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9]) + doAssert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9]) @@ -201,7 +201,7 @@ block ttoseq: stdout.write(x) for x in items(toSeq(countup(2, 6))): stdout.write(x) - var y: type("a b c".split) + var y: typeof("a b c".split) y = "xzy" stdout.write("\n") diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 338a83fedc..61197e9f0e 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -50,20 +50,20 @@ block thashes: var t = initTable[int,int]() t[0] = 42 t[1] = t[0] + 1 - assert(t[0] == 42) - assert(t[1] == 43) + doAssert(t[0] == 42) + doAssert(t[1] == 43) let t2 = {1: 1, 2: 2}.toTable - assert(t2[2] == 2) + doAssert(t2[2] == 2) # Test with char block: var t = initTable[char,int]() t['0'] = 42 t['1'] = t['0'] + 1 - assert(t['0'] == 42) - assert(t['1'] == 43) + doAssert(t['0'] == 42) + doAssert(t['1'] == 43) let t2 = {'1': 1, '2': 2}.toTable - assert(t2['2'] == 2) + doAssert(t2['2'] == 2) # Test with enum block: @@ -72,10 +72,10 @@ block thashes: var t = initTable[E,int]() t[eA] = 42 t[eB] = t[eA] + 1 - assert(t[eA] == 42) - assert(t[eB] == 43) + doAssert(t[eA] == 42) + doAssert(t[eB] == 43) let t2 = {eA: 1, eB: 2}.toTable - assert(t2[eB] == 2) + doAssert(t2[eB] == 2) # Test with range block: @@ -84,10 +84,10 @@ block thashes: var t = initTable[R,int]() # causes warning, why? t[1] = 42 # causes warning, why? t[2] = t[1] + 1 - assert(t[1] == 42) - assert(t[2] == 43) + doAssert(t[1] == 42) + doAssert(t[2] == 43) let t2 = {1.R: 1, 2.R: 2}.toTable - assert(t2[2.R] == 2) + doAssert(t2[2.R] == 2) # Test which combines the generics for tuples + ordinals block: @@ -96,10 +96,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 - assert(t[("a", eA, 0, '0')] == 42) - assert(t[("b", eB, 1, '1')] == 43) + doAssert(t[("a", eA, 0, '0')] == 42) + doAssert(t[("b", eB, 1, '1')] == 43) let t2 = {("a", eA, 0, '0'): 1, ("b", eB, 1, '1'): 2}.toTable - assert(t2[("b", eB, 1, '1')] == 2) + doAssert(t2[("b", eB, 1, '1')] == 2) # Test to check if overloading is possible # Unfortunately, this does not seem to work for int @@ -165,9 +165,9 @@ block tableconstr: ignoreExpr({2: 3, "key": "value"}) # NEW: - assert 56 in 50..100 + doAssert 56 in 50..100 - assert 56 in ..60 + doAssert 56 in ..60 block ttables2: @@ -239,8 +239,8 @@ block tablesref: t[(1,1)] = "11" for x in 0..1: for y in 0..1: - assert t[(x,y)] == $x & $y - assert t.sortedPairs == + 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")] block tableTest2: @@ -253,31 +253,31 @@ block tablesref: t["012"] = 67.9 t["123"] = 1.5 # test overwriting - assert t["123"] == 1.5 + doAssert t["123"] == 1.5 try: echo t["111"] # deleted except KeyError: discard - assert(not hasKey(t, "111")) - assert "111" notin t + doAssert(not hasKey(t, "111")) + doAssert "111" notin t for key, val in items(data): t[key] = val.toFloat - for key, val in items(data): assert t[key] == val.toFloat + for key, val in items(data): doAssert 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): assert t[key] == val + for key, val in items(data): doAssert t[key] == val var i = 0 # `pairs` needs to yield in insertion order: for key, val in pairs(t): - assert key == data[i][0] - assert val == data[i][1] + doAssert key == data[i][0] + doAssert val == data[i][1] inc(i) for key, val in mpairs(t): val = 99 - for val in mvalues(t): assert val == 99 + for val in mvalues(t): doAssert val == 99 block countTableTest1: var s = data.toTable @@ -286,11 +286,11 @@ block tablesref: for x in [t, r]: for k in s.keys: x.inc(k) - assert x[k] == 1 + doAssert x[k] == 1 x.inc("90", 3) x.inc("12", 2) x.inc("34", 1) - assert t.largest()[0] == "90" + doAssert t.largest()[0] == "90" t.sort() r.sort(SortOrder.Ascending) @@ -301,9 +301,9 @@ block tablesref: var i = 0 for (k, v) in ps: case i - of 0: assert k == "90" and v == 4 - of 1: assert k == "12" and v == 3 - of 2: assert k == "34" and v == 2 + of 0: doAssert k == "90" and v == 4 + of 1: doAssert k == "12" and v == 3 + of 2: doAssert k == "34" and v == 2 else: break inc i @@ -327,17 +327,17 @@ block tablesref: block nilTest: var i, j: TableRef[int, int] = nil - assert i == j + doAssert i == j j = newTable[int, int]() - assert i != j - assert j != i + doAssert i != j + doAssert j != i i = newTable[int, int]() - assert i == j + doAssert 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): assert t[key] == val + for key, val in items(data): doAssert t[key] == val proc cmper(x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key) t.sort(cmper) var i = 0 @@ -369,25 +369,25 @@ block tablesref: t["test"] = 1.2345 t["111"] = 1.000043 t["123"] = 1.23 - assert t.len() != 0 + doAssert t.len() != 0 t.clear() - assert t.len() == 0 + doAssert t.len() == 0 block clearOrderedTableTest: var t = newOrderedTable[string, int](2) for key, val in items(data): t[key] = val - assert t.len() != 0 + doAssert t.len() != 0 t.clear() - assert t.len() == 0 + doAssert t.len() == 0 block clearCountTableTest: var t = newCountTable[string]() t.inc("90", 3) t.inc("12", 2) t.inc("34", 1) - assert t.len() != 0 + doAssert t.len() != 0 t.clear() - assert t.len() == 0 + doAssert t.len() == 0 orderedTableSortTest() echo "3" @@ -415,7 +415,7 @@ block: # https://github.com/nim-lang/Nim/issues/13496 doAssert sortedPairs(t) == @[(15, 1), (17, 3), (19, 2)] var s = newSeq[int]() for v in t.values: s.add(v) - assert s.len == 3 + doAssert s.len == 3 doAssert sortedItems(s) == @[1, 2, 3] when t is OrderedTable|OrderedTableRef: doAssert toSeq(t.keys) == @[15, 19, 17] @@ -433,14 +433,14 @@ block: # https://github.com/nim-lang/Nim/issues/13496 block testNonPowerOf2: var a = initTable[int, int](7) a[1] = 10 - assert a[1] == 10 + doAssert a[1] == 10 var b = initTable[int, int](9) b[1] = 10 - assert b[1] == 10 + doAssert b[1] == 10 block emptyOrdered: var t1: OrderedTable[int, string] var t2: OrderedTable[int, string] - assert t1 == t2 + doAssert t1 == t2 diff --git a/tests/collections/ttablesthreads.nim b/tests/collections/ttablesthreads.nim index 9f7d777194..2a4e1bf425 100644 --- a/tests/collections/ttablesthreads.nim +++ b/tests/collections/ttablesthreads.nim @@ -48,8 +48,8 @@ block tableTest1: t[(1,1)] = "11" for x in 0..1: for y in 0..1: - assert t[(x,y)] == $x & $y - assert t.sortedPairs == @[((x: 0, y: 0), "00"), ((x: 0, y: 1), "01"), ((x: 1, y: 0), "10"), ((x: 1, y: 1), "11")] + 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")] block tableTest2: var t = initTable[string, float]() @@ -61,74 +61,74 @@ block tableTest2: t["012"] = 67.9 t["123"] = 1.5 # test overwriting - assert t["123"] == 1.5 + doAssert t["123"] == 1.5 try: echo t["111"] # deleted except KeyError: discard - assert(not hasKey(t, "111")) + doAssert(not hasKey(t, "111")) - assert "123" in t - assert("111" notin t) + doAssert "123" in t + doAssert("111" notin t) for key, val in items(data): t[key] = val.toFloat - for key, val in items(data): assert t[key] == val.toFloat + for key, val in items(data): doAssert t[key] == val.toFloat - assert(not t.hasKeyOrPut("456", 4.0)) # test absent key - assert t.hasKeyOrPut("012", 3.0) # test present key + doAssert(not t.hasKeyOrPut("456", 4.0)) # test absent key + doAssert t.hasKeyOrPut("012", 3.0) # test present key var x = t.mgetOrPut("111", 1.5) # test absent key x = x * 2 - assert x == 3.0 + doAssert x == 3.0 x = t.mgetOrPut("test", 1.5) # test present key x = x * 2 - assert x == 2 * 1.2345 + doAssert 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): assert t[key] == val + for key, val in items(data): doAssert t[key] == val var i = 0 # `pairs` needs to yield in insertion order: for key, val in pairs(t): - assert key == data[i][0] - assert val == data[i][1] + doAssert key == data[i][0] + doAssert val == data[i][1] inc(i) for key, val in mpairs(t): val = 99 - for val in mvalues(t): assert val == 99 + for val in mvalues(t): doAssert val == 99 block orderedTableTest2: var s = initOrderedTable[string, int]() t = initOrderedTable[string, int]() - assert s == t + doAssert s == t for key, val in items(data): t[key] = val - assert s != t + doAssert s != t for key, val in items(sorteddata): s[key] = val - assert s != t + doAssert s != t t.clear() - assert s != t + doAssert s != t for key, val in items(sorteddata): t[key] = val - assert s == t + doAssert 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: assert t[k] == 1 + for k in t.keys: doAssert t[k] == 1 t.inc("90", 3) t.inc("12", 2) t.inc("34", 1) - assert t.largest()[0] == "90" + doAssert t.largest()[0] == "90" t.sort() var i = 0 for k, v in t.pairs: case i - of 0: assert k == "90" and v == 4 - of 1: assert k == "12" and v == 3 - of 2: assert k == "34" and v == 2 + of 0: doAssert k == "90" and v == 4 + of 1: doAssert k == "12" and v == 3 + of 2: doAssert k == "34" and v == 2 else: break inc i @@ -136,19 +136,19 @@ block countTableTest2: var s = initCountTable[int]() t = initCountTable[int]() - assert s == t + doAssert s == t s.inc(1) - assert s != t + doAssert s != t t.inc(2) - assert s != t + doAssert s != t t.inc(1) - assert s != t + doAssert s != t s.inc(2) - assert s == t + doAssert s == t s.inc(1) - assert s != t + doAssert s != t t.inc(1) - assert s == t + doAssert s == t block mpairsTableTest1: var t = initTable[string, int]() @@ -162,9 +162,9 @@ block mpairsTableTest1: for k, v in t.pairs: if k == "a" or k == "c": - assert v == 9 + doAssert v == 9 else: - assert v != 1 and v != 3 + doAssert v != 1 and v != 3 block SyntaxTest: var x = toTable[int, string]({:}) @@ -174,10 +174,10 @@ block zeroHashKeysTest: let initialLen = t.len var testTable = t testTable[nullHashKey] = value - assert testTable[nullHashKey] == value - assert testTable.len == initialLen + 1 + doAssert testTable[nullHashKey] == value + doAssert testTable.len == initialLen + 1 testTable.del(nullHashKey) - assert testTable.len == initialLen + doAssert testTable.len == initialLen # with empty table doZeroHashValueTest(toTable[int,int]({:}), 0, 42) @@ -194,46 +194,46 @@ block zeroHashKeysTest: block clearTableTest: var t = data.toTable - assert t.len() != 0 + doAssert t.len() != 0 t.clear() - assert t.len() == 0 + doAssert t.len() == 0 block clearOrderedTableTest: var t = data.toOrderedTable - assert t.len() != 0 + doAssert t.len() != 0 t.clear() - assert t.len() == 0 + doAssert t.len() == 0 block clearCountTableTest: var t = initCountTable[string]() t.inc("90", 3) t.inc("12", 2) t.inc("34", 1) - assert t.len() != 0 + doAssert t.len() != 0 t.clear() - assert t.len() == 0 + doAssert t.len() == 0 block withKeyTest: var t: SharedTable[int, int] t.init() t.withKey(1) do (k: int, v: var int, pairExists: var bool): - assert(v == 0) + doAssert(v == 0) pairExists = true v = 42 - assert(t.mget(1) == 42) + doAssert(t.mget(1) == 42) t.withKey(1) do (k: int, v: var int, pairExists: var bool): - assert(v == 42) + doAssert(v == 42) pairExists = false try: discard t.mget(1) - assert(false, "KeyError expected") + doAssert(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) - assert(false, "KeyError expected") + doAssert(false, "KeyError expected") except KeyError: discard @@ -242,20 +242,20 @@ block takeTest: t["key"] = 123 var val = 0 - assert(t.take("key", val)) - assert(val == 123) + doAssert(t.take("key", val)) + doAssert(val == 123) val = -1 - assert(not t.take("key", val)) - assert(val == -1) + doAssert(not t.take("key", val)) + doAssert(val == -1) - assert(not t.take("otherkey", val)) - assert(val == -1) + doAssert(not t.take("otherkey", val)) + doAssert(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): assert t[key] == val + for key, val in items(data): doAssert 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/tasciitables.nim b/tests/compiler/tasciitables.nim index 80d648508d..2f3b7bf2f5 100644 --- a/tests/compiler/tasciitables.nim +++ b/tests/compiler/tasciitables.nim @@ -1,5 +1,5 @@ import stdtest/unittest_light -import compiler/asciitables +import std/private/asciitables import strformat diff --git a/tests/compiler/tbrees.nim b/tests/compiler/tbrees.nim index 364b51b226..5f6482ed94 100644 --- a/tests/compiler/tbrees.nim +++ b/tests/compiler/tbrees.nim @@ -42,14 +42,14 @@ proc main = st.add("www.weather.com", "63.111.66.11") st.add("www.yahoo.com", "216.109.118.65") - assert st.getOrDefault("www.cs.princeton.edu") == "abc" - assert st.getOrDefault("www.harvardsucks.com") == "" + doAssert st.getOrDefault("www.cs.princeton.edu") == "abc" + doAssert st.getOrDefault("www.harvardsucks.com") == "" - assert st.getOrDefault("www.simpsons.com") == "209.052.165.60" - assert st.getOrDefault("www.apple.com") == "17.112.152.32" - assert st.getOrDefault("www.ebay.com") == "66.135.192.87" - assert st.getOrDefault("www.dell.com") == "143.166.224.230" - assert(st.len == 16) + 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 diff --git a/tests/compiler/tcmdlineoswin.nim b/tests/compiler/tcmdlineoswin.nim index 6642c5ac62..602671e989 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: "macosx" + disabled: "osx" disabled: "unix" disabled: "posix" """ diff --git a/tests/compilerapi/tcompilerapi.nim b/tests/compilerapi/tcompilerapi.nim index d8489c763f..ab995cb6db 100644 --- a/tests/compilerapi/tcompilerapi.nim +++ b/tests/compilerapi/tcompilerapi.nim @@ -18,7 +18,7 @@ import std / [os] proc initInterpreter(script: string): Interpreter = let std = findNimStdLibCompileTime() - result = createInterpreter(script , [std, parentDir(currentSourcePath), + result = createInterpreter(script, [std, parentDir(currentSourcePath), std / "pure", std / "core"]) proc main() = diff --git a/tests/concepts/tconcepts.nim b/tests/concepts/tconcepts.nim index d0bc76c20f..acdff6f246 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 + type CustomTypeClass = concept c true # 3 competing procs diff --git a/tests/concepts/tconcepts_issues.nim b/tests/concepts/tconcepts_issues.nim index 65f6d46604..c76049bdde 100644 --- a/tests/concepts/tconcepts_issues.nim +++ b/tests/concepts/tconcepts_issues.nim @@ -397,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 + type ProtocolFollower = concept c true # not a particularly involved protocol type ImplementorA = object @@ -467,3 +467,36 @@ 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 = unsafeAddr b + prod(r, b) + else: + assert address == unsafeAddr 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) + diff --git a/tests/concepts/tconcepts_overload_precedence.nim b/tests/concepts/tconcepts_overload_precedence.nim index 9eed6256a3..c580d2688c 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 +type CustomTypeClass = concept c true # 3 competing procs diff --git a/tests/concepts/tspec.nim b/tests/concepts/tspec.nim new file mode 100644 index 0000000000..1bca3c11b8 --- /dev/null +++ b/tests/concepts/tspec.nim @@ -0,0 +1,106 @@ +discard """ + output: '''4 +0 +4 +4 +1 +2 +3 +yes int +string int +true''' + 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 + +echo(int is Monoid) + diff --git a/tests/config.nims b/tests/config.nims index e0b8502ee5..41edf00053 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -8,9 +8,22 @@ switch("path", "$lib/../testament/lib") switch("colors", "off") switch("listFullPaths", "off") switch("excessiveStackTrace", "off") +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") + +# experimental API's are enabled in testament, refs https://github.com/timotheecour/Nim/issues/575 +switch("define", "nimExperimentalAsyncjsThen") diff --git a/tests/constr/tnocompiletimefunc.nim b/tests/constr/tnocompiletimefunc.nim new file mode 100644 index 0000000000..a95648c0ff --- /dev/null +++ b/tests/constr/tnocompiletimefunc.nim @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000000..d134eea403 --- /dev/null +++ b/tests/constr/tnocompiletimefunclambda.nim @@ -0,0 +1,6 @@ +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/converter/t7097.nim b/tests/converter/t7097.nim new file mode 100644 index 0000000000..fdb5735886 --- /dev/null +++ b/tests/converter/t7097.nim @@ -0,0 +1,38 @@ +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 + + 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/tconverter.nim b/tests/converter/tconverter.nim new file mode 100644 index 0000000000..0bf067c55b --- /dev/null +++ b/tests/converter/tconverter.nim @@ -0,0 +1,11 @@ +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/tgenericconverter.nim b/tests/converter/tgenericconverter.nim index e1c9f7c4c3..cbbd2e1b07 100644 --- a/tests/converter/tgenericconverter.nim +++ b/tests/converter/tgenericconverter.nim @@ -28,3 +28,27 @@ 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/coroutines/tgc.nim b/tests/coroutines/tgc.nim index 311ec5efc4..e2f8b64697 100644 --- a/tests/coroutines/tgc.nim +++ b/tests/coroutines/tgc.nim @@ -1,19 +1,22 @@ discard """ - targets: "c" + matrix: "--gc:refc; --gc:arc; --gc:orc" + target: "c" """ -import coro +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 -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/twait.nim b/tests/coroutines/twait.nim index 348007afbf..71782ece16 100644 --- a/tests/coroutines/twait.nim +++ b/tests/coroutines/twait.nim @@ -1,20 +1,28 @@ discard """ output: "Exit 1\nExit 2" - targets: "c" + matrix: "--gc:refc; --gc:arc; --gc:orc" + target: "c" """ -import coro -var coro1: CoroutineRef +when compileOption("gc", "refc") or not defined(openbsd): + # xxx openbsd failed, see tgc.nim + import coro -proc testCoroutine1() = - for i in 0..<10: - suspend(0) + 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 echo "Exit 1" - -proc testCoroutine2() = - coro1.wait() echo "Exit 2" - -coro1 = coro.start(testCoroutine1) -coro.start(testCoroutine2) -run() diff --git a/tests/cpp/t4834.nim b/tests/cpp/t4834.nim new file mode 100644 index 0000000000..0275b1b70d --- /dev/null +++ b/tests/cpp/t4834.nim @@ -0,0 +1,17 @@ +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/tasync_cpp.nim b/tests/cpp/tasync_cpp.nim index a68be6cd5c..696274ec47 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 --nilseqs:on --nimblePath:tests/deps $file" + cmd: "nim cpp --clearNimblePath --nimblePath:build/deps/pkgs $file" """ # bug #3299 diff --git a/tests/cpp/ttemplatetype.nim b/tests/cpp/ttemplatetype.nim index ef24e4cdc8..bf243ac431 100644 --- a/tests/cpp/ttemplatetype.nim +++ b/tests/cpp/ttemplatetype.nim @@ -3,7 +3,7 @@ discard """ """ type - Map {.importcpp: "std::map", header: "".} [T,U] = object + Map[T,U] {.importcpp: "std::map", header: "".} = object proc cInitMap(T: typedesc, U: typedesc): Map[T,U] {.importcpp: "std::map<'*1,'*2>()", nodecl.} diff --git a/tests/deps/jester-#head/jester.nim b/tests/deps/jester-#head/jester.nim deleted file mode 100644 index 1118214c26..0000000000 --- a/tests/deps/jester-#head/jester.nim +++ /dev/null @@ -1,1385 +0,0 @@ -# Copyright (C) 2015 Dominik Picheta -# MIT License - Look at license.txt for details. -import net, strtabs, re, tables, os, strutils, uri, - times, mimetypes, asyncnet, asyncdispatch, macros, md5, - logging, httpcore, asyncfile, macrocache, json, options, - strformat - -import jester/private/[errorpages, utils] -import jester/[request, patterns] - -from cgi import decodeData, decodeUrl, CgiError - -export request -export strtabs -export tables -export httpcore -export MultiData -export HttpMethod -export asyncdispatch - -export SameSite - -when useHttpBeast: - import httpbeast except Settings, Request - import options - from nativesockets import close -else: - import asynchttpserver except Request - -type - MatchProc* = proc (request: Request): Future[ResponseData] {.gcsafe, closure.} - MatchProcSync* = proc (request: Request): ResponseData{.gcsafe, closure.} - - Matcher = object - case async: bool - of false: - syncProc: MatchProcSync - of true: - asyncProc: MatchProc - - ErrorProc* = proc ( - request: Request, error: RouteError - ): Future[ResponseData] {.gcsafe, closure.} - - Jester* = object - when not useHttpBeast: - httpServer*: AsyncHttpServer - settings: Settings - matchers: seq[Matcher] - errorHandlers: seq[ErrorProc] - - MatchType* = enum - MRegex, MSpecial, MStatic - - RawHeaders* = seq[tuple[key, val: string]] - ResponseData* = tuple[ - action: CallbackAction, - code: HttpCode, - headers: Option[RawHeaders], - content: string, - matched: bool - ] - - CallbackAction* = enum - TCActionNothing, TCActionSend, TCActionRaw, TCActionPass - - RouteErrorKind* = enum - RouteException, RouteCode - RouteError* = object - case kind*: RouteErrorKind - of RouteException: - exc: ref Exception - of RouteCode: - data: ResponseData - -const jesterVer = "0.4.3" - -proc toStr(headers: Option[RawHeaders]): string = - return $newHttpHeaders(headers.get(@({:}))) - -proc createHeaders(headers: RawHeaders): string = - result = "" - if headers.len > 0: - for header in headers: - let (key, value) = header - result.add(key & ": " & value & "\c\L") - - result = result[0 .. ^3] # Strip trailing \c\L - -proc createResponse(status: HttpCode, headers: RawHeaders): string = - return "HTTP/1.1 " & $status & "\c\L" & createHeaders(headers) & "\c\L\c\L" - -proc unsafeSend(request: Request, content: string) = - when useHttpBeast: - request.getNativeReq.unsafeSend(content) - else: - # TODO: This may cause issues if we send too fast. - asyncCheck request.getNativeReq.client.send(content) - -proc send( - request: Request, code: HttpCode, headers: Option[RawHeaders], body: string -): Future[void] = - when useHttpBeast: - let h = - if headers.isNone: "" - else: headers.get().createHeaders - request.getNativeReq.send(code, body, h) - var fut = newFuture[void]() - complete(fut) - return fut - else: - return request.getNativeReq.respond( - code, body, newHttpHeaders(headers.get(@({:}))) - ) - -proc statusContent(request: Request, status: HttpCode, content: string, - headers: Option[RawHeaders]): Future[void] = - try: - result = send(request, status, headers, content) - when not defined(release): - logging.debug(" $1 $2" % [$status, toStr(headers)]) - except: - logging.error("Could not send response: $1" % osErrorMsg(osLastError())) - -# TODO: Add support for proper Future Streams instead of this weird raw mode. -template enableRawMode* = - # TODO: Use the effect system to make this implicit? - result.action = TCActionRaw - -proc send*(request: Request, content: string) = - ## Sends ``content`` immediately to the client socket. - ## - ## Routes using this procedure must enable raw mode. - unsafeSend(request, content) - -proc sendHeaders*(request: Request, status: HttpCode, - headers: RawHeaders) = - ## Sends ``status`` and ``headers`` to the client socket immediately. - ## The user is then able to send the content immediately to the client on - ## the fly through the use of ``response.client``. - let headerData = createResponse(status, headers) - try: - request.send(headerData) - logging.debug(" $1 $2" % [$status, $headers]) - except: - logging.error("Could not send response: $1" % [osErrorMsg(osLastError())]) - -proc sendHeaders*(request: Request, status: HttpCode) = - ## Sends ``status`` and ``Content-Type: text/html`` as the headers to the - ## client socket immediately. - let headers = @({"Content-Type": "text/html;charset=utf-8"}) - request.sendHeaders(status, headers) - -proc sendHeaders*(request: Request) = - ## Sends ``Http200`` and ``Content-Type: text/html`` as the headers to the - ## client socket immediately. - request.sendHeaders(Http200) - -proc send*(request: Request, status: HttpCode, headers: RawHeaders, - content: string) = - ## Sends out a HTTP response comprising of the ``status``, ``headers`` and - ## ``content`` specified. - var headers = headers & @({"Content-Length": $content.len}) - request.sendHeaders(status, headers) - request.send(content) - -# TODO: Cannot capture 'paths: varargs[string]' here. -proc sendStaticIfExists( - req: Request, paths: seq[string] -): Future[HttpCode] {.async.} = - result = Http200 - for p in paths: - if existsFile(p): - - var fp = getFilePermissions(p) - if not fp.contains(fpOthersRead): - return Http403 - - let fileSize = getFileSize(p) - let ext = p.splitFile.ext - let mimetype = req.settings.mimes.getMimetype( - if ext.len > 0: ext[1 .. ^1] - else: "" - ) - if fileSize < 10_000_000: # 10 mb - var file = readFile(p) - - var hashed = getMD5(file) - - # If the user has a cached version of this file and it matches our - # version, let them use it - if req.headers.hasKey("If-None-Match") and req.headers["If-None-Match"] == hashed: - await req.statusContent(Http304, "", none[RawHeaders]()) - else: - await req.statusContent(Http200, file, some(@({ - "Content-Type": mimetype, - "ETag": hashed - }))) - else: - let headers = @({ - "Content-Type": mimetype, - "Content-Length": $fileSize - }) - await req.statusContent(Http200, "", some(headers)) - - var fileStream = newFutureStream[string]("sendStaticIfExists") - var file = openAsync(p, fmRead) - # Let `readToStream` write file data into fileStream in the - # background. - asyncCheck file.readToStream(fileStream) - # The `writeFromStream` proc will complete once all the data in the - # `bodyStream` has been written to the file. - while true: - let (hasValue, value) = await fileStream.read() - if hasValue: - req.unsafeSend(value) - else: - break - file.close() - - return - - # If we get to here then no match could be found. - return Http404 - -proc close*(request: Request) = - ## Closes client socket connection. - ## - ## Routes using this procedure must enable raw mode. - let nativeReq = request.getNativeReq() - when useHttpBeast: - nativeReq.forget() - nativeReq.client.close() - -proc defaultErrorFilter(error: RouteError): ResponseData = - case error.kind - of RouteException: - let e = error.exc - let traceback = getStackTrace(e) - var errorMsg = e.msg - if errorMsg.len == 0: errorMsg = "(empty)" - - let error = traceback & errorMsg - logging.error(error) - result.headers = some(@({ - "Content-Type": "text/html;charset=utf-8" - })) - result.content = routeException( - error.replace("\n", "
          \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 - let pathDir = path.splitFile.dir / "" - let staticDir = jes.settings.staticDir / "" - if pathDir.startsWith(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)) - - await 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): - return 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) - - assert(not result.isNil, "Expected handleRequest to return a valid future.") - -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: - when defined(windows): - logging.info("Jester is making jokes at http://127.0.0.1:$1$2 (all interfaces)" % - [$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] = - {.gcsafe.}: - 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 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*(code: HttpCode, - headers: openarray[tuple[key, val: string]], - content: string): typed = - ## Sets ``(code, headers, content)`` as the response. - bind TCActionSend - result = (TCActionSend, code, none[RawHeaders](), content, true) - for header in headers: - setHeader(result[2], header[0], header[1]) - break route - - -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 + initTimeInterval(days = days) - -template setCookie*(name, value: string, expires="", - sameSite: SameSite=Lax, secure = false, - httpOnly = false, domain = "", path = "") = - ## 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, domain, path, secure, httpOnly, sameSite) - 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, secure = false, - httpOnly = false, domain = "", path = "") = - ## Creates a cookie which stores ``value`` under ``name``. - setCookie(name, value, - format(expires.utc, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"), - sameSite, secure, httpOnly, domain, path) - -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: - raise newException( - ValueError, - "Missing route action, did you forget to use `resp` in your route?" - ) - -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*() = - # 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() {.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 != 0: - 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) = - 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) = - if name.kind != nnkIdent: - error("Need an ident.", name) - - routesEx(strVal(name), body) - -macro settings*(body: untyped) = - #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 deleted file mode 100644 index a1306c525b..0000000000 --- a/tests/deps/jester-#head/jester.nimble +++ /dev/null @@ -1,22 +0,0 @@ -# Package - -version = "0.4.3" # 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.2" - -# For tests -requires "https://github.com/timotheecour/asynctools#pr_fix_compilation" - -task test, "Runs the test suite.": - exec "nimble c -y -r tests/tester" diff --git a/tests/deps/jester-#head/jester/patterns.nim b/tests/deps/jester-#head/jester/patterns.nim deleted file mode 100644 index 03d41796e2..0000000000 --- a/tests/deps/jester-#head/jester/patterns.nim +++ /dev/null @@ -1,141 +0,0 @@ -# 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) = - 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 isMainModule: - 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 deleted file mode 100644 index d1e6950400..0000000000 --- a/tests/deps/jester-#head/jester/private/errorpages.nim +++ /dev/null @@ -1,19 +0,0 @@ -# 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 deleted file mode 100644 index 2d1390955b..0000000000 --- a/tests/deps/jester-#head/jester/private/utils.nim +++ /dev/null @@ -1,194 +0,0 @@ -# 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 cgi/decodeData".} = - 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 deleted file mode 100644 index 20e5c840fe..0000000000 --- a/tests/deps/jester-#head/jester/request.nim +++ /dev/null @@ -1,185 +0,0 @@ -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, e.g. 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 deleted file mode 100644 index 5594ef9159..0000000000 --- a/tests/deps/opengl-1.1.0/glu.nim +++ /dev/null @@ -1,326 +0,0 @@ -# -# -# 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 deleted file mode 100644 index 55a5da0c71..0000000000 --- a/tests/deps/opengl-1.1.0/glut.nim +++ /dev/null @@ -1,366 +0,0 @@ -# -# -# 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 deleted file mode 100644 index 6ad096c7d1..0000000000 --- a/tests/deps/opengl-1.1.0/glx.nim +++ /dev/null @@ -1,154 +0,0 @@ -# -# -# 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 deleted file mode 100644 index 55e009a461..0000000000 --- a/tests/deps/opengl-1.1.0/opengl.nim +++ /dev/null @@ -1,8481 +0,0 @@ - -# -# -# 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 deleted file mode 100644 index ac3b8aa329..0000000000 --- a/tests/deps/opengl-1.1.0/opengl.nimble +++ /dev/null @@ -1,12 +0,0 @@ -# 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 deleted file mode 100644 index 9497bffb44..0000000000 --- a/tests/deps/opengl-1.1.0/wingl.nim +++ /dev/null @@ -1,369 +0,0 @@ -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 deleted file mode 100644 index b262ad7c11..0000000000 --- a/tests/deps/x11-1.0/cursorfont.nim +++ /dev/null @@ -1,110 +0,0 @@ -# $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 deleted file mode 100644 index c001ab6224..0000000000 --- a/tests/deps/x11-1.0/keysym.nim +++ /dev/null @@ -1,1926 +0,0 @@ -# -#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 deleted file mode 100644 index 9d9df48bd2..0000000000 --- a/tests/deps/x11-1.0/x.nim +++ /dev/null @@ -1,400 +0,0 @@ - -# -# 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 deleted file mode 100644 index 2f4385100b..0000000000 --- a/tests/deps/x11-1.0/x11.nimble +++ /dev/null @@ -1,11 +0,0 @@ -[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 deleted file mode 100644 index b4c876cf0a..0000000000 --- a/tests/deps/x11-1.0/x11pragma.nim +++ /dev/null @@ -1,20 +0,0 @@ -# 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 deleted file mode 100644 index b2e1dca916..0000000000 --- a/tests/deps/x11-1.0/xatom.nim +++ /dev/null @@ -1,81 +0,0 @@ -# -# 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 deleted file mode 100644 index 659676c45b..0000000000 --- a/tests/deps/x11-1.0/xcms.nim +++ /dev/null @@ -1,389 +0,0 @@ - -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 deleted file mode 100644 index 65e26df22d..0000000000 --- a/tests/deps/x11-1.0/xf86dga.nim +++ /dev/null @@ -1,235 +0,0 @@ -# -# 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 deleted file mode 100644 index 547f5cbd2e..0000000000 --- a/tests/deps/x11-1.0/xf86vmode.nim +++ /dev/null @@ -1,229 +0,0 @@ -# $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 deleted file mode 100644 index d1b9f78462..0000000000 --- a/tests/deps/x11-1.0/xi.nim +++ /dev/null @@ -1,307 +0,0 @@ -# -# $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 deleted file mode 100644 index 96f5d7da3b..0000000000 --- a/tests/deps/x11-1.0/xinerama.nim +++ /dev/null @@ -1,25 +0,0 @@ -# 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 deleted file mode 100644 index 2ecf17026e..0000000000 --- a/tests/deps/x11-1.0/xkb.nim +++ /dev/null @@ -1,2387 +0,0 @@ -# -# $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 deleted file mode 100644 index 2366b09718..0000000000 --- a/tests/deps/x11-1.0/xkblib.nim +++ /dev/null @@ -1,661 +0,0 @@ -# $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 deleted file mode 100644 index e9f2119364..0000000000 --- a/tests/deps/x11-1.0/xlib.nim +++ /dev/null @@ -1,2026 +0,0 @@ - -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 deleted file mode 100644 index ee6f1705b8..0000000000 --- a/tests/deps/x11-1.0/xrandr.nim +++ /dev/null @@ -1,194 +0,0 @@ -# -# $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 deleted file mode 100644 index c4b2b364dd..0000000000 --- a/tests/deps/x11-1.0/xrender.nim +++ /dev/null @@ -1,241 +0,0 @@ - -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 deleted file mode 100644 index c96fbbb523..0000000000 --- a/tests/deps/x11-1.0/xresource.nim +++ /dev/null @@ -1,201 +0,0 @@ - -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 deleted file mode 100644 index e56bd87b1f..0000000000 --- a/tests/deps/x11-1.0/xshm.nim +++ /dev/null @@ -1,77 +0,0 @@ - -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 deleted file mode 100644 index b7de0ae3e3..0000000000 --- a/tests/deps/x11-1.0/xutil.nim +++ /dev/null @@ -1,412 +0,0 @@ - -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 deleted file mode 100644 index 45ab614183..0000000000 --- a/tests/deps/x11-1.0/xv.nim +++ /dev/null @@ -1,84 +0,0 @@ -#*********************************************************** -#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 deleted file mode 100644 index 354a4b93b2..0000000000 --- a/tests/deps/x11-1.0/xvlib.nim +++ /dev/null @@ -1,234 +0,0 @@ -#*********************************************************** -#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] # e.g. 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 deleted file mode 100644 index 561f1b9c9f..0000000000 --- a/tests/deps/zip-0.2.1/zip.nimble +++ /dev/null @@ -1,18 +0,0 @@ -# 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 deleted file mode 100644 index 82c412bc3b..0000000000 --- a/tests/deps/zip-0.2.1/zip/gzipfiles.nim +++ /dev/null @@ -1,97 +0,0 @@ -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 deleted file mode 100644 index a2904cd2c7..0000000000 --- a/tests/deps/zip-0.2.1/zip/libzip.nim +++ /dev/null @@ -1,252 +0,0 @@ -# -# -# 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 deleted file mode 100644 index e0627a7eb5..0000000000 --- a/tests/deps/zip-0.2.1/zip/private/libzip_all.c +++ /dev/null @@ -1,4193 +0,0 @@ -/* - 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 deleted file mode 100644 index 274587df92..0000000000 --- a/tests/deps/zip-0.2.1/zip/zipfiles.nim +++ /dev/null @@ -1,193 +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. -# - -## 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 deleted file mode 100644 index f41ed5cfe1..0000000000 --- a/tests/deps/zip-0.2.1/zip/zlib.nim +++ /dev/null @@ -1,425 +0,0 @@ -# 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 deleted file mode 100644 index 553970e0cc..0000000000 --- a/tests/deps/zip-0.2.1/zip/zzip.nim +++ /dev/null @@ -1,176 +0,0 @@ -# -# -# 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/t12037.nim b/tests/destructor/t12037.nim index 1a7d536cc6..c2c41dfb54 100644 --- a/tests/destructor/t12037.nim +++ b/tests/destructor/t12037.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --newruntime $file''' + cmd: '''nim c --gc:arc $file''' output: ''' showing original type, length, and contents seq[int] 1 @[42] copy length and contents 1 @[42] diff --git a/tests/destructor/t16607.nim b/tests/destructor/t16607.nim new file mode 100644 index 0000000000..5cc9d4a088 --- /dev/null +++ b/tests/destructor/t16607.nim @@ -0,0 +1,24 @@ +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() + result.b = initO() + +proc main() = + discard pair() + +main() diff --git a/tests/destructor/t17198.nim b/tests/destructor/t17198.nim new file mode 100644 index 0000000000..098db82453 --- /dev/null +++ b/tests/destructor/t17198.nim @@ -0,0 +1,32 @@ +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 new file mode 100644 index 0000000000..19354ea64d --- /dev/null +++ b/tests/destructor/t5342.nim @@ -0,0 +1,23 @@ +discard """ + matrix: "--gc:refc; --gc:arc" + 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 9e5292a61c..3834d39fff 100644 --- a/tests/destructor/t7346.nim +++ b/tests/destructor/t7346.nim @@ -2,8 +2,7 @@ discard """ joinable: false """ -when not defined(nimNewRuntime): - {.error: "This bug could only be reproduced with --newruntime".} +# This bug could only be reproduced with --newruntime type Obj = object diff --git a/tests/destructor/t9440.nim b/tests/destructor/t9440.nim new file mode 100644 index 0000000000..153bb303dc --- /dev/null +++ b/tests/destructor/t9440.nim @@ -0,0 +1,52 @@ +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/tarray_indexing.nim b/tests/destructor/tarray_indexing.nim index 7efd5a00c8..657101c4d2 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 --newruntime $file''' + cmd: '''nim c --gc:arc $file''' """ # bug #12669 diff --git a/tests/destructor/tbintree2.nim b/tests/destructor/tbintree2.nim index 6fdda6e546..0bc52457c9 100644 --- a/tests/destructor/tbintree2.nim +++ b/tests/destructor/tbintree2.nim @@ -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 4e203f4efd..61464101f0 100644 --- a/tests/destructor/tcaseobj_transitions.nim +++ b/tests/destructor/tcaseobj_transitions.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --newruntime $file''' + cmd: '''nim c --gc:arc $file''' output: '''no crash''' """ diff --git a/tests/destructor/tcomplexobjconstr.nim b/tests/destructor/tcomplexobjconstr.nim index fd112b6e24..aea0ad1fec 100644 --- a/tests/destructor/tcomplexobjconstr.nim +++ b/tests/destructor/tcomplexobjconstr.nim @@ -20,16 +20,16 @@ type of true: y*: float var x = new(MyObject2) -assert x of MyObject2 -assert x.subobj of MyObject1 -assert x.more[2] of MyObject1 -assert x.more[2] of RootObj +doAssert x of MyObject2 +doAssert x.subobj of MyObject1 +doAssert x.more[2] of MyObject1 +doAssert x.more[2] of RootObj var y: MyObject2 -assert y of MyObject2 -assert y.subobj of MyObject1 -assert y.more[2] of MyObject1 -assert y.more[2] of RootObj +doAssert y of MyObject2 +doAssert y.subobj of MyObject1 +doAssert y.more[2] of MyObject1 +doAssert y.more[2] of RootObj echo "true" diff --git a/tests/destructor/tgcdestructors.nim b/tests/destructor/tgcdestructors.nim index 4731bf694f..07a3731a09 100644 --- a/tests/destructor/tgcdestructors.nim +++ b/tests/destructor/tgcdestructors.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c -d:nimAllocStats --newruntime $file''' + cmd: '''nim c -d:nimAllocStats --gc:arc $file''' output: '''hi ho ha diff --git a/tests/destructor/tglobaldestructor.nim b/tests/destructor/tglobaldestructor.nim index 403f670a08..4d002a092a 100644 --- a/tests/destructor/tglobaldestructor.nim +++ b/tests/destructor/tglobaldestructor.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --newruntime $file''' + cmd: '''nim c --gc:arc $file''' output: '''(v: 42) igotdestroyed''' """ diff --git a/tests/destructor/tnewruntime_strutils.nim b/tests/destructor/tnewruntime_strutils.nim index 0725718d75..8e5378f77d 100644 --- a/tests/destructor/tnewruntime_strutils.nim +++ b/tests/destructor/tnewruntime_strutils.nim @@ -1,6 +1,6 @@ discard """ valgrind: true - cmd: '''nim c -d:nimAllocStats --newruntime -d:useMalloc $file''' + cmd: '''nim c -d:nimAllocStats --gc:arc -d:useMalloc $file''' output: ''' @[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])] 14 diff --git a/tests/destructor/towned_binary_tree.nim b/tests/destructor/towned_binary_tree.nim index 320e33759e..fb635e7c67 100644 --- a/tests/destructor/towned_binary_tree.nim +++ b/tests/destructor/towned_binary_tree.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c -d:nimAllocStats --newruntime $file''' + cmd: '''nim c -d:nimAllocStats --gc:arc $file''' output: '''31665 (allocCount: 33334, deallocCount: 33334)''' """ diff --git a/tests/destructor/tsimpleclosure.nim b/tests/destructor/tsimpleclosure.nim index 35c57a6342..9626dd6f85 100644 --- a/tests/destructor/tsimpleclosure.nim +++ b/tests/destructor/tsimpleclosure.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c -d:nimAllocStats --newruntime $file''' + cmd: '''nim c -d:nimAllocStats --gc:arc $file''' output: '''a b 70 hello diff --git a/tests/destructor/tv2_cast.nim b/tests/destructor/tv2_cast.nim index 9c05b2ae17..ef0b3a9362 100644 --- a/tests/destructor/tv2_cast.nim +++ b/tests/destructor/tv2_cast.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --newruntime $file''' + cmd: '''nim c --gc:arc $file''' output: '''@[1] @[116, 101, 115, 116] @[1953719668, 875770417]''' diff --git a/tests/distinct/tdistinct_issues.nim b/tests/distinct/tdistinct_issues.nim index ce71344d06..747cf0b8d1 100644 --- a/tests/distinct/tdistinct_issues.nim +++ b/tests/distinct/tdistinct_issues.nim @@ -65,3 +65,17 @@ 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/dll/nimhcr_integration.nim b/tests/dll/nimhcr_integration.nim index 58851b5c4c..ac34f1f85e 100644 --- a/tests/dll/nimhcr_integration.nim +++ b/tests/dll/nimhcr_integration.nim @@ -1,5 +1,5 @@ discard """ - disabled: "openbsd" + disabled: "true" output: ''' main: HELLO! main: hasAnyModuleChanged? true diff --git a/tests/effects/tnosideeffect.nim b/tests/effects/tnosideeffect.nim new file mode 100644 index 0000000000..9cabb35a2c --- /dev/null +++ b/tests/effects/tnosideeffect.nim @@ -0,0 +1,24 @@ +block: # `.noSideEffect` + func foo(bar: proc(): int): int = 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/tstrict_funcs.nim b/tests/effects/tstrict_funcs.nim index d30326123e..044bc7ee15 100644 --- a/tests/effects/tstrict_funcs.nim +++ b/tests/effects/tstrict_funcs.nim @@ -3,17 +3,6 @@ discard """ """ import tables, streams, parsecsv -# We import the below modules to check that they compile with `strictFuncs`. -# They are otherwise unused in this file. -import - complex, - httpcore, - math, - nre, - rationals, - sequtils, - strutils, - uri type Contig2Reads = TableRef[string, seq[string]] diff --git a/tests/effects/tstrict_funcs_imports.nim b/tests/effects/tstrict_funcs_imports.nim new file mode 100644 index 0000000000..4e9b9fe66d --- /dev/null +++ b/tests/effects/tstrict_funcs_imports.nim @@ -0,0 +1,177 @@ +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 + +import + algorithm, + asyncdispatch, + asyncfile, + asyncftpclient, + asyncfutures, + asynchttpserver, + asyncmacro, + asyncnet, + asyncstreams, + atomics, + base64, + bitops, + browsers, + cgi, + chains, + colors, + complex, + cookies, + coro, + cpuinfo, + cpuload, + critbits, + cstrutils, + db_common, + db_mysql, + db_odbc, + db_postgres, + db_sqlite, + 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, + punycode, + random, + rationals, + rdstdin, + re, + registry, + reservedmem, + rlocks, + ropes, + rtarrays, + selectors, + sequtils, + sets, + sharedlist, + sharedtables, + smtp, + 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 new file mode 100644 index 0000000000..b7fcd343ab --- /dev/null +++ b/tests/effects/tstrict_funcs_imports_js.nim @@ -0,0 +1,21 @@ +discard """ + cmd: "nim $target $options --hints:on --experimental:strictFuncs --experimental:views $file" + targets: "js" +""" +{.warning[UnusedImport]: off.} + +import + asyncjs, + dom, + dom_extensions, + jsconsole, + jsffi, + jsre + +import std/[ + jsbigints, +] + +import std/private/[ + jsutils, +] diff --git a/tests/errmsgs/t10734.nim b/tests/errmsgs/t10734.nim new file mode 100644 index 0000000000..4e73db7cd0 --- /dev/null +++ b/tests/errmsgs/t10734.nim @@ -0,0 +1,20 @@ +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 new file mode 100644 index 0000000000..307acac2d4 --- /dev/null +++ b/tests/errmsgs/t10735.nim @@ -0,0 +1,41 @@ +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/t8610.nim b/tests/errmsgs/t8610.nim index d3405bc91c..ec99beae5a 100644 --- a/tests/errmsgs/t8610.nim +++ b/tests/errmsgs/t8610.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "invalid type: 'type int' for const" + errormsg: "invalid type: 'typedesc[int]' for const" """ -## issue #8610 +## bug #8610 const Foo = int diff --git a/tests/errmsgs/tconceptconstraint.nim b/tests/errmsgs/tconceptconstraint.nim index 9ab1708c7b..b1977acbca 100644 --- a/tests/errmsgs/tconceptconstraint.nim +++ b/tests/errmsgs/tconceptconstraint.nim @@ -2,7 +2,7 @@ discard """ errormsg: "cannot instantiate B" line: 20 nimout: ''' -got: +got: but expected: ''' """ diff --git a/tests/errmsgs/tgenericconstraint.nim b/tests/errmsgs/tgenericconstraint.nim index e3093fead9..b7272e7878 100644 --- a/tests/errmsgs/tgenericconstraint.nim +++ b/tests/errmsgs/tgenericconstraint.nim @@ -2,7 +2,7 @@ discard """ errormsg: "cannot instantiate B" line: 14 nimout: ''' -got: +got: but expected: ''' """ diff --git a/tests/errmsgs/twrong_at_operator.nim b/tests/errmsgs/twrong_at_operator.nim index ebf6d966b8..d7bfca415d 100644 --- a/tests/errmsgs/twrong_at_operator.nim +++ b/tests/errmsgs/twrong_at_operator.nim @@ -1,17 +1,17 @@ discard """ -errormsg: "type mismatch: got " +errormsg: "type mismatch: got " line: 22 nimout: ''' -twrong_at_operator.nim(22, 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, type int] + but expression '[int]' is of type: array[0..0, typedesc[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, type int] + but expression '[int]' is of type: array[0..0, typedesc[int]] expression: @[int] ''' diff --git a/tests/fields/tfielditerator.nim b/tests/fields/tfielditerator.nim index 877e4454c4..d1fbf02f95 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 - assert x != y - assert x == x - assert(not (x < x)) - assert x <= x - assert y < x - assert y <= x + doAssert x != y + doAssert x == x + doAssert(not (x < x)) + doAssert x <= x + doAssert y < x + doAssert y <= x block titerator2: diff --git a/tests/float/tfloatnan.nim b/tests/float/tfloatnan.nim index 8f384c3d91..9e3dd94f68 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: # issue #10305 +block: # bug #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,3 +42,16 @@ block: # issue #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/gc/growobjcrash.nim b/tests/gc/growobjcrash.nim index 84fd30a4fe..ff1aa7e98d 100644 --- a/tests/gc/growobjcrash.nim +++ b/tests/gc/growobjcrash.nim @@ -1,8 +1,4 @@ -discard """ - output: "works" -""" - -import cgi, strtabs +import std/[cgi, strtabs] proc handleRequest(query: string): StringTableRef = iterator foo(): StringTableRef {.closure.} = @@ -26,4 +22,3 @@ proc main = quit "but now a leak" main() -echo "works" diff --git a/tests/gc/trace_globals.nim b/tests/gc/trace_globals.nim new file mode 100644 index 0000000000..d91bc5f355 --- /dev/null +++ b/tests/gc/trace_globals.nim @@ -0,0 +1,22 @@ +discard """ + output: '''10000000 +10000000 +10000000''' +""" + +# bug #17085 + +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 b.len + echo c.len + +f() diff --git a/tests/generics/tgenerics_issues.nim b/tests/generics/tgenerics_issues.nim index 812f339b9c..9e70efcd29 100644 --- a/tests/generics/tgenerics_issues.nim +++ b/tests/generics/tgenerics_issues.nim @@ -24,9 +24,9 @@ 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])] +(foo: none(seq[Foo]), s: "") +(foo: some(@[(a: "world", bar: none(Bar))]), s: "hello,") +@[(a: "hey", bar: none(Bar))] ''' joinable: false """ @@ -55,8 +55,8 @@ block t88: let c = ChildClass[string].new("Base", "Child") - assert c.baseMethod == "Base" - assert c.overriddenMethod == "Child" + doAssert c.baseMethod == "Base" + doAssert c.overriddenMethod == "Child" @@ -128,7 +128,7 @@ block t1789: bar: array[N, T] proc `[]`[N, T](f: Bar[N, T], n: range[0..(N - 1)]): T = - assert high(n) == N-1 + doAssert high(n) == N-1 result = f.bar[n] var b: Bar[3, int] @@ -734,7 +734,7 @@ block t1684: proc newDerived(idx: int): DerivedType {.inline.} = DerivedType(idx: idx) let d = newDerived(2) - assert(d.index == 2) + doAssert(d.index == 2) @@ -774,13 +774,13 @@ block: # issue #9458 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) = + proc foo[T](self: T; x: Option[Bar] = Bar.none) = discard foo(1) @@ -834,7 +834,7 @@ proc getBar(x: string): Bar = Bar(foo: none[seq[Foo]](), s: "") -proc fakeReadLine(): TaintedString = "hey" +proc fakeReadLine(): string = "hey" echo getBar(fakeReadLine()) # causes error diff --git a/tests/generics/tgenerics_various.nim b/tests/generics/tgenerics_various.nim index 22d3cff7ad..285108cd3e 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: - assert type(x1.x) is int - assert type(x1.y) is float - assert type(x1.z) is int + doAssert type(x1.x) is int + doAssert type(x1.y) is float + doAssert type(x1.z) is int var x2: TFoo[string, R = float, U = seq[int]] static: - assert type(x2.x) is string - assert type(x2.y) is seq[int] - assert type(x2.z) is float + doAssert type(x2.x) is string + doAssert type(x2.y) is seq[int] + doAssert type(x2.z) is float var x3: TBar[float] static: - assert type(x3.x) is float - assert type(x3.y) is array[4, float] - assert type(x3.z) is float + doAssert type(x3.x) is float + doAssert type(x3.y) is array[4, float] + doAssert type(x3.z) is float @@ -150,31 +150,31 @@ block tsharedcases: doAssert high(f2.data2) == 3 # int8.len - 1 == 3 static: - assert high(f1.data1) == ord(C) - assert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high + doAssert high(f1.data1) == ord(C) + doAssert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high - assert high(f2.data1) == 126 - assert high(f2.data2) == 3 + doAssert high(f2.data1) == 126 + doAssert high(f2.data2) == 3 - assert high(f1.data3) == 6 # length of MyEnum - assert high(f2.data3) == 4 # length of int8 + doAssert high(f1.data3) == 6 # length of MyEnum + doAssert high(f2.data3) == 4 # length of int8 - assert f2.data3[0] is float + doAssert f2.data3[0] is float block tmap_auto: let x = map(@[1, 2, 3], x => x+10) - assert x == @[11, 12, 13] + doAssert x == @[11, 12, 13] let y = map(@[(1,"a"), (2,"b"), (3,"c")], x => $x[0] & x[1]) - assert y == @["1a", "2b", "3c"] + doAssert 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) - assert z == "1a" + doAssert z == "1a" diff --git a/tests/generics/tnullary_generics.nim b/tests/generics/tnullary_generics.nim new file mode 100644 index 0000000000..c79558ee3d --- /dev/null +++ b/tests/generics/tnullary_generics.nim @@ -0,0 +1,26 @@ +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/tparser_generator.nim b/tests/generics/tparser_generator.nim index 8f8fea3820..ac921c0e5d 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 - assert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) + doAssert(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 - assert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) + doAssert(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 - assert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)]) + doAssert(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]]() - assert(not isNil(left.parser), "Left hand side parser is nil") + doAssert(not isNil(left.parser), "Left hand side parser is nil") let leftlength = left.parser(text, start, mynodes) if leftlength == -1: return leftlength - assert(not isNil(right.parser), "Right hand side parser is nil") + doAssert(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]]() - assert(not isNil(left.parser), "Left hand side of / is not fully defined") + doAssert(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]]() - assert(not isNil(right.parser), "Right hand side of / is not fully defined") + doAssert(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) = - assert(not isnil(production.parser), "Right hand side of -> is nil - has the rule been defined yet?") + doAssert(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/iter/t1550.nim b/tests/iter/t1550.nim new file mode 100644 index 0000000000..8ad96f0dac --- /dev/null +++ b/tests/iter/t1550.nim @@ -0,0 +1,20 @@ +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/tclosureiters.nim b/tests/iter/tclosureiters.nim index 0ee8e81cc6..afeaabc7d7 100644 --- a/tests/iter/tclosureiters.nim +++ b/tests/iter/tclosureiters.nim @@ -98,7 +98,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 = TaintedString(newStringOfCap(80)) + var res = newStringOfCap(80) while f.readLine(res): yield res proc unusedB = diff --git a/tests/js/readme.md b/tests/js/readme.md new file mode 100644 index 0000000000..7fcc722fa2 --- /dev/null +++ b/tests/js/readme.md @@ -0,0 +1,5 @@ +## 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 8dd77925cf..e98ccda10c 100644 --- a/tests/js/t11166.nim +++ b/tests/js/t11166.nim @@ -1,4 +1,20 @@ +discard """ + output: ''' +test1 +test2 +''' +""" + import jsffi +type + C = object + props: int + +var c: C + when compiles(c.props): - echo "test" + echo "test1" + +when not compiles(d.props): + echo "test2" diff --git a/tests/js/t17177.nim b/tests/js/t17177.nim new file mode 100644 index 0000000000..fc362cec1b --- /dev/null +++ b/tests/js/t17177.nim @@ -0,0 +1,10 @@ +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/tasync.nim b/tests/js/tasync.nim deleted file mode 100644 index 3182376519..0000000000 --- a/tests/js/tasync.nim +++ /dev/null @@ -1,33 +0,0 @@ -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.nim b/tests/js/tasyncjs.nim new file mode 100644 index 0000000000..00753a16c8 --- /dev/null +++ b/tests/js/tasyncjs.nim @@ -0,0 +1,97 @@ +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` + +discard main() diff --git a/tests/js/tasyncjs_bad.nim b/tests/js/tasyncjs_bad.nim new file mode 100644 index 0000000000..b1e5a7bc33 --- /dev/null +++ b/tests/js/tasyncjs_bad.nim @@ -0,0 +1,22 @@ +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/tasync_pragma.nim b/tests/js/tasyncjs_pragma.nim similarity index 93% rename from tests/js/tasync_pragma.nim rename to tests/js/tasyncjs_pragma.nim index 916769fadc..2b6f32e92b 100644 --- a/tests/js/tasync_pragma.nim +++ b/tests/js/tasyncjs_pragma.nim @@ -5,6 +5,8 @@ t ''' """ +# xxx merge into tasyncjs.nim + import asyncjs, macros macro f*(a: untyped): untyped = diff --git a/tests/js/tbigint_backend.nim b/tests/js/tbigint_backend.nim new file mode 100644 index 0000000000..8f2f6c4f49 --- /dev/null +++ b/tests/js/tbigint_backend.nim @@ -0,0 +1,57 @@ +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/tclosures.nim b/tests/js/tclosures.nim index 3137123bf8..4f1c28de3f 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/tjsffi.nim b/tests/js/tjsffi.nim index 143ac4a253..06a30c44df 100644 --- a/tests/js/tjsffi.nim +++ b/tests/js/tjsffi.nim @@ -1,291 +1,196 @@ 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 -# 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 + 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 - 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 .= 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 .() -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.`?!$` = 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.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() +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 Iterators -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: # 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"] -# 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 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 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() +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 # Tests for JsAssoc -# 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[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[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 .= 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 .() -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 + 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 - let call = obj["a"] - call(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 Iterators -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: # 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"] -# 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 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 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() +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" }) # Tests for macros on non-JsRoot objects -# Test lit -block: +block: # Test lit type TestObject = object a: int b: cstring - proc test(): bool = - {. emit: "var comparison = {a: 1};" .} - var comparison {. importjs, nodecl .}: TestObject - let obj = TestObject{ a: 1 } - obj == comparison - echo test() + {. emit: "var comparison = {a: 1};" .} + var comparison {. importjs, nodecl .}: TestObject + let obj = TestObject{ a: 1 } + doAssert obj == comparison -# Test bindMethod -block: +block: # Test bindMethod type TestObject = object a: int onWhatever: proc(e: int): int proc handleWhatever(this: TestObject, e: int): int = e + this.a - proc test(): bool = + block: let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever)) - obj.onWhatever(1) == 10 - echo test() + doAssert obj.onWhatever(1) == 10 block: {.emit: "function jsProc(n) { return n; }" .} proc jsProc(x: int32): JsObject {.importjs: "jsProc(#)".} - - proc test() = + block: var x = jsProc(1) var y = jsProc(2) console.log x + y @@ -294,8 +199,6 @@ block: x += jsProc(10) console.log x - test() - block: {.emit: """ @@ -323,13 +226,13 @@ block: console.log jsarguments[0] block: - echo jsUndefined == jsNull - echo jsUndefined == nil - echo jsNull == nil - echo jsUndefined.isNil - echo jsNull.isNil - echo jsNull.isNull - echo jsUndefined.isUndefined + 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) @@ -362,4 +265,3 @@ block: # test ** doAssert to(`**`(a + a, b), int) == 2 doAssert to(`**`(toJs(1) + toJs(1), toJs(2)), int) == 4 - diff --git a/tests/js/tjsffi_old.nim b/tests/js/tjsffi_old.nim index 1f149694b4..078d208c5f 100644 --- a/tests/js/tjsffi_old.nim +++ b/tests/js/tjsffi_old.nim @@ -35,6 +35,9 @@ 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 diff --git a/tests/js/tnilstrs.nim b/tests/js/tnilstrs.nim index c0048cb240..6c1e4e4016 100644 --- a/tests/js/tnilstrs.nim +++ b/tests/js/tnilstrs.nim @@ -14,4 +14,12 @@ block: var x = "foo".cstring var y: string add(y, x) - doAssert y == "foo" \ No newline at end of file + 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" diff --git a/tests/js/tseqops.nim b/tests/js/tseqops.nim index af664222cc..8cfb508863 100644 --- a/tests/js/tseqops.nim +++ b/tests/js/tseqops.nim @@ -1,11 +1,3 @@ -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 @@ -17,8 +9,8 @@ proc onLoad() = var foo = TestO(x: 0, y: 0) test.add(foo) foo.x = 5 - echo(test[0]) - echo foo + doAssert $test[0] == "(x: 0, y: 0)" + doAssert $foo == "(x: 5, y: 0)" onLoad() @@ -34,7 +26,7 @@ proc foo(x: var seq[MyObj]) = var s = @[MyObj(x: "2", y: 4), MyObj(x: "4", y: 5)] foo(s) -echo s +doAssert $s == """@[(x: "2", y: 4), (x: "4", y: 5), (x: "4", y: 5)]""" # bug #5933 import sequtils @@ -48,4 +40,9 @@ var test = @[Test(a: "1", b: 1), Test(a: "2", b: 2)] test.insert(@[Test(a: "3", b: 3)], 0) -echo test +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] diff --git a/tests/js/tstdlib_imports.nim b/tests/js/tstdlib_imports.nim index 7611b7dcb9..6fe3772d37 100644 --- a/tests/js/tstdlib_imports.nim +++ b/tests/js/tstdlib_imports.nim @@ -46,7 +46,7 @@ import std/[ # Parsers: htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, - # fails: parseopt + parseopt, # XML processing: xmltree, xmlparser, diff --git a/tests/js/tstdlib_various.nim b/tests/js/tstdlib_various.nim index d19f40c39c..a1bb63d46e 100644 --- a/tests/js/tstdlib_various.nim +++ b/tests/js/tstdlib_various.nim @@ -29,7 +29,7 @@ Hi Andreas! How do you feel, Rumpf? """ import - critbits, cstrutils, sets, strutils, tables, random, algorithm, ropes, + critbits, sets, strutils, tables, random, algorithm, ropes, lists, htmlgen, xmltree, strtabs @@ -177,18 +177,3 @@ block txmltree: ]) ]) doAssert(y.innerText == "foobar") - - - -block tcstrutils: - let s = cstring "abcdef" - doAssert s.startsWith("a") - doAssert not s.startsWith("b") - doAssert s.endsWith("f") - doAssert not s.endsWith("a") - - let a = cstring "abracadabra" - doAssert a.startsWith("abra") - doAssert not a.startsWith("bra") - doAssert a.endsWith("abra") - doAssert not a.endsWith("dab") diff --git a/tests/js/ttypedarray.nim b/tests/js/ttypedarray.nim new file mode 100644 index 0000000000..222f665697 --- /dev/null +++ b/tests/js/ttypedarray.nim @@ -0,0 +1,21 @@ +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/tunittest_error2.nim b/tests/js/tunittest_error2.nim new file mode 100644 index 0000000000..273e39d9d4 --- /dev/null +++ b/tests/js/tunittest_error2.nim @@ -0,0 +1,16 @@ +discard """ + exitcode: 1 + outputsub: ''' +Unhandled exception: Cannot read property 'charCodeAt' of null [] +[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/lexer/tintegerliterals.nim b/tests/lexer/tintegerliterals.nim index 7420db144d..fd401b71b0 100644 --- a/tests/lexer/tintegerliterals.nim +++ b/tests/lexer/tintegerliterals.nim @@ -1,9 +1,9 @@ # test the valid literals -assert 0b10 == 2 -assert 0B10 == 2 -assert 0x10 == 16 -assert 0X10 == 16 -assert 0o10 == 8 +doAssert 0b10 == 2 +doAssert 0B10 == 2 +doAssert 0x10 == 16 +doAssert 0X10 == 16 +doAssert 0o10 == 8 # the following is deprecated: -assert 0c10 == 8 -assert 0C10 == 8 +doAssert 0c10 == 8 +doAssert 0C10 == 8 diff --git a/tests/m14634.nim b/tests/m14634.nim index 56a3d9034e..f19f02f0c7 100644 --- a/tests/m14634.nim +++ b/tests/m14634.nim @@ -20,7 +20,7 @@ when not defined(windows): # the test fails. var rc1 = selector.select(t) var rc2 = selector.select(t) - assert len(rc1) <= 1 and len(rc2) <= 1 + doAssert len(rc1) <= 1 and len(rc2) <= 1 data.s1 += ord(len(rc1) == 1) data.s2 += ord(len(rc2) == 1) selector.unregister(timer) @@ -32,9 +32,9 @@ when not defined(windows): # this can't be too large as it'll actually wait that long: # timer_notification_test.n * t2 var rc5 = selector.select(t2) - assert len(rc4) + len(rc5) <= 1 + doAssert len(rc4) + len(rc5) <= 1 data.s3 += ord(len(rc4) + len(rc5) == 1) - assert(selector.isEmpty()) + doAssert(selector.isEmpty()) selector.close() proc timerNotificationTest() = diff --git a/tests/macros/tcasestmtmacro.nim b/tests/macros/tcasestmtmacro.nim new file mode 100644 index 0000000000..26519f637c --- /dev/null +++ b/tests/macros/tcasestmtmacro.nim @@ -0,0 +1,35 @@ +discard """ + output: ''' +yes +''' +""" + +{.experimental: "caseStmtMacros".} + +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 2a7847b9ec..44c2411a57 100644 --- a/tests/macros/tclosuremacro.nim +++ b/tests/macros/tclosuremacro.nim @@ -5,8 +5,6 @@ calling mystuff yes calling mystuff yes -calling sugarWithPragma -sugarWithPragma called ''' """ @@ -40,7 +38,7 @@ proc pass2(f: (int, int) -> int): (int) -> int = doAssert pass2((x, y) => x + y)(4) == 6 -fun(x, y: int) {.noSideEffect.} => x + y +const fun = (x, y: int) {.noSideEffect.} => x + y doAssert typeof(fun) is (proc (x, y: int): int {.nimcall.}) doAssert fun(3, 4) == 7 @@ -70,9 +68,7 @@ m: proc mystuff() = echo "yes" -sugarWithPragma() {.m.} => echo "sugarWithPragma called" - -typedParamAndPragma(x, y: int) {.used.} -> int => x + y +const typedParamAndPragma = (x, y: int) -> int => x + y doAssert typedParamAndPragma(1, 2) == 3 type @@ -82,5 +78,3 @@ type var myBot = Bot() myBot.call = () {.noSideEffect.} => "I'm a bot." doAssert myBot.call() == "I'm a bot." - - diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim index b9788a81d0..e2c1b0a045 100644 --- a/tests/manyloc/argument_parser/argument_parser.nim +++ b/tests/manyloc/argument_parser/argument_parser.nim @@ -225,7 +225,7 @@ template raise_or_quit(exception, message: untyped) = template run_custom_proc(parsed_parameter: Tparsed_parameter, custom_validator: Tparameter_callback, - parameter: TaintedString) = + parameter: string) = ## Runs the custom validator if it is not nil. ## ## Pass in the string of the parameter triggering the call. If the @@ -318,7 +318,7 @@ proc echo_help*(expected: seq[Tparameter_specification] = @[], proc parse*(expected: seq[Tparameter_specification] = @[], - type_of_positional_parameters = PK_STRING, args: seq[TaintedString] = @[], + type_of_positional_parameters = PK_STRING, args: seq[string] = @[], bad_prefixes = @["-", "--"], end_of_options = "--", quit_on_failure = true): Tcommandline_results = ## Parses parameters and returns results. diff --git a/tests/manyloc/keineschweine/dependencies/enet/enet.nim b/tests/manyloc/keineschweine/dependencies/enet/enet.nim index 02ebef5956..5dee6ae9c7 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 ad0d20f1c6..a0c8a7a3c2 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'): TaintedString = +proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): string = 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): TaintedString = +proc readLEStr*(s: PStream): string = 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 bc380986f1..e466ee5e1f 100644 --- a/tests/manyloc/keineschweine/dependencies/nake/nake.nim +++ b/tests/manyloc/keineschweine/dependencies/nake/nake.nim @@ -7,6 +7,10 @@ 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 @@ -60,7 +64,8 @@ when true: args.add " " quit(shell("nim", "c", "-r", "nakefile.nim", args)) else: - addQuitProc(proc() {.noconv.} = + import std/exitprocs + addExitProc(proc() {.noconv.} = var task: string printTaskList: bool diff --git a/tests/manyloc/keineschweine/keineschweine.nim.cfg b/tests/manyloc/keineschweine/keineschweine.nim.cfg index f335a0e0e3..ca6c75f6ed 100644 --- a/tests/manyloc/keineschweine/keineschweine.nim.cfg +++ b/tests/manyloc/keineschweine/keineschweine.nim.cfg @@ -7,4 +7,3 @@ path = "dependencies/genpacket" path = "enet_server" debugger = off warning[SmallLshouldNotBeUsed] = off -nilseqs = on diff --git a/tests/manyloc/keineschweine/lib/glut.nim b/tests/manyloc/keineschweine/lib/glut.nim index 44a2907286..de9a974563 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/zlib_helpers.nim b/tests/manyloc/keineschweine/lib/zlib_helpers.nim index 895f41759b..e51c000c88 100644 --- a/tests/manyloc/keineschweine/lib/zlib_helpers.nim +++ b/tests/manyloc/keineschweine/lib/zlib_helpers.nim @@ -1,21 +1,26 @@ +# 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 - var res = zlib.compress(cstring(result), addr destLen, cstring(source), sourceLen) + # 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) if res != Z_OK: echo "Error occurred: ", res - elif destLen < result.len: - result.setLen(destLen) + elif destLen2.int < result.len: + result.setLen(destLen2.int) proc uncompress*(source: string, destLen: var int): string = result = "" result.setLen destLen - var res = zlib.uncompress(cstring(result), addr destLen, cstring(source), source.len) + var destLen2 = destLen.Ulongf + var res = zlib.uncompress(cstring(result), addr destLen2, cstring(source), source.len.Ulong) if res != Z_OK: echo "Error occurred: ", res diff --git a/tests/manyloc/nake/nake.nim b/tests/manyloc/nake/nake.nim index 87db5b54d5..ce7faab5cc 100644 --- a/tests/manyloc/nake/nake.nim +++ b/tests/manyloc/nake/nake.nim @@ -60,7 +60,8 @@ when true: args.add " " quit(shell("nim", "c", "-r", "nakefile.nim", args)) else: - addQuitProc(proc() {.noconv.} = + import std/exitprocs + addExitProc(proc() {.noconv.} = var task: string printTaskList: bool diff --git a/tests/manyloc/standalone/panicoverride.nim b/tests/manyloc/standalone/panicoverride.nim index d9b3f43886..c0b8bb030e 100644 --- a/tests/manyloc/standalone/panicoverride.nim +++ b/tests/manyloc/standalone/panicoverride.nim @@ -11,9 +11,4 @@ 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 new file mode 100644 index 0000000000..c0b8bb030e --- /dev/null +++ b/tests/manyloc/standalone2/panicoverride.nim @@ -0,0 +1,14 @@ + +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 new file mode 100644 index 0000000000..6cbc5c6990 --- /dev/null +++ b/tests/manyloc/standalone2/tavr.nim @@ -0,0 +1,7 @@ +# 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 new file mode 100644 index 0000000000..e5291969dd --- /dev/null +++ b/tests/manyloc/standalone2/tavr.nim.cfg @@ -0,0 +1,4 @@ +--gc:arc +--cpu:avr +--os:standalone +--compileOnly diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim index 326faac82d..3ff5c5ea66 100644 --- a/tests/metatype/ttypetraits.nim +++ b/tests/metatype/ttypetraits.nim @@ -90,6 +90,8 @@ block distinctBase: Foo[T] = distinct seq[T] var a: Foo[int] doAssert a.type.distinctBase is seq[int] + doAssert seq[int].distinctBase is seq[int] + doAssert "abc".distinctBase == "abc" block: # simplified from https://github.com/nim-lang/Nim/pull/8531#issuecomment-410436458 @@ -282,7 +284,12 @@ block genericHead: doAssert not compiles(genericHead(Foo)) type Bar = object doAssert not compiles(genericHead(Bar)) - # doAssert seq[int].genericHead is seq + + when false: # xxx not supported yet + doAssert seq[int].genericHead is seq + when false: # xxx not supported yet, gives: Error: identifier expected + type Hoo[T] = object + doAssert genericHead(Hoo[int])[float] is Hoo[float] block: # elementType iterator myiter(n: int): auto = diff --git a/tests/metatype/twildtypedesc.nim b/tests/metatype/twildtypedesc.nim index 268bff0d8b..d1c5ffba55 100644 --- a/tests/metatype/twildtypedesc.nim +++ b/tests/metatype/twildtypedesc.nim @@ -17,8 +17,8 @@ proc unpack[T](v: string): T = var s = "123" -assert(unpack[string](s) is string) -assert(unpack[int](s) is int) +doAssert(unpack[string](s) is string) +doAssert(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 -assert unit(int) == 0 -assert unit(string) == "" -assert unit(float) == 0.0 +doAssert unit(int) == 0 +doAssert unit(string) == "" +doAssert unit(float) == 0.0 diff --git a/tests/metatype/typedesc_as_value.nim b/tests/metatype/typedesc_as_value.nim index 69eaf8a5ca..463d237248 100644 --- a/tests/metatype/typedesc_as_value.nim +++ b/tests/metatype/typedesc_as_value.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "invalid type: 'type int' for var" + errormsg: "invalid type: 'typedesc[int]' for var" """ diff --git a/tests/metatype/utypeclasses.nim b/tests/metatype/utypeclasses.nim index 06bab375e9..f94b397425 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 -test "if proc param types are not supplied, the params are assumed to be generic": +block: # 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" -test "explicit param types can still be specified": +block: # explicit param types can still be specified check concat[cstring, cstring]("x", "y") == "xy" diff --git a/tests/method/tmethod_issues.nim b/tests/method/tmethod_issues.nim index 80f54caee1..df4c3771af 100644 --- a/tests/method/tmethod_issues.nim +++ b/tests/method/tmethod_issues.nim @@ -2,6 +2,8 @@ discard """ output: ''' wof! wof! +type A +type B ''' """ @@ -126,3 +128,34 @@ 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() + diff --git a/tests/misc/mspellsuggest.nim b/tests/misc/mspellsuggest.nim new file mode 100644 index 0000000000..ad449554fe --- /dev/null +++ b/tests/misc/mspellsuggest.nim @@ -0,0 +1,7 @@ +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 new file mode 100644 index 0000000000..992977acd8 --- /dev/null +++ b/tests/misc/mtlsemulation.h @@ -0,0 +1,37 @@ +#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/t8545.nim b/tests/misc/t8545.nim new file mode 100644 index 0000000000..89957e1d31 --- /dev/null +++ b/tests/misc/t8545.nim @@ -0,0 +1,23 @@ +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/tapp_lib_staticlib.nim b/tests/misc/tapp_lib_staticlib.nim new file mode 100644 index 0000000000..92c9acbc30 --- /dev/null +++ b/tests/misc/tapp_lib_staticlib.nim @@ -0,0 +1,27 @@ +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/tproveinit.nim b/tests/misc/tproveinit.nim new file mode 100644 index 0000000000..c9f6883090 --- /dev/null +++ b/tests/misc/tproveinit.nim @@ -0,0 +1,18 @@ +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/trunner.nim b/tests/misc/trunner.nim index e288a56c7a..a66177f28b 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -7,20 +7,25 @@ discard """ ## 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. -import std/[strformat,os,osproc,unittest] +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 + defaultHintsOff = "--hint:successx:off --hint:exec:off --hint:link:off --hint:cc:off --hint:conf:off --hint:processing:off --hint:QuitCalled:off" + # useful when you want to turn only some hints on, and some common ones off. + # pending https://github.com/timotheecour/Nim/issues/453, simplify to: `--hints:off` nim = getCurrentCompilerExe() - mode = - when defined(c): "c" - elif defined(cpp): "cpp" - else: static: doAssert false + mode = querySetting(backend) nimcache = buildDir / "nimcacheTrunner" # instead of `querySetting(nimcacheDir)`, avoids stomping on other parallel tests @@ -93,10 +98,9 @@ else: # don't run twice the same test check exitCode == 0 let ret = toSeq(walkDirRec(htmldocsDir, relative=true)).mapIt(it.nativeToUnixPath).sorted.join("\n") let context = $(i, ret, cmd) - var expected = "" case i of 0,5: - let htmlFile = htmldocsDir/"mmain.html" + let htmlFile = htmldocsDir/mainFname check htmlFile in outp # sanity check for `hintSuccessX` assertEquals ret, fmt""" {dotdotMangle}/imp.html @@ -106,7 +110,7 @@ imp.html imp.idx imp2.html imp2.idx -mmain.html +{mainFname} mmain.idx {nimdocOutCss} {theindexFname}""", context @@ -119,21 +123,21 @@ tests/nimdoc/sub/imp.html tests/nimdoc/sub/imp.idx tests/nimdoc/sub/imp2.html tests/nimdoc/sub/imp2.idx -tests/nimdoc/sub/mmain.html +tests/nimdoc/sub/{mainFname} tests/nimdoc/sub/mmain.idx {theindexFname}""" of 2, 3: assertEquals ret, fmt""" {docHackJsFname} -mmain.html +{mainFname} mmain.idx {nimdocOutCss}""", context of 4: assertEquals ret, fmt""" {docHackJsFname} {nimdocOutCss} -sub/mmain.html +sub/{mainFname} sub/mmain.idx""", context of 6: assertEquals ret, fmt""" -mmain.html +{mainFname} {nimdocOutCss}""", context else: doAssert false @@ -217,8 +221,66 @@ mmain.html let cmd = fmt"{nim} r -b:cpp --hints:off --nimcache:{nimcache} --warningAsError:ProveInit {file}" check execCmdEx(cmd) == ("witness\n", 0) + block: # config.nims, nim.cfg, hintConf, bug #16557 + let cmd = fmt"{nim} r {defaultHintsOff} --hint:conf tests/newconfig/bar/mfoo.nim" + let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) + doAssert exitCode == 0 + let dir = getCurrentDir() + let files = """ +tests/config.nims +tests/newconfig/bar/nim.cfg +tests/newconfig/bar/config.nims +tests/newconfig/bar/mfoo.nim.cfg +tests/newconfig/bar/mfoo.nims""".splitLines + var expected = "" + for a in files: + let b = dir / a + expected.add &"Hint: used config file '{b}' [Conf]\n" + doAssert outp.endsWith expected, outp & "\n" & expected + block: # nim --eval let opt = "--hints:off" check fmt"""{nim} {opt} --eval:"echo defined(nimscript)"""".execCmdEx == ("true\n", 0) check fmt"""{nim} r {opt} --eval:"echo defined(c)"""".execCmdEx == ("true\n", 0) check fmt"""{nim} r -b:js {opt} --eval:"echo defined(js)"""".execCmdEx == ("true\n", 0) + + block: # `hintProcessing` dots should not interfere with `static: echo` + friends + let cmd = fmt"""{nim} r {defaultHintsOff} --hint:processing -f --eval:"static: echo 1+1"""" + let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut}) + template check3(cond) = doAssert cond, $(outp,) + doAssert exitCode == 0 + let lines = outp.splitLines + check3 lines.len == 3 + when not defined(windows): # xxx: on windows, dots not properly handled, gives: `....2\n\n` + check3 lines[0].isDots + check3 lines[1] == "2" + check3 lines[2] == "" + else: + check3 "2" in outp + + block: # nim secret + let opt = fmt"{defaultHintsOff} --hint:processing" + template check3(cond) = doAssert cond, $(outp,) + for extra in ["", "--stdout"]: + let cmd = fmt"""{nim} secret {opt} {extra}""" + # xxx minor bug: `nim --hint:QuitCalled:off secret` ignores the hint cmdline flag + template run(input2): untyped = + execCmdEx(cmd, options = {poStdErrToStdOut}, input = input2) + block: + let (outp, exitCode) = run """echo 1+2; import strutils; echo strip(" ab "); quit()""" + let lines = outp.splitLines + when not defined(windows): + check3 lines.len == 5 + check3 lines[0].isDots + check3 lines[1].dup(removePrefix(">>> ")) == "3" # prompt depends on `nimUseLinenoise` + check3 lines[2].isDots + 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 diff --git a/tests/misc/trunner_special.nim b/tests/misc/trunner_special.nim new file mode 100644 index 0000000000..47ba44a296 --- /dev/null +++ b/tests/misc/trunner_special.nim @@ -0,0 +1,31 @@ +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 {testsDir}/untestable/thttpclient_ssl_remotenetwork.nim" + +main() diff --git a/tests/misc/tspellsuggest.nim b/tests/misc/tspellsuggest.nim new file mode 100644 index 0000000000..033ed0afc8 --- /dev/null +++ b/tests/misc/tspellsuggest.nim @@ -0,0 +1,45 @@ +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' [var declared in tspellsuggest.nim(43, 9)] + (1, 1): 'fooBar7' [var declared in tspellsuggest.nim(41, 7)] + (1, 3): 'fooBar1' [var declared in tspellsuggest.nim(33, 5)] + (1, 3): 'fooBar2' [let declared in tspellsuggest.nim(34, 5)] + (1, 3): 'fooBar3' [const declared in tspellsuggest.nim(35, 7)] + (1, 3): 'fooBar4' [proc declared in tspellsuggest.nim(36, 6)] + (1, 3): 'fooBar5' [template declared in tspellsuggest.nim(37, 10)] + (1, 3): 'fooBar6' [macro declared in tspellsuggest.nim(38, 7)] + (1, 5): 'FooBar' [type declared in mspellsuggest.nim(5, 6)] + (1, 5): 'fooBar4' [proc declared in mspellsuggest.nim(1, 6)] + (1, 5): 'fooBar9' [var declared in mspellsuggest.nim(2, 5)] + (1, 5): 'fooCar' [var declared in mspellsuggest.nim(4, 5)] + (2, 5): 'FooCar' [type declared in mspellsuggest.nim(6, 6)] + (2, 5): 'GooBa' [type declared in mspellsuggest.nim(7, 6)] + (3, 0): 'fooBarBaz' [const declared in tspellsuggest.nim(44, 11)] +''' +""" + +# 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 new file mode 100644 index 0000000000..78504c513f --- /dev/null +++ b/tests/misc/tspellsuggest2.nim @@ -0,0 +1,45 @@ +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' [var declared in tspellsuggest2.nim(43, 9)] + (1, 1): 'fooBar7' [var declared in tspellsuggest2.nim(41, 7)] + (1, 3): 'fooBar1' [var declared in tspellsuggest2.nim(33, 5)] + (1, 3): 'fooBar2' [let declared in tspellsuggest2.nim(34, 5)] + (1, 3): 'fooBar3' [const declared in tspellsuggest2.nim(35, 7)] + (1, 3): 'fooBar4' [proc declared in tspellsuggest2.nim(36, 6)] + (1, 3): 'fooBar5' [template declared in tspellsuggest2.nim(37, 10)] + (1, 3): 'fooBar6' [macro declared in tspellsuggest2.nim(38, 7)] + (1, 5): 'FooBar' [type declared in mspellsuggest.nim(5, 6)] + (1, 5): 'fooBar4' [proc declared in mspellsuggest.nim(1, 6)] + (1, 5): 'fooBar9' [var declared in mspellsuggest.nim(2, 5)] + (1, 5): 'fooCar' [var declared in mspellsuggest.nim(4, 5)] +''' +""" + +# 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/ttlsemulation.nim b/tests/misc/ttlsemulation.nim new file mode 100644 index 0000000000..47c5934e66 --- /dev/null +++ b/tests/misc/ttlsemulation.nim @@ -0,0 +1,75 @@ +discard """ + 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 19c8876b12..970c4ae9de 100644 --- a/tests/misc/tunsignedcomp.nim +++ b/tests/misc/tunsignedcomp.nim @@ -10,127 +10,127 @@ discard """ # unsigned < signed -assert 10'u8 < 20'i8 -assert 10'u8 < 20'i16 -assert 10'u8 < 20'i32 -assert 10'u8 < 20'i64 +doAssert 10'u8 < 20'i8 +doAssert 10'u8 < 20'i16 +doAssert 10'u8 < 20'i32 +doAssert 10'u8 < 20'i64 -assert 10'u16 < 20'i8 -assert 10'u16 < 20'i16 -assert 10'u16 < 20'i32 -assert 10'u16 < 20'i64 +doAssert 10'u16 < 20'i8 +doAssert 10'u16 < 20'i16 +doAssert 10'u16 < 20'i32 +doAssert 10'u16 < 20'i64 -assert 10'u32 < 20'i8 -assert 10'u32 < 20'i16 -assert 10'u32 < 20'i32 -assert 10'u32 < 20'i64 +doAssert 10'u32 < 20'i8 +doAssert 10'u32 < 20'i16 +doAssert 10'u32 < 20'i32 +doAssert 10'u32 < 20'i64 -# assert 10'u64 < 20'i8 -# assert 10'u64 < 20'i16 -# assert 10'u64 < 20'i32 -# assert 10'u64 < 20'i64 +# doAssert 10'u64 < 20'i8 +# doAssert 10'u64 < 20'i16 +# doAssert 10'u64 < 20'i32 +# doAssert 10'u64 < 20'i64 # signed < unsigned -assert 10'i8 < 20'u8 -assert 10'i8 < 20'u16 -assert 10'i8 < 20'u32 -# assert 10'i8 < 20'u64 +doAssert 10'i8 < 20'u8 +doAssert 10'i8 < 20'u16 +doAssert 10'i8 < 20'u32 +# doAssert 10'i8 < 20'u64 -assert 10'i16 < 20'u8 -assert 10'i16 < 20'u16 -assert 10'i16 < 20'u32 -# assert 10'i16 < 20'u64 +doAssert 10'i16 < 20'u8 +doAssert 10'i16 < 20'u16 +doAssert 10'i16 < 20'u32 +# doAssert 10'i16 < 20'u64 -assert 10'i32 < 20'u8 -assert 10'i32 < 20'u16 -assert 10'i32 < 20'u32 -# assert 10'i32 < 20'u64 +doAssert 10'i32 < 20'u8 +doAssert 10'i32 < 20'u16 +doAssert 10'i32 < 20'u32 +# doAssert 10'i32 < 20'u64 -assert 10'i64 < 20'u8 -assert 10'i64 < 20'u16 -assert 10'i64 < 20'u32 -# assert 10'i64 < 20'u64 +doAssert 10'i64 < 20'u8 +doAssert 10'i64 < 20'u16 +doAssert 10'i64 < 20'u32 +# doAssert 10'i64 < 20'u64 # unsigned <= signed -assert 10'u8 <= 20'i8 -assert 10'u8 <= 20'i16 -assert 10'u8 <= 20'i32 -assert 10'u8 <= 20'i64 +doAssert 10'u8 <= 20'i8 +doAssert 10'u8 <= 20'i16 +doAssert 10'u8 <= 20'i32 +doAssert 10'u8 <= 20'i64 -assert 10'u16 <= 20'i8 -assert 10'u16 <= 20'i16 -assert 10'u16 <= 20'i32 -assert 10'u16 <= 20'i64 +doAssert 10'u16 <= 20'i8 +doAssert 10'u16 <= 20'i16 +doAssert 10'u16 <= 20'i32 +doAssert 10'u16 <= 20'i64 -assert 10'u32 <= 20'i8 -assert 10'u32 <= 20'i16 -assert 10'u32 <= 20'i32 -assert 10'u32 <= 20'i64 +doAssert 10'u32 <= 20'i8 +doAssert 10'u32 <= 20'i16 +doAssert 10'u32 <= 20'i32 +doAssert 10'u32 <= 20'i64 -# assert 10'u64 <= 20'i8 -# assert 10'u64 <= 20'i16 -# assert 10'u64 <= 20'i32 -# assert 10'u64 <= 20'i64 +# doAssert 10'u64 <= 20'i8 +# doAssert 10'u64 <= 20'i16 +# doAssert 10'u64 <= 20'i32 +# doAssert 10'u64 <= 20'i64 # signed <= unsigned -assert 10'i8 <= 20'u8 -assert 10'i8 <= 20'u16 -assert 10'i8 <= 20'u32 -# assert 10'i8 <= 20'u64 +doAssert 10'i8 <= 20'u8 +doAssert 10'i8 <= 20'u16 +doAssert 10'i8 <= 20'u32 +# doAssert 10'i8 <= 20'u64 -assert 10'i16 <= 20'u8 -assert 10'i16 <= 20'u16 -assert 10'i16 <= 20'u32 -# assert 10'i16 <= 20'u64 +doAssert 10'i16 <= 20'u8 +doAssert 10'i16 <= 20'u16 +doAssert 10'i16 <= 20'u32 +# doAssert 10'i16 <= 20'u64 -assert 10'i32 <= 20'u8 -assert 10'i32 <= 20'u16 -assert 10'i32 <= 20'u32 -# assert 10'i32 <= 20'u64 +doAssert 10'i32 <= 20'u8 +doAssert 10'i32 <= 20'u16 +doAssert 10'i32 <= 20'u32 +# doAssert 10'i32 <= 20'u64 -assert 10'i64 <= 20'u8 -assert 10'i64 <= 20'u16 -assert 10'i64 <= 20'u32 -# assert 10'i64 <= 20'u64 +doAssert 10'i64 <= 20'u8 +doAssert 10'i64 <= 20'u16 +doAssert 10'i64 <= 20'u32 +# doAssert 10'i64 <= 20'u64 # signed == unsigned -assert 10'i8 == 10'u8 -assert 10'i8 == 10'u16 -assert 10'i8 == 10'u32 -# assert 10'i8 == 10'u64 +doAssert 10'i8 == 10'u8 +doAssert 10'i8 == 10'u16 +doAssert 10'i8 == 10'u32 +# doAssert 10'i8 == 10'u64 -assert 10'i16 == 10'u8 -assert 10'i16 == 10'u16 -assert 10'i16 == 10'u32 -# assert 10'i16 == 10'u64 +doAssert 10'i16 == 10'u8 +doAssert 10'i16 == 10'u16 +doAssert 10'i16 == 10'u32 +# doAssert 10'i16 == 10'u64 -assert 10'i32 == 10'u8 -assert 10'i32 == 10'u16 -assert 10'i32 == 10'u32 -# assert 10'i32 == 10'u64 +doAssert 10'i32 == 10'u8 +doAssert 10'i32 == 10'u16 +doAssert 10'i32 == 10'u32 +# doAssert 10'i32 == 10'u64 -assert 10'i64 == 10'u8 -assert 10'i64 == 10'u16 -assert 10'i64 == 10'u32 -# assert 10'i64 == 10'u64 +doAssert 10'i64 == 10'u8 +doAssert 10'i64 == 10'u16 +doAssert 10'i64 == 10'u32 +# doAssert 10'i64 == 10'u64 # unsigned == signed -assert 10'u8 == 10'i8 -assert 10'u8 == 10'i16 -assert 10'u8 == 10'i32 -# assert 10'u8 == 10'i64 +doAssert 10'u8 == 10'i8 +doAssert 10'u8 == 10'i16 +doAssert 10'u8 == 10'i32 +# doAssert 10'u8 == 10'i64 -assert 10'u16 == 10'i8 -assert 10'u16 == 10'i16 -assert 10'u16 == 10'i32 -# assert 10'u16 == 10'i64 +doAssert 10'u16 == 10'i8 +doAssert 10'u16 == 10'i16 +doAssert 10'u16 == 10'i32 +# doAssert 10'u16 == 10'i64 -assert 10'u32 == 10'i8 -assert 10'u32 == 10'i16 -assert 10'u32 == 10'i32 -# assert 10'u32 == 10'i64 +doAssert 10'u32 == 10'i8 +doAssert 10'u32 == 10'i16 +doAssert 10'u32 == 10'i32 +# doAssert 10'u32 == 10'i64 -# assert 10'u64 == 10'i8 -# assert 10'u64 == 10'i16 -# assert 10'u64 == 10'i32 -# assert 10'u64 == 10'i64 +# doAssert 10'u64 == 10'i8 +# doAssert 10'u64 == 10'i16 +# doAssert 10'u64 == 10'i32 +# doAssert 10'u64 == 10'i64 diff --git a/tests/misc/twarningaserror.nim b/tests/misc/twarningaserror.nim new file mode 100644 index 0000000000..6f7b760956 --- /dev/null +++ b/tests/misc/twarningaserror.nim @@ -0,0 +1,35 @@ +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/newconfig/bar/config.nims b/tests/newconfig/bar/config.nims new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/newconfig/bar/mfoo.nim b/tests/newconfig/bar/mfoo.nim new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/newconfig/bar/mfoo.nim.cfg b/tests/newconfig/bar/mfoo.nim.cfg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/newconfig/bar/mfoo.nims b/tests/newconfig/bar/mfoo.nims new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/newconfig/bar/nim.cfg b/tests/newconfig/bar/nim.cfg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims index a53e777d49..6f0048afbb 100644 --- a/tests/newconfig/tfoo.nims +++ b/tests/newconfig/tfoo.nims @@ -51,56 +51,56 @@ doAssert(existsEnv("dummy") == false) # issue #7393 let wd = getCurrentDir() cd("..") -assert wd != getCurrentDir() +doAssert wd != getCurrentDir() cd(wd) -assert wd == getCurrentDir() +doAssert wd == getCurrentDir() when false: # this doesn't work in a 'koch testintall' environment - assert findExe("nim") != "" + doAssert findExe("nim") != "" # general tests mode = ScriptMode.Verbose -assert getCommand() == "c" +doAssert getCommand() == "c" setCommand("cpp") -assert getCommand() == "cpp" +doAssert getCommand() == "cpp" setCommand("c") -assert cmpic("HeLLO", "hello") == 0 +doAssert cmpic("HeLLO", "hello") == 0 -assert fileExists("tests/newconfig/tfoo.nims") == true -assert dirExists("tests") == true +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 discard selfExe() when defined(windows): - assert toExe("nim") == "nim.exe" - assert toDll("nim") == "nim.dll" + doAssert toExe("nim") == "nim.exe" + doAssert toDll("nim") == "nim.dll" else: - assert toExe("nim") == "nim" - assert toDll("nim") == "libnim.so" + doAssert toExe("nim") == "nim" + doAssert toDll("nim") == "libnim.so" rmDir("tempXYZ") doAssertRaises(OSError): rmDir("tempXYZ", checkDir = true) -assert dirExists("tempXYZ") == false +doAssert dirExists("tempXYZ") == false mkDir("tempXYZ") -assert dirExists("tempXYZ") == true -assert fileExists("tempXYZ/koch.nim") == false +doAssert dirExists("tempXYZ") == true +doAssert fileExists("tempXYZ/koch.nim") == false when false: # this doesn't work in a 'koch testintall' environment cpFile("koch.nim", "tempXYZ/koch.nim") - assert fileExists("tempXYZ/koch.nim") == true + doAssert fileExists("tempXYZ/koch.nim") == true cpDir("nimsuggest", "tempXYZ/.") - assert dirExists("tempXYZ/tests") == true - assert fileExists("tempXYZ/nimsuggest.nim") == true + doAssert dirExists("tempXYZ/tests") == true + doAssert fileExists("tempXYZ/nimsuggest.nim") == true rmFile("tempXYZ/koch.nim") - assert fileExists("tempXYZ/koch.nim") == false + doAssert fileExists("tempXYZ/koch.nim") == false rmDir("tempXYZ") -assert dirExists("tempXYZ") == false +doAssert dirExists("tempXYZ") == false diff --git a/tests/nimdoc/trunnableexamples.nim b/tests/nimdoc/trunnableexamples.nim index 6232011cbf..2de1862bd8 100644 --- a/tests/nimdoc/trunnableexamples.nim +++ b/tests/nimdoc/trunnableexamples.nim @@ -109,6 +109,31 @@ when true: # runnableExamples with rdoccmd # passing seq (to run with multiple compilation options) runnableExamples(@["-b:cpp", "-b:js"]): discard +runnableExamples: + block: # bug #17279 + when int.sizeof == 8: + let x = 0xffffffffffffffff + doAssert x == -1 + + # bug #13491 + block: + proc fun(): int = doAssert false + doAssertRaises(AssertionError, (discard fun())) + + block: + template foo(body) = discard + foo (discard) + + block: + template fn(body: untyped): untyped = true + doAssert(fn do: nonexistant) + 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: @@ -120,3 +145,13 @@ runnableExamples: # 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/niminaction/Chapter1/various1.nim b/tests/niminaction/Chapter1/various1.nim index 4e2cb463d8..21553dc40e 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, future, strutils +import sequtils, sugar, 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/resultaccept.nim b/tests/niminaction/Chapter2/resultaccept.nim index 7dd976b40e..390f7b3299 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() == nil +doAssert discarded().len == 0 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/various2.nim b/tests/niminaction/Chapter2/various2.nim index 488c361a28..921f38c7d1 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, future +import sequtils, sugar 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 future +import sugar proc isValid2(x: int, validator: (x: int) -> bool) = if validator(x): echo(x, " is valid") else: echo(x, " is NOT valid") @@ -193,7 +193,7 @@ doAssertRaises(IndexDefect): block: var list = newSeq[string](3) - assert list[0] == nil + assert list[0].len == 0 list[0] = "Foo" list[1] = "Bar" list[2] = "Baz" diff --git a/tests/niminaction/Chapter3/various3.nim b/tests/niminaction/Chapter3/various3.nim index 849ea71d8b..4e028a048d 100644 --- a/tests/niminaction/Chapter3/various3.nim +++ b/tests/niminaction/Chapter3/various3.nim @@ -7,7 +7,7 @@ Future is no longer empty, 42 import threadpool proc foo: string = "Dog" var x: FlowVar[string] = spawn foo() -assert(^x == "Dog") +doAssert(^x == "Dog") block: type @@ -19,20 +19,20 @@ block: discard var obj = Box(empty: false, contents: "Hello") - assert obj.contents == "Hello" + doAssert obj.contents == "Hello" var obj2 = Box(empty: true) doAssertRaises(FieldDefect): echo(obj2.contents) import json -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 +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 import json let data = """ @@ -40,15 +40,15 @@ let data = """ """ let obj = parseJson(data) -assert obj.kind == JObject -assert obj["username"].kind == JString -assert obj["username"].str == "Dominik" +doAssert obj.kind == JObject +doAssert obj["username"].kind == JString +doAssert obj["username"].str == "Dominik" block: proc count10(): int = for i in 0 ..< 10: result.inc - assert count10() == 10 + doAssert count10() == 10 type Point = tuple[x, y: int] diff --git a/tests/niminaction/Chapter8/sdl/sdl.nim b/tests/niminaction/Chapter8/sdl/sdl.nim index 7ba154cae6..212f7b0228 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) or defined(netbsd): 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/objects/tobject.nim b/tests/objects/tobject.nim index d166d5385c..543a863765 100644 --- a/tests/objects/tobject.nim +++ b/tests/objects/tobject.nim @@ -1,7 +1,3 @@ -discard """ -output: "\n[Suite] object basic methods" -""" - import unittest type Obj = object @@ -10,12 +6,12 @@ type Obj = object proc makeObj(x: int): Obj = result.foo = x -suite "object basic methods": - test "it should convert an object to a string": +block: # object basic methods + block: # it should convert an object to a string var obj = makeObj(1) # Should be "obj: (foo: 1)" or similar. check($obj == "(foo: 1)") - test "it should test equality based on fields": + block: # it should test equality based on fields check(makeObj(1) == makeObj(1)) # bug #10203 diff --git a/tests/objvariant/t14581.nim b/tests/objvariant/t14581.nim new file mode 100644 index 0000000000..72ba32f182 --- /dev/null +++ b/tests/objvariant/t14581.nim @@ -0,0 +1,25 @@ +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/tconstructionorder.nim b/tests/objvariant/tconstructionorder.nim index 19ddea7a14..5ca484884a 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 - assert root.kind == Operator - assert root.operator == '*' + doAssert root.kind == Operator + doAssert root.operator == '*' # check left subtree - assert root.left.value == 5 - assert root.left.kind == Literal + doAssert root.left.value == 5 + doAssert root.left.kind == Literal # check right subtree - assert root.right.kind == Operator - assert root.right.operator == '+' + doAssert root.right.kind == Operator + doAssert root.right.operator == '+' - assert root.right.left.value == 5 - assert root.right.left.kind == Literal + doAssert root.right.left.value == 5 + doAssert root.right.left.kind == Literal - assert root.right.right.value == 10 - assert root.right.right.kind == Literal + doAssert root.right.right.value == 10 + doAssert root.right.right.kind == Literal proc newLiteralNode(value: int): Node = result = Node( diff --git a/tests/openarray/topenarray.nim b/tests/openarray/topenarray.nim new file mode 100644 index 0000000000..0b6e3afc49 --- /dev/null +++ b/tests/openarray/topenarray.nim @@ -0,0 +1,27 @@ +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] + +main() +# static: main() # xxx bug #15952: Error: cannot generate code for: mSlice diff --git a/tests/osproc/tclose.nim b/tests/osproc/tclose.nim index d466b466a7..1c99237c71 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}) - assert countFds() == initCount + 3 + doAssert countFds() == initCount + 3 p.close - assert countFds() == initCount + doAssert countFds() == initCount let p1 = osproc.startProcess("echo", options={poUsePath}) discard p1.inputStream - assert countFds() == initCount + 3 + doAssert countFds() == initCount + 3 p.close - assert countFds() == initCount + doAssert countFds() == initCount diff --git a/tests/parallel/tconvexhull.nim b/tests/parallel/tconvexhull.nim index ebadb874dd..0a07e6b766 100644 --- a/tests/parallel/tconvexhull.nim +++ b/tests/parallel/tconvexhull.nim @@ -1,8 +1,6 @@ discard """ output: ''' ''' - -ccodeCheck: "\\i ! @'deepCopy(' .*" """ # parallel convex hull for Nim bigbreak diff --git a/tests/parser/tpostexprblocks.nim b/tests/parser/tpostexprblocks.nim index c27bbf3215..bc10a72e2e 100644 --- a/tests/parser/tpostexprblocks.nim +++ b/tests/parser/tpostexprblocks.nim @@ -406,6 +406,98 @@ 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 + Par + Ident "a" + Ident "b" + StmtList + DiscardStmt + Empty + ElifBranch + Ident "a" + StmtList + DiscardStmt + Empty + ElifBranch + Par + Ident "a" + Ident "b" + StmtList + DiscardStmt + Empty + ExceptBranch + Ident "a" + StmtList + DiscardStmt + Empty + ExceptBranch + Par + Ident "a" + Ident "b" + StmtList + DiscardStmt + Empty + Finally + StmtList + DiscardStmt + Empty ''' """ @@ -540,3 +632,26 @@ 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 diff --git a/tests/parser/ttypeclasses.nim b/tests/parser/ttypeclasses.nim index 06146dcb68..e6e7a48b8d 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: - 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 + 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 # XXX: These cases don't work properly at the moment: - # assert type[int] isnot int - # assert type(int) isnot int + # doAssert type[int] isnot int + # doAssert type(int) isnot int diff --git a/tests/pragmas/tbitsize.nim b/tests/pragmas/tbitsize.nim index 7a44944d24..39aee445f2 100644 --- a/tests/pragmas/tbitsize.nim +++ b/tests/pragmas/tbitsize.nim @@ -10,13 +10,13 @@ type var b: bits -assert b.flag == 0 +doAssert b.flag == 0 b.flag = 1 -assert b.flag == 1 +doAssert b.flag == 1 b.flag = 2 -assert b.flag == 0 +doAssert b.flag == 0 b.opts = 7 -assert b.opts == 7 +doAssert b.opts == 7 b.opts = 9 -assert b.opts == -7 +doAssert b.opts == -7 diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index a4a200c34b..e9dac753dd 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -8,7 +8,7 @@ block: proc myProc():int {.myAttr.} = 2 const hasMyAttr = myProc.hasCustomPragma(myAttr) static: - assert(hasMyAttr) + doAssert(hasMyAttr) block: template myAttr(a: string) {.pragma.} @@ -19,8 +19,8 @@ block: var o: MyObj static: - assert o.myField2.hasCustomPragma(myAttr) - assert(not o.myField1.hasCustomPragma(myAttr)) + doAssert o.myField2.hasCustomPragma(myAttr) + doAssert(not o.myField1.hasCustomPragma(myAttr)) import custom_pragma block: # A bit more advanced case @@ -42,31 +42,31 @@ block: # A bit more advanced case var s: MySerializable const aDefVal = s.a.getCustomPragmaVal(defaultValue) - static: assert(aDefVal == 5) + static: doAssert(aDefVal == 5) const aSerKey = s.a.getCustomPragmaVal(serializationKey) - static: assert(aSerKey == "asdf") + static: doAssert(aSerKey == "asdf") const cSerKey = getCustomPragmaVal(s.field.c, serializationKey) - static: assert(cSerKey == "cc") + static: doAssert(cSerKey == "cc") const procSerKey = getCustomPragmaVal(myproc, serializationKey) - static: assert(procSerKey == "myprocSS") + static: doAssert(procSerKey == "myprocSS") - static: assert(hasCustomPragma(myproc, alternativeKey)) + static: doAssert(hasCustomPragma(myproc, alternativeKey)) const hasFieldCustomPragma = s.field.hasCustomPragma(defaultValue) - static: assert(hasFieldCustomPragma == false) + static: doAssert(hasFieldCustomPragma == false) # pragma on an object static: - assert Subfield.hasCustomPragma(defaultValue) - assert(Subfield.getCustomPragmaVal(defaultValue) == "catman") + doAssert Subfield.hasCustomPragma(defaultValue) + doAssert(Subfield.getCustomPragmaVal(defaultValue) == "catman") - assert hasCustomPragma(type(s.field), defaultValue) + doAssert hasCustomPragma(type(s.field), defaultValue) proc foo(s: var MySerializable) = - static: assert(s.a.getCustomPragmaVal(defaultValue) == 5) + static: doAssert(s.a.getCustomPragmaVal(defaultValue) == 5) foo(s) @@ -91,8 +91,8 @@ block: # ref types leftSerKey = getCustomPragmaVal(s.left, serializationKey) rightSerKey = getCustomPragmaVal(s.right, serializationKey) static: - assert leftSerKey == "l" - assert rightSerKey == "r" + doAssert leftSerKey == "l" + doAssert rightSerKey == "r" var specS = SpecialNodeRef() @@ -100,25 +100,25 @@ block: # ref types dataDefVal = hasCustomPragma(specS.data, defaultValue) specLeftSerKey = hasCustomPragma(specS.left, serializationKey) static: - assert dataDefVal == true - assert specLeftSerKey == true + doAssert dataDefVal == true + doAssert specLeftSerKey == true var ptrS = NodePtr(nil) const ptrRightSerKey = getCustomPragmaVal(ptrS.right, serializationKey) static: - assert ptrRightSerKey == "r" + doAssert ptrRightSerKey == "r" var f = MyFile() const fileDefVal = f.getCustomPragmaVal(defaultValue) filePathDefVal = f.path.getCustomPragmaVal(defaultValue) static: - assert fileDefVal == "closed" - assert filePathDefVal == "invalid" + doAssert fileDefVal == "closed" + doAssert filePathDefVal == "invalid" static: - assert TypeWithoutPragma.hasCustomPragma(defaultValue) == false + doAssert TypeWithoutPragma.hasCustomPragma(defaultValue) == false block: type @@ -144,9 +144,9 @@ block: nestedItemDefVal = vari.nestedItem.getCustomPragmaVal(defaultValue) static: - assert hasIntSerKey - assert strSerKey == "string" - assert nestedItemDefVal == "Nimmers of the world, unite!" + doAssert hasIntSerKey + doAssert strSerKey == "string" + doAssert nestedItemDefVal == "Nimmers of the world, unite!" block: template simpleAttr {.pragma.} @@ -154,7 +154,7 @@ block: type Annotated {.simpleAttr.} = object proc generic_proc[T]() = - assert Annotated.hasCustomPragma(simpleAttr) + doAssert Annotated.hasCustomPragma(simpleAttr) #-------------------------------------------------------------------------- @@ -252,7 +252,7 @@ block: block: macro expectedAst(expectedRepr: static[string], input: untyped): untyped = - assert input.treeRepr & "\n" == expectedRepr + doAssert input.treeRepr & "\n" == expectedRepr return input const procTypeAst = """ @@ -270,7 +270,7 @@ ProcTy type Foo = proc (x: int) {.expectedAst(procTypeAst), async.} - static: assert Foo is proc(x: int): Future[void] + static: doAssert Foo is proc(x: int): Future[void] const asyncProcTypeAst = """ ProcTy @@ -288,7 +288,7 @@ ProcTy type Bar = proc (s: string) {.async, expectedAst(asyncProcTypeAst).} - static: assert Bar is proc(x: string): Future[void] + static: doAssert Bar is proc(x: string): Future[void] const typeAst = """ TypeDef @@ -310,7 +310,7 @@ TypeDef Baz {.expectedAst(typeAst).} = object x: string - static: assert Baz.x is string + static: doAssert Baz.x is string const procAst = """ ProcDef @@ -333,7 +333,7 @@ ProcDef proc bar(s: string): string {.expectedAst(procAst).} = return s - static: assert bar("x") == "x" + static: doAssert bar("x") == "x" #------------------------------------------------------ # bug #13909 diff --git a/tests/pragmas/twarning_off.nim b/tests/pragmas/twarning_off.nim index d5d31d4c23..bada2999b4 100644 --- a/tests/pragmas/twarning_off.nim +++ b/tests/pragmas/twarning_off.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--hint:processing" nimout: ''' compile start .. diff --git a/tests/proc/tlambdapragma.nim b/tests/proc/tlambdapragma.nim new file mode 100644 index 0000000000..daa952b1ef --- /dev/null +++ b/tests/proc/tlambdapragma.nim @@ -0,0 +1,7 @@ +discard """ + errormsg: "invalid pragma: exportc" +""" + +let _ = proc () {.exportc.} = + # this would previously cause a codegen error + discard diff --git a/tests/sandwich/generic_library.nim b/tests/sandwich/generic_library.nim new file mode 100644 index 0000000000..43e7bd65f2 --- /dev/null +++ b/tests/sandwich/generic_library.nim @@ -0,0 +1,6 @@ + +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 new file mode 100644 index 0000000000..d003bf0441 --- /dev/null +++ b/tests/sandwich/helper_module.nim @@ -0,0 +1,3 @@ + +proc indirectlyMixedIn*: int = + 200 diff --git a/tests/sandwich/module_using_generic_library.nim b/tests/sandwich/module_using_generic_library.nim new file mode 100644 index 0000000000..bbb0d92a4a --- /dev/null +++ b/tests/sandwich/module_using_generic_library.nim @@ -0,0 +1,12 @@ + +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 new file mode 100644 index 0000000000..aa50bfb049 --- /dev/null +++ b/tests/sandwich/tmain.nim @@ -0,0 +1,9 @@ +discard """ + output: '''100 +200''' +""" + +import + module_using_generic_library + +makeUseOfLibrary "test" diff --git a/tests/sets/m17385.nim b/tests/sets/m17385.nim new file mode 100644 index 0000000000..3919e067a6 --- /dev/null +++ b/tests/sets/m17385.nim @@ -0,0 +1,11 @@ +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/t17385.nim b/tests/sets/t17385.nim new file mode 100644 index 0000000000..cc08b48822 --- /dev/null +++ b/tests/sets/t17385.nim @@ -0,0 +1,4 @@ +import m17385 + +let a = Diff[int]() +a.test() diff --git a/tests/sets/tsets_various.nim b/tests/sets/tsets_various.nim index c27d8e124c..5f3b234366 100644 --- a/tests/sets/tsets_various.nim +++ b/tests/sets/tsets_various.nim @@ -1,14 +1,15 @@ discard """ + targets: "c cpp js" output: ''' set is empty ''' """ -import sets, hashes +import std/[sets, hashes] -from sequtils import toSeq -from algorithm import sorted +from std/sequtils import toSeq +from std/algorithm import sorted proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted template sortedItems(t: untyped): untyped = sorted(toSeq(t)) @@ -58,13 +59,13 @@ block tsets2: var t = initHashSet[tuple[x, y: int]]() t.incl((0,0)) t.incl((1,0)) - assert(not t.containsOrIncl((0,1))) + doAssert(not t.containsOrIncl((0,1))) t.incl((1,1)) for x in 0..1: for y in 0..1: - assert((x,y) in t) - #assert($t == + doAssert((x,y) in t) + #doAssert($t == # "{(x: 0, y: 0), (x: 0, y: 1), (x: 1, y: 0), (x: 1, y: 1)}") block setTest2: @@ -76,31 +77,31 @@ block tsets2: t.incl("012") t.incl("123") # test duplicates - assert "123" in t - assert "111" notin t # deleted + doAssert "123" in t + doAssert "111" notin t # deleted - assert t.missingOrExcl("000") - assert "000" notin t - assert t.missingOrExcl("012") == false - assert "012" notin t + doAssert t.missingOrExcl("000") + doAssert "000" notin t + doAssert t.missingOrExcl("012") == false + doAssert "012" notin t - assert t.containsOrIncl("012") == false - assert t.containsOrIncl("012") - assert "012" in t # added back + doAssert t.containsOrIncl("012") == false + doAssert t.containsOrIncl("012") + doAssert "012" in t # added back for key in items(data): t.incl(key) - for key in items(data): assert key in t + for key in items(data): doAssert key in t for key in items(data): t.excl(key) - for key in items(data): assert key notin t + for key in items(data): doAssert key notin t block orderedSetTest1: var t = data.toOrderedSet - for key in items(data): assert key in t + for key in items(data): doAssert key in t var i = 0 # `items` needs to yield in insertion order: for key in items(t): - assert key == data[i] + doAssert key == data[i] inc(i) @@ -117,22 +118,22 @@ block tsets3: s1_s3 = s1 + s3 s2_s3 = s2 + s3 - assert s1_s2.len == 7 - assert s1_s3.len == 8 - assert s2_s3.len == 6 + doAssert s1_s2.len == 7 + doAssert s1_s3.len == 8 + doAssert s2_s3.len == 6 for i in s1: - assert i in s1_s2 - assert i in s1_s3 + doAssert i in s1_s2 + doAssert i in s1_s3 for i in s2: - assert i in s1_s2 - assert i in s2_s3 + doAssert i in s1_s2 + doAssert i in s2_s3 for i in s3: - assert i in s1_s3 - assert i in s2_s3 + doAssert i in s1_s3 + doAssert i in s2_s3 - assert((s1 + s1) == s1) - assert((s2 + s1) == s1_s2) + doAssert((s1 + s1) == s1) + doAssert((s2 + s1) == s1_s2) block intersection: let @@ -140,22 +141,22 @@ block tsets3: s1_s3 = intersection(s1, s3) s2_s3 = s2 * s3 - assert s1_s2.len == 3 - assert s1_s3.len == 0 - assert s2_s3.len == 2 + doAssert s1_s2.len == 3 + doAssert s1_s3.len == 0 + doAssert s2_s3.len == 2 for i in s1_s2: - assert i in s1 - assert i in s2 + doAssert i in s1 + doAssert i in s2 for i in s1_s3: - assert i in s1 - assert i in s3 + doAssert i in s1 + doAssert i in s3 for i in s2_s3: - assert i in s2 - assert i in s3 + doAssert i in s2 + doAssert i in s3 - assert((s2 * s2) == s2) - assert((s3 * s2) == s2_s3) + doAssert((s2 * s2) == s2) + doAssert((s3 * s2) == s2_s3) block symmetricDifference: let @@ -163,22 +164,22 @@ block tsets3: s1_s3 = s1 -+- s3 s2_s3 = s2 -+- s3 - assert s1_s2.len == 4 - assert s1_s3.len == 8 - assert s2_s3.len == 4 + doAssert s1_s2.len == 4 + doAssert s1_s3.len == 8 + doAssert s2_s3.len == 4 for i in s1: - assert i in s1_s2 xor i in s2 - assert i in s1_s3 xor i in s3 + doAssert i in s1_s2 xor i in s2 + doAssert i in s1_s3 xor i in s3 for i in s2: - assert i in s1_s2 xor i in s1 - assert i in s2_s3 xor i in s3 + doAssert i in s1_s2 xor i in s1 + doAssert i in s2_s3 xor i in s3 for i in s3: - assert i in s1_s3 xor i in s1 - assert i in s2_s3 xor i in s2 + doAssert i in s1_s3 xor i in s1 + doAssert i in s2_s3 xor i in s2 - assert((s3 -+- s3) == initHashSet[int]()) - assert((s3 -+- s1) == s1_s3) + doAssert((s3 -+- s3) == initHashSet[int]()) + doAssert((s3 -+- s1) == s1_s3) block difference: let @@ -186,23 +187,23 @@ block tsets3: s1_s3 = difference(s1, s3) s2_s3 = s2 - s3 - assert s1_s2.len == 2 - assert s1_s3.len == 5 - assert s2_s3.len == 3 + doAssert s1_s2.len == 2 + doAssert s1_s3.len == 5 + doAssert s2_s3.len == 3 for i in s1: - assert i in s1_s2 xor i in s2 - assert i in s1_s3 xor i in s3 + doAssert i in s1_s2 xor i in s2 + doAssert i in s1_s3 xor i in s3 for i in s2: - assert i in s2_s3 xor i in s3 + doAssert i in s2_s3 xor i in s3 - assert((s2 - s2) == initHashSet[int]()) + doAssert((s2 - s2) == initHashSet[int]()) block disjoint: - assert(not disjoint(s1, s2)) - assert disjoint(s1, s3) - assert(not disjoint(s2, s3)) - assert(not disjoint(s2, s2)) + 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) = @@ -217,7 +218,7 @@ block: # https://github.com/nim-lang/Nim/issues/13496 doAssert sortedItems(t) == @[15, 17, 19] var s = newSeq[int]() for v in t: s.add(v) - assert s.len == 3 + 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)] @@ -254,3 +255,24 @@ block: # test correctness after a number of inserts/deletes testDel(): (var t: HashSet[int]) testDel(): (var t: OrderedSet[int]) + + +template main() = + 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 + + +static: main() +main() diff --git a/tests/specialops/tcallops.nim b/tests/specialops/tcallops.nim new file mode 100644 index 0000000000..0508a37a15 --- /dev/null +++ b/tests/specialops/tcallops.nim @@ -0,0 +1,39 @@ +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) diff --git a/tests/specialops/tcallprecedence.nim b/tests/specialops/tcallprecedence.nim new file mode 100644 index 0000000000..6116f83d53 --- /dev/null +++ b/tests/specialops/tcallprecedence.nim @@ -0,0 +1,44 @@ +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 b1c75ab33a..ca5eee6657 100644 --- a/tests/specialops/tdotops.nim +++ b/tests/specialops/tdotops.nim @@ -17,6 +17,14 @@ one param call to c with 10 ''' """ +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/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index f3a0f0fcb8..a76276d2cd 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -2,6 +2,8 @@ discard """ nimout: ''' staticAlialProc instantiated with 358 staticAlialProc instantiated with 368 +0: Foo +1: Bar ''' output: ''' 16 @@ -17,14 +19,14 @@ Val1 import macros -template ok(x) = assert(x) -template no(x) = assert(not x) +template ok(x) = doAssert(x) +template no(x) = doAssert(not x) template accept(x) = - static: assert(compiles(x)) + static: doAssert(compiles(x)) template reject(x) = - static: assert(not compiles(x)) + static: doAssert(not compiles(x)) proc plus(a, b: int): int = a + b @@ -54,8 +56,8 @@ when true: b: static[int], c: static int) = static: - assert a.isStatic and b.isStatic and c.isStatic - assert isStatic(a + plus(b, c)) + doAssert a.isStatic and b.isStatic and c.isStatic + doAssert isStatic(a + plus(b, c)) echo "staticAlialProc instantiated with ", a, b, c when b mod a == 0: @@ -111,9 +113,9 @@ when true: var aw3: ArrayWrapper3[(10, "str")] static: - assert aw1.data.high == 5 - assert aw2.data.high == 6 - assert aw3.data.high == 9 + doAssert aw1.data.high == 5 + doAssert aw2.data.high == 6 + doAssert aw3.data.high == 9 # #6077 block: @@ -289,8 +291,10 @@ macro fooParam(x: static array[2, string]): untyped = echo i, ": ", val macro barParam(x: static Table[int, string]): untyped = - for i, val in x: + let barParamInsides = proc(i: int, val: string): NimNode = echo i, ": ", val + for i, val in x: + discard barParamInsides(i, val) fooM() barM() @@ -366,3 +370,19 @@ block: 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..1(?2(?3))(?'v4'4))()")) == { "v1" : 0, "v2" : 1, "v3" : 2, "v4" : 3 }.toTable()) - test "capture bounds are correct": + block: # 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 @@ suite "captures": let ex3 = re("([0-9]+)") check("824".find(ex3).captureBounds[0] == 0 .. 2) - test "named captures": + block: # named captures let ex1 = "foobar".find(re("(?foo)(?bar)")) check(ex1.captures["foo"] == "foo") check(ex1.captures["bar"] == "bar") @@ -32,7 +32,7 @@ suite "captures": expect KeyError: discard ex2.captures["bar"] - test "named capture bounds": + block: # 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 @@ suite "captures": expect KeyError: discard ex1.captures["bar"] - test "capture count": + block: # capture count let ex1 = re("(?foo)(?bar)?") check(ex1.captureCount == 2) check(ex1.captureNameId == {"foo" : 0, "bar" : 1}.toTable()) - test "named capture table": + block: # 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 @@ suite "captures": let ex2 = "foobar".find(re("(?foo)(?bar)?")) check(ex2.captures.toTable == {"foo" : "foo", "bar" : "bar"}.toTable()) - test "capture sequence": + block: # 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 db5e8a0012..5e7dc0c0ef 100644 --- a/tests/stdlib/nre/escape.nim +++ b/tests/stdlib/nre/escape.nim @@ -1,7 +1,7 @@ import nre, unittest -suite "escape strings": - test "escape strings": +block: # escape strings + block: # 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 caa953ff45..7e7555d732 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 -suite "find": - test "find text": +block: # find + block: # 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 ) == @[" ", " ", " ", " ", " ", " ", " ", " "]) - test "find bounds": + block: # 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]) - test "overlapping find": + block: # overlapping find check("222".findAll(re"22") == @["22"]) check("2222".findAll(re"22") == @["22", "22"]) - test "len 0 find": + block: # len 0 find check("".findAll(re"\ ") == newSeq[string]()) check("".findAll(re"") == @[""]) check("abc".findAll(re"") == @["", "", "", ""]) @@ -27,7 +27,7 @@ suite "find": check("word\r\lword".findAll(re"(*ANYCRLF)(?m)$") == @["", ""]) check("слово слово".findAll(re"(*U)\b") == @["", "", "", ""]) - test "bail early": + block: # 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 26e6681041..f0c8e0a00f 100644 --- a/tests/stdlib/nre/init.nim +++ b/tests/stdlib/nre/init.nim @@ -1,12 +1,12 @@ import unittest include nre -suite "Test NRE initialization": - test "correct initialization": +block: # Test NRE initialization + block: # correct initialization check(re("[0-9]+") != nil) check(re("(?i)[0-9]+") != nil) - test "options": + block: # options check(extractOptions("(*NEVER_UTF)") == ("", pcre.NEVER_UTF, true)) check(extractOptions("(*UTF8)(*ANCHORED)(*UCP)z") == @@ -19,14 +19,14 @@ suite "Test NRE initialization": check(extractOptions("(*LIMIT_MATCH=6)(*ANCHORED)z") == ("(*LIMIT_MATCH=6)z", pcre.ANCHORED, true)) - test "incorrect options": + block: # 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)) - test "invalid regex": + block: # 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 06b69fd042..7e09a4b2f4 100644 --- a/tests/stdlib/nre/match.nim +++ b/tests/stdlib/nre/match.nim @@ -1,12 +1,12 @@ include nre, unittest, optional_nonstrict -suite "match": - test "upper bound must be inclusive": +block: # match + block: # 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)) - test "match examples": + block: # 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 @@ suite "match": check("abc".match(re"").captureBounds[-1] == 0 .. -1) check("abc".match(re"abc").captureBounds[-1] == 0 .. 2) - test "match test cases": + block: # 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 f4a88b639b..dbb0ecdf9c 100644 --- a/tests/stdlib/nre/misc.nim +++ b/tests/stdlib/nre/misc.nim @@ -1,11 +1,11 @@ import unittest, nre, strutils, optional_nonstrict -suite "Misc tests": - test "unicode": +block: # Misc tests + block: # unicode check("".find(re"(*UTF8)").match == "") check("перевірка".replace(re"(*U)\w", "") == "") - test "empty or non-empty match": + block: # empty or non-empty match check("abc".findall(re"|.").join(":") == ":a::b::c:") check("abc".findall(re".|").join(":") == "a:b:c:") diff --git a/tests/stdlib/nre/replace.nim b/tests/stdlib/nre/replace.nim index 6f3436410a..5cf659f213 100644 --- a/tests/stdlib/nre/replace.nim +++ b/tests/stdlib/nre/replace.nim @@ -1,13 +1,13 @@ include nre import unittest -suite "replace": - test "replace with 0-length strings": +block: # replace + block: # 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") - test "regular replace": + block: # 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,7 +15,7 @@ suite "replace": check("123".replace(re"(?\d)(\d)", "$foo$#$#") == "1123") check("123".replace(re"(?\d)(\d)", "${foo}$#$#") == "1123") - test "replacing missing captures should throw instead of segfaulting": + 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") expect KeyError: discard "b".replace(re"(a)?", "${foo}") diff --git a/tests/stdlib/nre/split.nim b/tests/stdlib/nre/split.nim index 9d57ea7d89..3cd57bb82d 100644 --- a/tests/stdlib/nre/split.nim +++ b/tests/stdlib/nre/split.nim @@ -1,8 +1,8 @@ import unittest, strutils include nre -suite "string splitting": - test "splitting strings": +block: # string splitting + block: # 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 @@ suite "string splitting": check("".split(re"foo") == @[""]) check("9".split(re"\son\s") == @["9"]) - test "captured patterns": + block: # captured patterns check("12".split(re"(\d)") == @["", "1", "", "2", ""]) - test "maxsplit": + block: # 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"]) - test "split with 0-length match": + block: # 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)") == @["", "слово", "", " ", "", "слово", ""]) - test "perl split tests": + block: # 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 @@ suite "string splitting": check("" .split(re"") .len == 0) check(":" .split(re"") .len == 1) - test "start position": + block: # 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/t14139.nim b/tests/stdlib/t14139.nim index 78e0f66457..07d2ff1376 100644 --- a/tests/stdlib/t14139.nim +++ b/tests/stdlib/t14139.nim @@ -6,4 +6,4 @@ test_queue.push(7) test_queue.push(3) test_queue.push(9) let i = test_queue.pushpop(10) -assert i == 3 +doAssert i == 3 diff --git a/tests/stdlib/t15835.nim b/tests/stdlib/t15835.nim deleted file mode 100644 index bddfa87aad..0000000000 --- a/tests/stdlib/t15835.nim +++ /dev/null @@ -1,17 +0,0 @@ -import json - -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) diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index 9dec68f032..fecd858200 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -1,9 +1,10 @@ discard """ + targets: "c js" output:'''@["3", "2", "1"] ''' """ #12928,10456 -import sequtils, strutils, algorithm, json +import std/[sequtils, algorithm, json] proc test() = try: @@ -14,37 +15,37 @@ proc test() = echo prefixes except: discard - + test() block: # 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 + doAssert arr.lowerBound(0) == 0 + doAssert arr.lowerBound(4) == 3 + doAssert arr.lowerBound(5) == 3 + doAssert arr.lowerBound(10) == 8 arr = @[1, 5, 10] - assert arr.lowerBound(4) == 1 - assert arr.lowerBound(5) == 1 - assert arr.lowerBound(6) == 2 + 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] - assert srt1.isSorted(cmp) == true - assert srt2.isSorted(cmp) == false - assert srt3.isSorted(cmp) == true - assert srt4.isSorted(cmp) == true + doAssert srt1.isSorted(cmp) == true + doAssert srt2.isSorted(cmp) == false + doAssert srt3.isSorted(cmp) == true + doAssert srt4.isSorted(cmp) == true var srtseq = newSeq[int]() - assert srtseq.isSorted(cmp) == true + doAssert srtseq.isSorted(cmp) == true # Tests for reversed var arr1 = @[0, 1, 2, 3, 4] - assert arr1.reversed() == @[4, 3, 2, 1, 0] + doAssert 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] + 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] diff --git a/tests/stdlib/tasynchttpserver_transferencoding.nim b/tests/stdlib/tasynchttpserver_transferencoding.nim new file mode 100644 index 0000000000..34f3cef11b --- /dev/null +++ b/tests/stdlib/tasynchttpserver_transferencoding.nim @@ -0,0 +1,81 @@ +import httpclient, asynchttpserver, asyncdispatch, asyncfutures +import net + +import std/asyncnet +import std/nativesockets + +const postBegin = """ +POST / HTTP/1.1 +Transfer-Encoding:chunked + +""" + +template genTest(input, expected) = + var sanity = false + proc handler(request: Request) {.async.} = + doAssert(request.body == expected) + doAssert(request.headers.hasKey("Transfer-Encoding")) + doAssert(not request.headers.hasKey("Content-Length")) + sanity = true + await request.respond(Http200, "Good") + + proc runSleepLoop(server: AsyncHttpServer) {.async.} = + server.listen(Port(0)) + proc wrapper() = + waitFor server.acceptRequest(handler) + asyncdispatch.callSoon wrapper + + let server = newAsyncHttpServer() + waitFor runSleepLoop(server) + let port = getLocalAddr(server.getSocket.getFd, AF_INET)[1] + let data = postBegin & input + var socket = newSocket() + socket.connect("127.0.0.1", port) + socket.send(data) + waitFor sleepAsync(10) + socket.close() + server.close() + + # Verify we ran the handler and its asserts + doAssert(sanity) + +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/tbitops.nim b/tests/stdlib/tbitops.nim index 2baa1c7183..6b5e0aeb98 100644 --- a/tests/stdlib/tbitops.nim +++ b/tests/stdlib/tbitops.nim @@ -2,12 +2,11 @@ discard """ nimout: "OK" output: ''' OK -OK ''' """ import bitops -proc main1() = +proc main() = const U8 = 0b0011_0010'u8 const I8 = 0b0011_0010'i8 const U16 = 0b00100111_00101000'u16 @@ -21,120 +20,120 @@ proc main1() = 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 (U64A and U64B and U64C) == bitand(U64A,U64B,U64C) + doAssert (I64A and I64B and I64C) == bitand(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( (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 (U64A or U64B or U64C) == bitor(U64A,U64B,U64C) + doAssert (I64A or I64B or I64C) == bitor(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( (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 (U64A xor U64B xor U64C) == bitxor(U64A,U64B,U64C) + doAssert (I64A xor I64B xor I64C) == bitxor(I64A,I64B,I64C) - 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 +150,106 @@ proc main1() = 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) 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) + doAssert v == 0b0000_0000 v.setMask(0b0001_1110) - doAssert(v == 0b0001_1110) + doAssert v == 0b0001_1110 v.mask(0b0101_0100) - doAssert(v == 0b0001_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) + 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) + 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) + 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) + 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) + doAssert b == 0b101 # loop test: let c = 0b1111_1111'u8 for i in 0 .. 7: - doAssert(c.bitsliced(i .. 7) == c shr i) + 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) + doAssert a == 0b0000_1100 a.setMask(4 .. 7) - doAssert(a == 0b1111_1100) + doAssert a == 0b1111_1100 a.flipMask(1 .. 3) - doAssert(a == 0b1111_0010) + doAssert a == 0b1111_0010 a.flipMask(2 .. 4) - doAssert(a == 0b1110_1110) + doAssert a == 0b1110_1110 a.clearMask(2 .. 4) - doAssert(a == 0b1110_0010) + doAssert a == 0b1110_0010 a.mask(0 .. 3) - doAssert(a == 0b0000_0010) + 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) + 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 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 block: # single bit operations var v: uint8 @@ -287,7 +286,7 @@ proc main1() = 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,6 +328,9 @@ proc main1() = echo "OK" + # bug #7587 + doAssert popcount(0b11111111'i8) == 8 + block: # not ready for vm because exception is compile error try: var v: uint32 @@ -341,172 +343,7 @@ block: # not ready for vm because exception is compile error doAssert false -main1() +main() static: # test everything on vm as well - main1() - - - -proc main2() = - 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" - -main2() - + main() diff --git a/tests/stdlib/tbitops.nim.cfg b/tests/stdlib/tbitops.nim.cfg index f0d7668a7c..013e8d38e3 100644 --- a/tests/stdlib/tbitops.nim.cfg +++ b/tests/stdlib/tbitops.nim.cfg @@ -1 +1 @@ --d:noUndefinedBitOps +-d:noUndefinedBitOpts diff --git a/tests/stdlib/tcgi.nim b/tests/stdlib/tcgi.nim index cec188e352..9937287121 100644 --- a/tests/stdlib/tcgi.nim +++ b/tests/stdlib/tcgi.nim @@ -1,25 +1,10 @@ -discard """ - output: ''' +import std/unittest +import std/[cgi, strtabs, sugar] -[Suite] Test cgi module -(key: "a", value: "1") -(key: "b", value: "0") -(key: "c", value: "3") -(key: "d", value: "") -(key: "e", value: "") -(key: "a", value: "5") -(key: "a", value: "t e x t") -(key: "e", value: "http://w3schools.com/my test.asp?name=ståle&car=saab") -''' -""" - -import unittest -import cgi, strtabs - -suite "Test cgi module": +block: # Test cgi module const queryString = "foo=bar&фу=бар&checked=✓&list=1,2,3&with_space=text%20with%20space" - test "test query parsing with readData": + block: # test query parsing with readData let parsedQuery = readData(queryString) check parsedQuery["foo"] == "bar" @@ -34,5 +19,8 @@ suite "Test cgi module": # 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" -for pair in decodeData(queryString): - echo pair +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/tchannels.nim b/tests/stdlib/tchannels.nim new file mode 100644 index 0000000000..33108c50c4 --- /dev/null +++ b/tests/stdlib/tchannels.nim @@ -0,0 +1,33 @@ +discard """ + timeout: 5.0 # but typically < 1s + disabled: "freebsd" + matrix: "--gc:arc --threads:on; --gc:arc --threads:on -d:danger" +""" + +when true: + # bug #17380: this was either blocking (without -d:danger) or crashing with SIGSEGV (with -d:danger) + import std/[channels, isolation] + const + N1 = 10 + N2 = 100 + var + sender: array[N1, Thread[void]] + receiver: array[5, Thread[void]] + + var chan = newChannel[seq[string]](N1 * N2) # large enough to not block + proc sendHandler() = + chan.send(isolate(@["Hello, Nim"])) + proc recvHandler() = + template fn = + let x = chan.recv() + fn() + + template benchmark() = + for t in mitems(sender): + t.createThread(sendHandler) + joinThreads(sender) + for t in mitems(receiver): + t.createThread(recvHandler) + joinThreads(receiver) + for i in 0.. 0 + +when defined(blockingTest): + const nonBlocking = false +else: + const nonBlocking = true + +type + Pthread {.importc: "pthread_t", header: "".} = distinct culong + PthreadAttr* {.byref, importc: "pthread_attr_t", header: "".} = object + Errno* = distinct cint + +proc pthread_create[T]( + thread: var Pthread, + attr: ptr PthreadAttr, # In Nim this is a var and how Nim sets a custom stack + fn: proc (x: ptr T): pointer {.thread, noconv.}, + arg: ptr T + ): Errno {.header: "".} + +proc pthread_join( + thread: Pthread, + thread_exit_status: ptr pointer + ): Errno {.header: "".} + +template channel_send_loop(chan: ChannelRaw, + data: sink pointer, + size: int, + body: untyped): untyped = + while not sendMpmc(chan, data, size, nonBlocking): + body + +template channel_receive_loop(chan: ChannelRaw, + data: pointer, + size: int, + body: untyped): untyped = + while not recvMpmc(chan, data, size, nonBlocking): + body + + +# Without threads:on or release, +# worker threads will crash on popFrame + +import std/unittest + +type ThreadArgs = object + ID: int + chan: ChannelRaw + +template Worker(id: int, body: untyped): untyped {.dirty.} = + if args.ID == id: + body + + +const Sender = 1 +const Receiver = 0 + +proc runSuite( + name: string, + fn: proc(args: ptr ThreadArgs): pointer {.noconv, gcsafe.} + ) = + var chan: ChannelRaw + + for i in Unbuffered .. Buffered: + if i == Unbuffered: + chan = allocChannel(size = 32, n = 1) + check: + peek(chan) == 0 + capacity(chan) == 1 + isBuffered(chan) == false + isUnbuffered(chan) == true + + else: + chan = allocChannel(size = int.sizeof.int, n = 7) + check: + peek(chan) == 0 + capacity(chan) == 7 + isBuffered(chan) == true + isUnbuffered(chan) == false + + var threads: array[2, Pthread] + var args = [ + ThreadArgs(ID: 0, chan: chan), + ThreadArgs(ID: 1, chan: chan) + ] + + discard pthread_create(threads[0], nil, fn, args[0].addr) + discard pthread_create(threads[1], nil, fn, args[1].addr) + + discard pthread_join(threads[0], nil) + discard pthread_join(threads[1], nil) + + freeChannel(chan) + +# ---------------------------------------------------------------------------------- + +proc thread_func(args: ptr ThreadArgs): pointer {.noconv.} = + + # Worker RECEIVER: + # --------- + # <- chan + # <- chan + # <- chan + # + # Worker SENDER: + # --------- + # chan <- 42 + # chan <- 53 + # chan <- 64 + # + + Worker(Receiver): + var val: int + for j in 0 ..< 3: + channel_receive_loop(args.chan, val.addr, val.sizeof.int): + # Busy loop, normally it should yield + discard + check: val == 42 + j*11 + + Worker(Sender): + var val: int + check: peek(args.chan) == 0 + for j in 0 ..< 3: + val = 42 + j*11 + channel_send_loop(args.chan, val.addr, val.sizeof.int): + # Busy loop, normally it should yield + discard + + return nil + +runSuite("[ChannelRaw] 2 threads can send data", thread_func) + +# ---------------------------------------------------------------------------------- + +iterator pairs(chan: ChannelRaw, T: typedesc): (int, T) = + var i = 0 + var x: T + while not isClosed(chan) or peek(chan) > 0: + let r = recvMpmc(chan, x.addr, x.sizeof.int, true) + # printf("x: %d, r: %d\n", x, r) + if r: + yield (i, x) + inc i + +proc thread_func_2(args: ptr ThreadArgs): pointer {.noconv.} = + # Worker RECEIVER: + # --------- + # <- chan until closed and empty + # + # Worker SENDER: + # --------- + # chan <- 42, 53, 64, ... + + const N = 100 + + Worker(Receiver): + for j, val in pairs(args.chan, int): + # TODO: Need special handling that doesn't allocate + # in thread with no GC + # when check fails + # + check: val == 42 + j*11 + + Worker(Sender): + var val: int + check: peek(args.chan) == 0 + for j in 0 ..< N: + val = 42 + j*11 + channel_send_loop(args.chan, val.addr, int.sizeof.int): + discard + discard channelCloseMpmc(args.chan) + + return nil + +runSuite("[ChannelRaw] channel_close, freeChannel, channelCache", thread_func_2) + +# ---------------------------------------------------------------------------------- + +proc isCached(chan: ChannelRaw): bool = + assert not chan.isNil + + var p = channelCache + while not p.isNil: + if chan.itemsize == p.chanSize and + chan.size == p.chanN: + for i in 0 ..< p.numCached: + if chan == p.cache[i]: + return true + # No more channel in cache can match + return false + p = p.next + return false + +block: # [ChannelRaw] ChannelRaw caching implementation + + # Start from clean cache slate + freeChannelCache() + + block: # Explicit caches allocation + check: + allocChannelCache(int sizeof(char), 4) + allocChannelCache(int sizeof(int), 8) + allocChannelCache(int sizeof(ptr float64), 16) + + # Don't create existing channel cache + not allocChannelCache(int sizeof(char), 4) + not allocChannelCache(int sizeof(int), 8) + not allocChannelCache(int sizeof(ptr float64), 16) + + check: + channelCacheLen == 3 + + # --------------------------------- + var chan, stash: array[10, ChannelRaw] + + block: # Implicit caches allocation + + chan[0] = allocChannel(sizeof(char), 4) + chan[1] = allocChannel(sizeof(int32), 8) + chan[2] = allocChannel(sizeof(ptr float64), 16) + + chan[3] = allocChannel(sizeof(char), 5) + chan[4] = allocChannel(sizeof(int64), 8) + chan[5] = allocChannel(sizeof(ptr float32), 24) + + # We have caches ready to store specific channel kinds + check: channelCacheLen == 6 # Cumulated with previous test + # But they are not in cache while in use + check: + not chan[0].isCached + not chan[1].isCached + not chan[2].isCached + not chan[3].isCached + not chan[4].isCached + not chan[5].isCached + + block: # Freed channels are returned to cache + stash[0..5] = chan.toOpenArray(0, 5) + for i in 0 .. 5: + # Free the channels + freeChannel(chan[i]) + + check: + stash[0].isCached + stash[1].isCached + stash[2].isCached + stash[3].isCached + stash[4].isCached + stash[5].isCached + + block: # Cached channels are being reused + + chan[6] = allocChannel(sizeof(char), 4) + chan[7] = allocChannel(sizeof(int32), 8) + chan[8] = allocChannel(sizeof(ptr float32), 16) + chan[9] = allocChannel(sizeof(ptr float64), 16) + + # All (itemsize, queue size, implementation) were already allocated + check: channelCacheLen == 6 + + # We reused old channels from cache + check: + chan[6] == stash[0] + chan[7] == stash[1] + chan[8] == stash[2] + # chan[9] - required a fresh alloc + + block: # Clearing the cache + + stash[6..9] = chan.toOpenArray(6, 9) + + for i in 6 .. 9: + freeChannel(chan[i]) + + check: + stash[6].isCached + stash[7].isCached + stash[8].isCached + stash[9].isCached + + freeChannelCache() + + # Check that nothing is cached anymore + for i in 0 .. 9: + check: not stash[i].isCached + # And length is reset to 0 + check: channelCacheLen == 0 + + # Cache can grow again + chan[0] = allocChannel(sizeof((int, float, int32, uint)), 1) + chan[1] = allocChannel(sizeof(int32), 0) + chan[2] = allocChannel(sizeof(int32), 0) + + check: channelCacheLen == 2 + + # Interleave cache clear and channel free + freeChannelCache() + check: channelCacheLen == 0 + + freeChannel(chan[0]) + freeChannel(chan[1]) + freeChannel(chan[2]) diff --git a/tests/stdlib/tchannels_simple.nim b/tests/stdlib/tchannels_simple.nim new file mode 100644 index 0000000000..56e5fb8f12 --- /dev/null +++ b/tests/stdlib/tchannels_simple.nim @@ -0,0 +1,67 @@ +discard """ + matrix: "--threads:on --gc:orc; --threads:on --gc:arc" + disabled: "freebsd" +""" + +import std/channels +import std/os + +var chan = newChannel[string]() + +# This proc will be run in another thread using the threads module. +proc firstWorker() = + chan.send("Hello World!") + +# This is another proc to run in a background thread. This proc takes a while +# to send the message since it sleeps for 2 seconds (or 2000 milliseconds). +proc secondWorker() = + sleep(2000) + chan.send("Another message") + + +# Launch the worker. +var worker1: Thread[void] +createThread(worker1, firstWorker) + +# Block until the message arrives, then print it out. +let dest = chan.recv() +doAssert dest == "Hello World!" + +# Wait for the thread to exit before moving on to the next example. +worker1.joinThread() + +# Launch the other worker. +var worker2: Thread[void] +createThread(worker2, secondWorker) +# This time, use a non-blocking approach with tryRecv. +# Since the main thread is not blocked, it could be used to perform other +# useful work while it waits for data to arrive on the channel. + +var messages: seq[string] +var msg = "" +while true: + let tried = chan.tryRecv(msg) + if tried: + messages.add move(msg) + break + + messages.add "Pretend I'm doing useful work..." + # For this example, sleep in order not to flood stdout with the above + # message. + sleep(400) + +# Wait for the second thread to exit before cleaning up the channel. +worker2.joinThread() + +# Clean up the channel. +doAssert chan.close() +doAssert messages[^1] == "Another message" +doAssert messages.len >= 2 + + +block: + let chan0 = newChannel[int]() + let chan1 = chan0 + block: + let chan3 = chan0 + let chan4 = chan0 diff --git a/tests/stdlib/tcmdline.nim b/tests/stdlib/tcmdline.nim new file mode 100644 index 0000000000..bc78d60576 --- /dev/null +++ b/tests/stdlib/tcmdline.nim @@ -0,0 +1,11 @@ +discard """ + targets: "c js" + joinable: false +""" + +import std/os + +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 index 8c9fa3055d..15267b9051 100644 --- a/tests/stdlib/tcomplex.nim +++ b/tests/stdlib/tcomplex.nim @@ -1,4 +1,4 @@ -import complex, math +import std/[complex, math] proc `=~`[T](x, y: Complex[T]): bool = @@ -7,7 +7,7 @@ proc `=~`[T](x, y: Complex[T]): bool = proc `=~`[T](x: Complex[T]; y: T): bool = result = abs(x.re-y) < 1e-6 and abs(x.im) < 1e-6 -var +let z: Complex64 = complex(0.0, 0.0) oo: Complex64 = complex(1.0, 1.0) a: Complex64 = complex(1.0, 2.0) @@ -76,12 +76,12 @@ doAssert(arccsch(a) =~ arcsinh(1.0/a)) doAssert(arccoth(a) =~ arctanh(1.0/a)) doAssert(phase(a) == 1.1071487177940904) -var t = polar(a) +let t = polar(a) doAssert(rect(t.r, t.phi) =~ a) doAssert(rect(1.0, 2.0) =~ complex(-0.4161468365471424, 0.9092974268256817)) -var +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) @@ -96,7 +96,7 @@ doAssert(sin(arcsin(b64)) =~ b64) doAssert(cosh(arccosh(a64)) =~ a64) doAssert(phase(a64) - 1.107149f < 1e-6) -var t64 = polar(a64) +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) @@ -104,5 +104,5 @@ doAssert(sizeof(a) == 16) doAssert 123.0.im + 456.0 == complex64(456, 123) -var localA = complex(0.1'f32) +let localA = complex(0.1'f32) doAssert localA.im is float32 diff --git a/tests/stdlib/tcookies.nim b/tests/stdlib/tcookies.nim index 95b431b19a..0a36cbebcd 100644 --- a/tests/stdlib/tcookies.nim +++ b/tests/stdlib/tcookies.nim @@ -1,4 +1,9 @@ -import cookies, times, strtabs +discard """ + targets: "c js" +""" + + +import std/[cookies, times, strtabs] let expire = fromUnix(0) + 1.seconds diff --git a/tests/stdlib/tcritbits.nim b/tests/stdlib/tcritbits.nim index 7b2dde1c83..b350cb2806 100644 --- a/tests/stdlib/tcritbits.nim +++ b/tests/stdlib/tcritbits.nim @@ -16,48 +16,48 @@ template main = doAssert r.contains"def" r.excl "def" - assert r.missingOrExcl("foo") == false - assert "foo" notin toSeq(r.items) + doAssert r.missingOrExcl("foo") == false + doAssert "foo" notin toSeq(r.items) - assert r.missingOrExcl("foo") == true + doAssert r.missingOrExcl("foo") == true - assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"] + doAssert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"] - assert toSeq(r.itemsWithPrefix("de")) == @["definition"] + doAssert toSeq(r.itemsWithPrefix("de")) == @["definition"] var c = CritBitTree[int]() c.inc("a") - assert c["a"] == 1 + doAssert c["a"] == 1 c.inc("a", 4) - assert c["a"] == 5 + doAssert c["a"] == 5 c.inc("a", -5) - assert c["a"] == 0 + doAssert c["a"] == 0 c.inc("b", 2) - assert c["b"] == 2 + doAssert c["b"] == 2 c.inc("c", 3) - assert c["c"] == 3 + doAssert c["c"] == 3 c.inc("a", 1) - assert c["a"] == 1 + doAssert c["a"] == 1 var cf = CritBitTree[float]() cf.incl("a", 1.0) - assert cf["a"] == 1.0 + doAssert cf["a"] == 1.0 cf.incl("b", 2.0) - assert cf["b"] == 2.0 + doAssert cf["b"] == 2.0 cf.incl("c", 3.0) - assert cf["c"] == 3.0 + doAssert cf["c"] == 3.0 - assert cf.len == 3 + doAssert cf.len == 3 cf.excl("c") - assert cf.len == 2 + doAssert cf.len == 2 var cb: CritBitTree[string] cb.incl("help", "help") diff --git a/tests/stdlib/tcstring.nim b/tests/stdlib/tcstring.nim new file mode 100644 index 0000000000..98da5d5c4d --- /dev/null +++ b/tests/stdlib/tcstring.nim @@ -0,0 +1,92 @@ +discard """ + targets: "c cpp js" + matrix: "; --gc:arc" +""" + +from std/sugar import collect +from stdtest/testutils import whenRuntimeJs, whenVMorJs + +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 new file mode 100644 index 0000000000..ba3b1de684 --- /dev/null +++ b/tests/stdlib/tcstrutils.nim @@ -0,0 +1,38 @@ +discard """ + targets: "c cpp js" +""" + +import std/cstrutils + + +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/tdeques.nim b/tests/stdlib/tdeques.nim index db392c6cc9..99208d4cfe 100644 --- a/tests/stdlib/tdeques.nim +++ b/tests/stdlib/tdeques.nim @@ -11,7 +11,7 @@ block: proc main = var testDeque = initDeque[int]() testDeque.addFirst(1) - assert testDeque.index(0) == 1 + doAssert testDeque.index(0) == 1 main() @@ -35,26 +35,26 @@ block: deq.addFirst(123) var first = deq.popFirst() deq.addLast(56) - assert(deq.peekLast() == 56) + doAssert(deq.peekLast() == 56) deq.addLast(6) - assert(deq.peekLast() == 6) + doAssert(deq.peekLast() == 6) var second = deq.popFirst() deq.addLast(789) - assert(deq.peekLast() == 789) + doAssert(deq.peekLast() == 789) - assert first == 123 - assert second == 9 - assert($deq == "[4, 56, 6, 789]") - assert deq == [4, 56, 6, 789].toDeque + doAssert first == 123 + doAssert second == 9 + doAssert($deq == "[4, 56, 6, 789]") + doAssert deq == [4, 56, 6, 789].toDeque - assert deq[0] == deq.peekFirst and deq.peekFirst == 4 - #assert deq[^1] == deq.peekLast and deq.peekLast == 789 + 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 - assert 6 in deq and 789 notin deq - assert deq.find(6) >= 0 - assert deq.find(789) < 0 + doAssert 6 in deq and 789 notin deq + doAssert deq.find(6) >= 0 + doAssert deq.find(789) < 0 block: var d = initDeque[int](1) @@ -74,21 +74,21 @@ block: for i in -2 .. 10: if i in deq: - assert deq.contains(i) and deq.find(i) >= 0 + doAssert deq.contains(i) and deq.find(i) >= 0 else: - assert(not deq.contains(i) and deq.find(i) < 0) + doAssert(not deq.contains(i) and deq.find(i) < 0) when compileOption("boundChecks"): try: echo deq[99] - assert false + doAssert false except IndexDefect: discard try: - assert deq.len == 4 + doAssert deq.len == 4 for i in 0 ..< 5: deq.popFirst() - assert false + doAssert false except IndexDefect: discard @@ -98,24 +98,24 @@ block: deq.popFirst() deq.popLast() for i in 5 .. 8: deq.addFirst i - assert $deq == "[8, 7, 6, 5, 2, 3]" + 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]() - assert deq.len == 0 + doAssert deq.len == 0 for i in 1 .. a: deq.addLast i if b < deq.len: # checking before indexed access. - assert deq[b] == b + 1 + 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. - assert deq.peekFirst == 1 - assert deq.peekLast == a + doAssert deq.peekFirst == 1 + doAssert deq.peekLast == a while deq.len > 0: # checking if the deque is empty - assert deq.popFirst() > 0 + doAssert deq.popFirst() > 0 #foo(0,0) foo(8, 5) @@ -133,7 +133,7 @@ block t13310: q.addFirst([1'i16].toHashSet) q.addFirst([2'i16].toHashSet) q.addFirst([3'i16].toHashSet) - assert $q == "[{3}, {2}, {1}]" + doAssert $q == "[{3}, {2}, {1}]" static: main() diff --git a/tests/stdlib/teditdistance.nim b/tests/stdlib/teditdistance.nim index 5a8acd513f..4335356356 100644 --- a/tests/stdlib/teditdistance.nim +++ b/tests/stdlib/teditdistance.nim @@ -30,11 +30,11 @@ 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) \ No newline at end of file +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/tenumerate.nim b/tests/stdlib/tenumerate.nim index e5f21bc15b..7a1c2d10a1 100644 --- a/tests/stdlib/tenumerate.nim +++ b/tests/stdlib/tenumerate.nim @@ -6,14 +6,14 @@ block: var res: seq[(int, int)] for i, x in enumerate(a): res.add (i, x) - assert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] + 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) - assert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] + 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) - assert res == @[(3, 1), (4, 3), (5, 5), (6, 7)] + doAssert res == @[(3, 1), (4, 3), (5, 5), (6, 7)] diff --git a/tests/stdlib/tenumutils.nim b/tests/stdlib/tenumutils.nim new file mode 100644 index 0000000000..11142216c4 --- /dev/null +++ b/tests/stdlib/tenumutils.nim @@ -0,0 +1,37 @@ +discard """ + targets: "c js" +""" + +import std/enumutils +from std/sequtils import toSeq + +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/tfenv.nim b/tests/stdlib/tfenv.nim index f58acf1c8d..5bcd1ea7c0 100644 --- a/tests/stdlib/tfenv.nim +++ b/tests/stdlib/tfenv.nim @@ -1,8 +1,7 @@ -import fenv +import std/fenv func is_significant(x: float): bool = - if x > minimumPositiveValue(float) and x < maximumPositiveValue(float): true - else: false + x > minimumPositiveValue(float) and x < maximumPositiveValue(float) doAssert is_significant(10.0) diff --git a/tests/stdlib/tfrexp1.nim b/tests/stdlib/tfrexp1.nim index 21ecc7491e..85110231d9 100644 --- a/tests/stdlib/tfrexp1.nim +++ b/tests/stdlib/tfrexp1.nim @@ -1,9 +1,8 @@ discard """ targets: "js c cpp" - output: '''ok''' """ -import math +import std/math const manualTest = false @@ -43,4 +42,12 @@ when manualTest: else: frexp_test(-200000.0, 200000.0, 0.125) -echo "ok" + +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 diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index 520b27e263..a4487c8c0b 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -2,7 +2,16 @@ discard """ targets: "c cpp js" """ -import hashes +import std/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: @@ -75,3 +84,97 @@ block largeSize: # longer than 4 characters 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) + 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)) + +static: main() +main() diff --git a/tests/stdlib/theapqueue.nim b/tests/stdlib/theapqueue.nim index 20e23e878e..3b68166afd 100644 --- a/tests/stdlib/theapqueue.nim +++ b/tests/stdlib/theapqueue.nim @@ -1,4 +1,4 @@ -import heapqueue +import std/heapqueue proc toSortedSeq[T](h: HeapQueue[T]): seq[T] = @@ -7,47 +7,96 @@ proc toSortedSeq[T](h: HeapQueue[T]): seq[T] = 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 == data.toHeapQueue) - doAssert(heap[0] == 0) - doAssert(heap.toSortedSeq == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) +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 -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) +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]) - heap.del(0) - doAssert(heap[0] == 1) + 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(heap.find(7)) - doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 8, 9]) + heap.del(0) + doAssert(heap[0] == 1) - heap.del(heap.find(5)) - doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 6, 8, 9]) + heap.del(heap.find(7)) + doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 8, 9]) - heap.del(heap.find(6)) - doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 8, 9]) + heap.del(heap.find(5)) + doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 6, 8, 9]) - heap.del(heap.find(2)) - doAssert(heap.toSortedSeq == @[1, 3, 4, 8, 9]) + heap.del(heap.find(6)) + doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 8, 9]) - doAssert(heap.find(2) == -1) + heap.del(heap.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) + doAssert(heap.find(2) == -1) - heap.del(2) - doAssert(heap.toSortedSeq == @[1, 2]) + block: # test del last + var heap = initHeapQueue[int]() + let data = [1, 2, 3] + for item in data: push(heap, item) - heap.del(1) - doAssert(heap.toSortedSeq == @[1]) + heap.del(2) + doAssert(heap.toSortedSeq == @[1, 2]) - heap.del(0) - doAssert(heap.toSortedSeq == @[]) + 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/thtmlparser.nim b/tests/stdlib/thtmlparser.nim index 2ac7b40049..f35785b252 100644 --- a/tests/stdlib/thtmlparser.nim +++ b/tests/stdlib/thtmlparser.nim @@ -47,7 +47,7 @@ block t2813: for n in tree.findAll("table"): n.findAll("tr", rows) # len = 2 break - assert tree.findAll("tr").len == rows.len + doAssert tree.findAll("tr").len == rows.len block t2814: diff --git a/tests/stdlib/thttpclient.nim b/tests/stdlib/thttpclient.nim index 6a634d90fc..e81590d951 100644 --- a/tests/stdlib/thttpclient.nim +++ b/tests/stdlib/thttpclient.nim @@ -1,10 +1,14 @@ discard """ cmd: "nim c --threads:on -d:ssl $file" - exitcode: 0 - output: "OK" - disabled: true + disabled: "openbsd" + disabled: "freebsd" + disabled: "windows" """ +#[ +disabled: see https://github.com/timotheecour/Nim/issues/528 +]# + import strutils from net import TimeoutError @@ -39,7 +43,7 @@ proc makeIPv6HttpServer(hostname: string, port: Port, proc asyncTest() {.async.} = var client = newAsyncHttpClient() - var resp = await client.request("http://example.com/") + var resp = await client.request("http://example.com/", HttpGet) doAssert(resp.code.is2xx) var body = await resp.body body = await resp.body # Test caching @@ -48,7 +52,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) @@ -102,14 +106,14 @@ proc asyncTest() {.async.} = proc syncTest() = var client = newHttpClient() - var resp = client.request("http://example.com/") + var resp = client.request("http://example.com/", HttpGet) 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) @@ -144,6 +148,12 @@ 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. @@ -168,5 +178,3 @@ proc ipv6Test() = ipv6Test() syncTest() waitFor(asyncTest()) - -echo "OK" diff --git a/tests/stdlib/thttpclient_ssl.nim b/tests/stdlib/thttpclient_ssl.nim index 71745c9dfd..1c531eae94 100644 --- a/tests/stdlib/thttpclient_ssl.nim +++ b/tests/stdlib/thttpclient_ssl.nim @@ -101,7 +101,7 @@ when not defined(windows): let t = spawn runServer(port) sleep(100) - var client = newHttpClient() + var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyNone)) try: log "client: connect" discard client.getContent("https://127.0.0.1:12345") diff --git a/tests/stdlib/thttpclient_standalone.nim b/tests/stdlib/thttpclient_standalone.nim new file mode 100644 index 0000000000..44a88e91ea --- /dev/null +++ b/tests/stdlib/thttpclient_standalone.nim @@ -0,0 +1,23 @@ +discard """ + cmd: "nim c --threads:on $file" +""" + +import asynchttpserver, httpclient, asyncdispatch + +block: # bug #16436 + proc startServer() {.async.} = + proc cb(req: Request) {.async.} = + let headers = { "Content-length": "15"} # Provide invalid content-length + await req.respond(Http200, "Hello World", headers.newHttpHeaders()) + + var server = newAsyncHttpServer() + await server.serve(Port(5555), cb) + + proc runClient() {.async.} = + let c = newAsyncHttpClient(headers = {"Connection": "close"}.newHttpHeaders) + let r = await c.getContent("http://127.0.0.1:5555") + doAssert false, "should fail earlier" + + asyncCheck startServer() + doAssertRaises(ProtocolError): + waitFor runClient() diff --git a/tests/stdlib/thttpcore.nim b/tests/stdlib/thttpcore.nim index fd5e1d90c8..6f88e95360 100644 --- a/tests/stdlib/thttpcore.nim +++ b/tests/stdlib/thttpcore.nim @@ -2,31 +2,31 @@ import httpcore, strutils block: block HttpCode: - assert $Http418 == "418 I'm a teapot" - assert Http418.is4xx() == true - assert Http418.is2xx() == false + doAssert $Http418 == "418 I'm a teapot" + doAssert Http418.is4xx() == true + doAssert Http418.is2xx() == false block headers: var h = newHttpHeaders() - assert h.len == 0 + doAssert h.len == 0 h.add("Cookie", "foo") - assert h.len == 1 - assert h.hasKey("cooKIE") - assert h["Cookie"] == "foo" - assert h["cookie"] == "foo" + doAssert h.len == 1 + doAssert h.hasKey("cooKIE") + doAssert h["Cookie"] == "foo" + doAssert h["cookie"] == "foo" h["cookie"] = @["bar", "x"] - 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"] + 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"] h.del("coOKie") - assert h.len == 0 + doAssert h.len == 0 # Test that header constructor works with repeated values let h1 = newHttpHeaders({"a": "1", "a": "2", "A": "3"}) - assert seq[string](h1["a"]).join(",") == "1,2,3" + doAssert seq[string](h1["a"]).join(",") == "1,2,3" block test_cookies_with_comma: doAssert parseHeader("cookie: foo, bar") == ("cookie", @["foo, bar"]) diff --git a/tests/stdlib/tio.nim b/tests/stdlib/tio.nim new file mode 100644 index 0000000000..0da64f9c26 --- /dev/null +++ b/tests/stdlib/tio.nim @@ -0,0 +1,37 @@ +# xxx move to here other tests that belong here; io is a proper module + +import std/os +from stdtest/specialpaths import buildDir + +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.. 0: + for ai in a: + ret.add ai + i.inc + if i >= max: break + ret + + 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 == [] + +static: main() +main() diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index d76be73f30..508205c3ae 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -1,32 +1,15 @@ -discard """ - output: '''{"age": 12, "bio": "Я Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"} -true -true -alpha 100 -omega 200 -Some(null) -None[JsonNode] -(numeric: "") -hello world -''' -joinable: false -""" +import std/marshal -#[ -joinable: false pending https://github.com/nim-lang/Nim/issues/9754 -]# +# TODO: add static tests -import marshal +proc testit[T](x: T): string = $$to[T]($$x) -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"]] -testit(x) -var test2: tuple[name: string, s: int] = ("tuple test", 56) -testit(test2) +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}""" type TE = enum @@ -57,87 +40,86 @@ proc buildList(): PNode = result.prev.next = result result.prev.prev = result.next -var test3: TestObj -test3.test = 42 -test3.test2 = blah -testit(test3) +let test3 = TestObj(test: 42, test2: blah) +doAssert testit(test3) == + """{"test": 42, "asd": 0, "test2": "blah", "help": ""}""" var test4: ref tuple[a, b: string] new(test4) test4.a = "ref string test: A" test4.b = "ref string test: B" -testit(test4) +discard testit(test4) # serialization uses the pointer address, which is not consistent -var test5 = @[(0,1),(2,3),(4,5)] -testit(test5) +let test5 = @[(0,1),(2,3),(4,5)] +doAssert testit(test5) == + """[{"Field0": 0, "Field1": 1}, {"Field0": 2, "Field1": 3}, {"Field0": 4, "Field1": 5}]""" -var test7 = buildList() -testit(test7) +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 test6: set[char] = {'A'..'Z', '_'} -testit(test6) +let test7 = buildList() +discard testit(test7) # serialization uses the pointer address, which is not consistent # bug #1352 +block: + type + Entity = object of RootObj + name: string -type - Entity = object of RootObj - name: string + Person = object of Entity + age: int + bio: string + blob: string - Person = object of Entity - age: int - bio: string - blob: 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 -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 +# bug #5757 +block: + type + Something = object + x: string + y: int -# bug 5757 + let data1 = """{"x": "alpha", "y": 100}""" + let data2 = """{"x": "omega", "y": 200}""" -type - Something = object - x: string - y: int + var r = to[Something](data1) + doAssert $r.x & " " & $r.y == "alpha 100" + r = to[Something](data2) + doAssert $r.x & " " & $r.y == "omega 200" -var data1 = """{"x": "alpha", "y": 100}""" -var data2 = """{"x": "omega", "y": 200}""" +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 r = to[Something](data1) - -echo r.x, " ", r.y - -r = to[Something](data2) - -echo r.x, " ", r.y - - -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) - -import options, json +import std/[options, json] # bug #15934 block: let a1 = some(newJNull()) a2 = none(JsonNode) - echo ($$a1).to[:Option[JsonNode]] - echo ($$a2).to[:Option[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) # bug #15620 block: @@ -148,10 +130,19 @@ block: numeric: string let test = to[LegacyEntry](str) - echo test + doAssert $test == """(numeric: "")""" # bug #16022 block: - let p: proc () = proc () = echo "hello world" - let poc = (to[typeof(p)]($$p)) - poc() + 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}" diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 43d19f9e0b..49b4c82f11 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -1,323 +1,377 @@ discard """ - action: run - output: ''' - -[Suite] random int - -[Suite] random float - -[Suite] cumsum - -[Suite] random sample - -[Suite] ^ -''' -matrix:"; -d:nimTmathCase2 -d:danger --passc:-ffast-math" + targets: "c cpp js" + matrix:"; -d:danger" """ -# xxx: fix bugs for js then add: targets:"c js" +# 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 math, random, os -import unittest -import sets, tables +import std/math -suite "random int": - test "there might be some randomness": - var set = initHashSet[int](128) +# Function for approximate comparison of floats +proc `==~`(x, y: float): bool = abs(x - y) < 1e-9 - for i in 1..1000: - incl(set, rand(high(int))) - check len(set) == 1000 - test "single number bounds work": - var rand: int - for i in 1..1000: - rand = rand(1000) - check rand < 1000 - check rand > -1 - test "slice bounds work": - - var rand: int - for i in 1..1000: - rand = rand(100..1000) - when defined(js): # xxx bug: otherwise fails - check rand <= 1000 - else: - check rand < 1000 - check rand >= 100 - test " again gives new numbers": - - var rand1 = rand(1000000) +template main() = + block: when not defined(js): - os.sleep(200) + # check for no side effect annotation + proc mySqrt(num: float): float {.noSideEffect.} = + # xxx unused + sqrt(num) - var rand2 = rand(1000000) - check rand1 != rand2 + # 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) + + when not defined(js) and not defined(windows): # xxx pending bug #17017 + doAssert gamma(-1.0).isNaN -suite "random float": - test "there might be some randomness": - var set = initHashSet[float](128) + 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(NegInf) == -1 + doAssert sgn(Inf) == 1 + doAssert sgn(NaN) == 0 - for i in 1..100: - incl(set, rand(1.0)) - check len(set) == 100 - test "single number bounds work": - - var rand: float - for i in 1..1000: - rand = rand(1000.0) - check rand < 1000.0 - check rand > -1.0 - test "slice bounds work": - - var rand: float - for i in 1..1000: - rand = rand(100.0..1000.0) - check rand < 1000.0 - check rand >= 100.0 - test " again gives new numbers": - - var rand1:float = rand(1000000.0) - when not defined(js): - os.sleep(200) - - var rand2:float = rand(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) - -block: - when not defined(js): - # Check for no side effect annotation - proc mySqrt(num: float): float {.noSideEffect.} = - # xxx unused - return sqrt(num) - - # check gamma function - assert(gamma(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)) - - - # 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 - - 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: # 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 + 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(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 + 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) == -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 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 + 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 + 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) == -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 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 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 - 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: # 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 + 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 - 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: # 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) -template main = - # xxx wrap all under `main` so it also gets tested in vm. 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) + + when not defined(windows): # xxx pending bug #17017 + doAssert sqrt(-1.0).isNaN -main() static: main() +main() diff --git a/tests/stdlib/tmd5.nim b/tests/stdlib/tmd5.nim index 736fa05a76..88a7b8d378 100644 --- a/tests/stdlib/tmd5.nim +++ b/tests/stdlib/tmd5.nim @@ -1,7 +1,7 @@ import md5 -assert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") == +doAssert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") == "a3cca2b2aa1e3b5b3b5aad99a8529074") -assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") == +doAssert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") == "7e716d0e702df0505fc72e2b89467910") -assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e") +doAssert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e") diff --git a/tests/stdlib/tmemlinesBuf.nim b/tests/stdlib/tmemlinesBuf.nim index 97ad751eee..ea607525d5 100644 --- a/tests/stdlib/tmemlinesBuf.nim +++ b/tests/stdlib/tmemlinesBuf.nim @@ -5,7 +5,7 @@ disabled: "appveyor" import memfiles var inp = memfiles.open("tests/stdlib/tmemlinesBuf.nim") -var buffer: TaintedString = "" +var buffer: string = "" var lineCount = 0 for line in lines(inp, buffer): lineCount += 1 diff --git a/tests/stdlib/tmemory.nim b/tests/stdlib/tmemory.nim new file mode 100644 index 0000000000..25b5d526ac --- /dev/null +++ b/tests/stdlib/tmemory.nim @@ -0,0 +1,15 @@ + +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.unsafeAddr, sizeof(SomeHash)) == 0 diff --git a/tests/stdlib/tmersenne.nim b/tests/stdlib/tmersenne.nim new file mode 100644 index 0000000000..2707aa2f2a --- /dev/null +++ b/tests/stdlib/tmersenne.nim @@ -0,0 +1,11 @@ +import std/mersenne + +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/tmimetypes.nim b/tests/stdlib/tmimetypes.nim new file mode 100644 index 0000000000..cd41e614bc --- /dev/null +++ b/tests/stdlib/tmimetypes.nim @@ -0,0 +1,13 @@ +discard """ + targets: "c js" +""" + +import std/mimetypes +template main() = + var m = newMimetypes() + doAssert m.getMimetype("mp4") == "video/mp4" + # 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/tmonotimes.nim b/tests/stdlib/tmonotimes.nim index cf25ef0258..2933bb6866 100644 --- a/tests/stdlib/tmonotimes.nim +++ b/tests/stdlib/tmonotimes.nim @@ -1,4 +1,8 @@ -import std/monotimes, times +discard """ + targets: "c js" +""" + +import std/[monotimes, times] let d = initDuration(nanoseconds = 10) let t1 = getMonoTime() diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim index 2dd22796cb..b19d31f6cd 100644 --- a/tests/stdlib/tnet.nim +++ b/tests/stdlib/tnet.nim @@ -5,48 +5,48 @@ outputsub: "" import net, nativesockets import unittest -suite "isIpAddress tests": - test "127.0.0.1 is valid": +block: # isIpAddress tests + block: # 127.0.0.1 is valid check isIpAddress("127.0.0.1") == true - test "ipv6 localhost is valid": + block: # ipv6 localhost is valid check isIpAddress("::1") == true - test "fqdn is not an ip address": + block: # fqdn is not an ip address check isIpAddress("example.com") == false - test "random string is not an ipaddress": + block: # random string is not an ipaddress check isIpAddress("foo bar") == false - test "5127.0.0.1 is invalid": + block: # 5127.0.0.1 is invalid check isIpAddress("5127.0.0.1") == false - test "ipv6 is valid": + block: # ipv6 is valid check isIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652") == true - test "invalid ipv6": + block: # invalid ipv6 check isIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") == false -suite "parseIpAddress tests": - test "127.0.0.1 is valid": +block: # parseIpAddress tests + block: # 127.0.0.1 is valid discard parseIpAddress("127.0.0.1") - test "ipv6 localhost is valid": + block: # ipv6 localhost is valid discard parseIpAddress("::1") - test "fqdn is not an ip address": + block: # fqdn is not an ip address expect(ValueError): discard parseIpAddress("example.com") - test "random string is not an ipaddress": + block: # random string is not an ipaddress expect(ValueError): discard parseIpAddress("foo bar") - test "ipv6 is valid": + block: # ipv6 is valid discard parseIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652") - test "invalid ipv6": + block: # invalid ipv6 expect(ValueError): discard parseIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") diff --git a/tests/stdlib/tnetconnect.nim b/tests/stdlib/tnetconnect.nim new file mode 100644 index 0000000000..e274996512 --- /dev/null +++ b/tests/stdlib/tnetconnect.nim @@ -0,0 +1,22 @@ +discard """ + cmd: "nim c -r -d:ssl $file" + exitcode: 0 +""" + +import std/net + +# Issue 15215 - https://github.com/nim-lang/Nim/issues/15215 +proc test() = + var + ctx = newContext() + socket = newSocket() + + wrapSocket(ctx, socket) + + connect(socket, "www.nim-lang.org", Port(443), 5000) + + send(socket, "GET / HTTP/1.0\nHost: www.nim-lang.org\nConnection: close\n\n") + + close(socket) + +test() diff --git a/tests/stdlib/tnre.nim b/tests/stdlib/tnre.nim index d2dc1a7c5b..f13c16052f 100644 --- a/tests/stdlib/tnre.nim +++ b/tests/stdlib/tnre.nim @@ -2,25 +2,6 @@ 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/toids.nim b/tests/stdlib/toids.nim new file mode 100644 index 0000000000..f162dbe57c --- /dev/null +++ b/tests/stdlib/toids.nim @@ -0,0 +1,6 @@ +import std/oids + + +block: # genOid + let x = genOid() + doAssert ($x).len == 24 diff --git a/tests/stdlib/topenssl.nim b/tests/stdlib/topenssl.nim new file mode 100644 index 0000000000..75e1ba868f --- /dev/null +++ b/tests/stdlib/topenssl.nim @@ -0,0 +1,41 @@ +import std/wordwrap +import openssl + +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 cuchar](fr.cstring) + var todata = cast[ptr cuchar](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 cuchar](fr.cstring) + var todata = cast[ptr cuchar](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 index 04544ffb77..71c52a07e4 100644 --- a/tests/stdlib/toptions.nim +++ b/tests/stdlib/toptions.nim @@ -1,19 +1,8 @@ discard """ - output: '''{"foo":{"test":"123"}}''' + targets: "c js" """ -import json, options - -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) -echo $(%*a) +import std/[json, options] # RefPerson is used to test that overloaded `==` operator is not called by @@ -26,133 +15,183 @@ proc `==`(a, b: RefPerson): bool = assert(not a.isNil and not b.isNil) a.name == b.name -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 +template disableJsVm(body) = + # something doesn't work in JS VM + when defined(js): + when nimvm: discard + else: body + else: + body - doAssert("abc".find('c').get() == 2) +proc main() = + type + Foo = ref object + test: string + Test = object + foo: Option[Foo] - let result = "team".find('i') + let js = """{"foo": {"test": "123"}}""" + let parsed = parseJson(js) + let a = parsed.to(Test) + doAssert $(%*a) == """{"foo":{"test":"123"}}""" - doAssert result == intNone - doAssert result.isNone + block options: + # work around a bug in unittest + let intNone = none(int) + let stringNone = none(string) - block some: - doAssert some(6).get() == 6 - doAssert some("a").unsafeGet() == "a" - doAssert some(6).isSome - doAssert some("a").isSome + block example: + proc find(haystack: string, needle: char): Option[int] = + for i, c in haystack: + if c == needle: + return some i - block none: - doAssertRaises UnpackDefect: - discard none(int).get() - doAssert(none(int).isNone) - doAssert(not none(string).isSome) + doAssert("abc".find('c').get() == 2) - block equality: - doAssert some("a") == some("a") - doAssert some(7) != some(6) - doAssert some("a") != stringNone - doAssert intNone == intNone + let result = "team".find('i') - when compiles(some("a") == some(5)): - doAssert false - when compiles(none(string) == none(int)): - doAssert false + doAssert result == intNone + doAssert result.isNone - block get_with_a_default_value: - doAssert(some("Correct").get("Wrong") == "Correct") - doAssert(stringNone.get("Correct") == "Correct") + block some: + doAssert some(6).get() == 6 + doAssert some("a").unsafeGet() == "a" + doAssert some(6).isSome + doAssert some("a").isSome - block stringify: - doAssert($(some("Correct")) == "Some(\"Correct\")") - doAssert($(stringNone) == "None[string]") + block none: + doAssertRaises UnpackDefect: + discard none(int).get() + doAssert(none(int).isNone) + doAssert(not none(string).isSome) - block map_with_a_void_result: - var procRan = 0 - some(123).map(proc (v: int) = procRan = v) - doAssert procRan == 123 - intNone.map(proc (v: int) = doAssert false) + block equality: + doAssert some("a") == some("a") + doAssert some(7) != some(6) + doAssert some("a") != stringNone + doAssert intNone == intNone - block map: - doAssert(some(123).map(proc (v: int): int = v * 2) == some(246)) - doAssert(intNone.map(proc (v: int): int = v * 2).isNone) + when compiles(some("a") == some(5)): + doAssert false + when compiles(none(string) == none(int)): + doAssert false - 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 get_with_a_default_value: + doAssert(some("Correct").get("Wrong") == "Correct") + doAssert(stringNone.get("Correct") == "Correct") - block flatMap: - proc addOneIfNotZero(v: int): Option[int] = - if v != 0: - result = some(v + 1) - else: - result = none(int) + block stringify: + doAssert($(some("Correct")) == "some(\"Correct\")") + doAssert($(stringNone) == "none(string)") - doAssert(some(1).flatMap(addOneIfNotZero) == some(2)) - doAssert(some(0).flatMap(addOneIfNotZero) == none(int)) - doAssert(some(1).flatMap(addOneIfNotZero).flatMap(addOneIfNotZero) == some(3)) + 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) - proc maybeToString(v: int): Option[string] = - if v != 0: - result = some($v) - else: - result = none(string) + block map: + doAssert(some(123).map(proc (v: int): int = v * 2) == some(246)) + doAssert(intNone.map(proc (v: int): int = v * 2).isNone) - doAssert(some(1).flatMap(maybeToString) == some("1")) + 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) - proc maybeExclaim(v: string): Option[string] = - if v != "": - result = some v & "!" - else: - result = none(string) + block flatMap: + proc addOneIfNotZero(v: int): Option[int] = + if v != 0: + result = some(v + 1) + else: + result = none(int) - doAssert(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!")) - doAssert(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string)) + doAssert(some(1).flatMap(addOneIfNotZero) == some(2)) + doAssert(some(0).flatMap(addOneIfNotZero) == none(int)) + doAssert(some(1).flatMap(addOneIfNotZero).flatMap(addOneIfNotZero) == some(3)) - block SomePointer: - var intref: ref int - doAssert(option(intref).isNone) - intref.new - doAssert(option(intref).isSome) + proc maybeToString(v: int): Option[string] = + if v != 0: + result = some($v) + else: + result = none(string) - let tmp = option(intref) - doAssert(sizeof(tmp) == sizeof(ptr int)) + doAssert(some(1).flatMap(maybeToString) == some("1")) - var prc = proc (x: int): int = x + 1 - doAssert(option(prc).isSome) - prc = nil - doAssert(option(prc).isNone) + proc maybeExclaim(v: string): Option[string] = + if v != "": + result = some v & "!" + else: + result = none(string) - block: - doAssert(none[int]().isNone) - doAssert(none(int) == none[int]()) + doAssert(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!")) + doAssert(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string)) - # "$ on typed with .name" - block: - type Named = object - name: string + block SomePointer: + var intref: ref int + doAssert(option(intref).isNone) + intref.new + doAssert(option(intref).isSome) - let nobody = none(Named) - doAssert($nobody == "None[Named]") + let tmp = option(intref) + doAssert(sizeof(tmp) == sizeof(ptr int)) - # "$ on type with name()" - block: - type Person = object - myname: string + var prc = proc (x: int): int = x + 1 + doAssert(option(prc).isSome) + prc = nil + doAssert(option(prc).isNone) - let noperson = none(Person) - doAssert($noperson == "None[Person]") + block: + doAssert(none[int]().isNone) + doAssert(none(int) == none[int]()) - # "Ref type with overloaded `==`" - block: - let p = some(RefPerson.new()) - doAssert p.isSome + # "$ 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 019303ebf3..3f62a098f7 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -26,6 +26,7 @@ Raises # test os path creation, iteration, and deletion import os, strutils, pathnorm +from stdtest/specialpaths import buildDir block fileOperations: let files = @["these.txt", "are.x", "testing.r", "files.q"] @@ -40,20 +41,25 @@ block fileOperations: doAssertRaises(OSError): copyFile(dname/"nonexistant.txt", dname/"nonexistant.txt") let fname = "D20201009T112235" let fname2 = "D20201009T112235.2" - writeFile(dname/fname, "foo") + 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(dname/fname, dname/sub/fname2) - doAssertRaises(OSError): copyFileToDir(dname/fname, dname/sub) - doAssertRaises(ValueError): copyFileToDir(dname/fname, "") - copyFile(dname/fname, dname/fname2) - doAssert fileExists(dname/fname2) + 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(dname/fname, dname/sub) + copyFileToDir(file, dname/sub) doAssert fileExists(dname/sub/fname) removeDir(dname/sub) doAssert not dirExists(dname/sub) - removeFile(dname/fname) - removeFile(dname/fname2) + removeFile(file) + removeFile(file2) # Test creating files and dirs for dir in dirs: @@ -149,6 +155,112 @@ block fileOperations: doAssert fileExists("../dest/a/file.txt") removeDir("../dest") + # 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_nonexistant" + 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) + import times block modificationTime: # Test get/set modification times @@ -241,7 +353,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" @@ -408,7 +520,7 @@ block ospaths: # 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" @@ -437,12 +549,12 @@ block getTempDir: if existsEnv("TMPDIR"): let origTmpDir = getEnv("TMPDIR") putEnv("TMPDIR", "/mytmp") - doAssert getTempDir() == "/mytmp/" + doAssert getTempDir() == "/mytmp" delEnv("TMPDIR") - doAssert getTempDir() == "/tmp/" + doAssert getTempDir() == "/tmp" putEnv("TMPDIR", origTmpDir) else: - doAssert getTempDir() == "/tmp/" + doAssert getTempDir() == "/tmp" block osenv: block delEnv: @@ -454,6 +566,10 @@ block osenv: doAssert existsEnv(dummyEnvVar) == false delEnv(dummyEnvVar) # deleting an already deleted env var doAssert existsEnv(dummyEnvVar) == false + block: + doAssert getEnv("DUMMY_ENV_VAR_NONEXISTENT", "") == "" + doAssert getEnv("DUMMY_ENV_VAR_NONEXISTENT", " ") == " " + doAssert getEnv("DUMMY_ENV_VAR_NONEXISTENT", "Arrakis") == "Arrakis" block isRelativeTo: doAssert isRelativeTo("/foo", "/") @@ -468,19 +584,19 @@ block isRelativeTo: doAssert not isRelativeTo("/foo2", "/foo") block: # quoteShellWindows - assert quoteShellWindows("aaa") == "aaa" - assert quoteShellWindows("aaa\"") == "aaa\\\"" - assert quoteShellWindows("") == "\"\"" + doAssert quoteShellWindows("aaa") == "aaa" + doAssert quoteShellWindows("aaa\"") == "aaa\\\"" + doAssert quoteShellWindows("") == "\"\"" block: # quoteShellWindows - assert quoteShellPosix("aaa") == "aaa" - assert quoteShellPosix("aaa a") == "'aaa a'" - assert quoteShellPosix("") == "''" - assert quoteShellPosix("a'a") == "'a'\"'\"'a'" + doAssert quoteShellPosix("aaa") == "aaa" + doAssert quoteShellPosix("aaa a") == "'aaa a'" + doAssert quoteShellPosix("") == "''" + doAssert quoteShellPosix("a'a") == "'a'\"'\"'a'" block: # quoteShell when defined(posix): - assert quoteShell("") == "''" + doAssert quoteShell("") == "''" block: # normalizePathEnd # handle edge cases correctly: shouldn't affect whether path is @@ -494,7 +610,7 @@ block: # normalizePathEnd doAssert "//".normalizePathEnd(false) == "/" doAssert "foo.bar//".normalizePathEnd == "foo.bar" doAssert "bar//".normalizePathEnd(trailingSep = true) == "bar/" - when defined(Windows): + 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, @@ -539,3 +655,10 @@ block: # normalizeExe 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() diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index ab80247461..96cff14681 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -195,15 +195,15 @@ else: # main driver # bugfix: windows stdin.close was a noop and led to blocking reads proc startProcessTest(command: string, options: set[ProcessOption] = { poStdErrToStdOut, poUsePath}, input = ""): tuple[ - output: TaintedString, + 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 = (TaintedString"", -1) - var line = newStringOfCap(120).TaintedString + result = ("", -1) + var line = newStringOfCap(120) while true: if outp.readLine(line): result[0].string.add(line.string) @@ -223,7 +223,7 @@ else: # main driver p.inputStream.flush() var line = "" var s: seq[string] - while p.outputStream.readLine(line.TaintedString): + while p.outputStream.readLine(line): s.add line doAssert s == @["10"] @@ -235,15 +235,15 @@ else: # main driver deferScoped: p.close() do: var sout: seq[string] - while p.outputStream.readLine(x.TaintedString): sout.add x + 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.TaintedString): serr.add x - while p.outputStream.readLine(x.TaintedString): sout.add x + 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"] diff --git a/tests/stdlib/tosprocterminate.nim b/tests/stdlib/tosprocterminate.nim index c02e0a8da8..8e9041b81c 100644 --- a/tests/stdlib/tosprocterminate.nim +++ b/tests/stdlib/tosprocterminate.nim @@ -6,7 +6,7 @@ discard """ import os, osproc, times, std / monotimes -when defined(Windows): +when defined(windows): const ProgramWhichDoesNotEnd = "notepad" elif defined(openbsd): const ProgramWhichDoesNotEnd = "/bin/cat" diff --git a/tests/stdlib/tparsecfg.nim b/tests/stdlib/tparsecfg.nim index bbf88ee035..5c077bbdad 100644 --- a/tests/stdlib/tparsecfg.nim +++ b/tests/stdlib/tparsecfg.nim @@ -24,8 +24,8 @@ when not defined(js): var config2 = loadConfig(file) let bar = config2.getSectionValue("foo", "bar") let foo = config2.getSectionValue("foo", "foo") - assert(bar == "-1") - assert(foo == "abc") + doAssert(bar == "-1") + doAssert(foo == "abc") ## Creating a configuration file. var dict1 = newConfig() diff --git a/tests/stdlib/tparseuints.nim b/tests/stdlib/tparseuints.nim index 72041da665..ef8c782b39 100644 --- a/tests/stdlib/tparseuints.nim +++ b/tests/stdlib/tparseuints.nim @@ -1,13 +1,6 @@ -discard """ - action: run - output: ''' - -[Suite] parseutils -''' -""" import unittest, strutils -suite "parseutils": +block: # parseutils check: parseBiggestUInt("0") == 0'u64 check: parseBiggestUInt("18446744073709551615") == 0xFFFF_FFFF_FFFF_FFFF'u64 expect(ValueError): diff --git a/tests/stdlib/tparsopt.nim b/tests/stdlib/tparsopt.nim index 948bc8d5f3..54a470cb30 100644 --- a/tests/stdlib/tparsopt.nim +++ b/tests/stdlib/tparsopt.nim @@ -27,7 +27,7 @@ for kind, key, val in getopt(): of "version", "v": writeVersion() else: writeLine(stdout, "Unknown command line option: ", key, ": ", val) - of cmdEnd: assert(false) # cannot happen + of cmdEnd: doAssert(false) # cannot happen if filename == "": # no filename has been given, so we show the help: writeHelp() diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim index 2990a44a5c..99b7dc6f49 100644 --- a/tests/stdlib/tpegs.nim +++ b/tests/stdlib/tpegs.nim @@ -146,4 +146,4 @@ block: echo "Event parser output" echo "-------------------" let pLen = parseArithExpr(txt) - assert txt.len == pLen + doAssert txt.len == pLen diff --git a/tests/stdlib/tprelude.nim b/tests/stdlib/tprelude.nim new file mode 100644 index 0000000000..a60bcf70a6 --- /dev/null +++ b/tests/stdlib/tprelude.nim @@ -0,0 +1,14 @@ +discard """ + targets: "c js" + matrix: "; -d:nimTestTpreludeCase1" +""" + +when defined nimTestTpreludeCase1: + include std/prelude +else: + include prelude + +template main() = + doAssert toSeq(1..3) == @[1,2,3] +static: main() +main() diff --git a/tests/stdlib/tpunycode.nim b/tests/stdlib/tpunycode.nim index 998bd3bdfa..596c5ef63e 100644 --- a/tests/stdlib/tpunycode.nim +++ b/tests/stdlib/tpunycode.nim @@ -1,5 +1,5 @@ import punycode -assert(decode(encode("", "bücher")) == "bücher") -assert(decode(encode("münchen")) == "münchen") -assert encode("xn--", "münchen") == "xn--mnchen-3ya" +doAssert(decode(encode("", "bücher")) == "bücher") +doAssert(decode(encode("münchen")) == "münchen") +doAssert encode("xn--", "münchen") == "xn--mnchen-3ya" diff --git a/tests/stdlib/tquit.nim b/tests/stdlib/tquit.nim index 0b4a479dc4..81726fd7f6 100644 --- a/tests/stdlib/tquit.nim +++ b/tests/stdlib/tquit.nim @@ -5,9 +5,11 @@ just exiting... joinable: false """ -# Test `addQuitProc` +# Test `addQuitProc` (now deprecated by `addExitProc`) 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 index f8797944ee..9fc68fca11 100644 --- a/tests/stdlib/trandom.nim +++ b/tests/stdlib/trandom.nim @@ -3,11 +3,11 @@ discard """ targets: "c js" """ -import std/[random, stats] +import std/[random, math, os, stats, sets, tables] randomize(233) -proc main = +proc main() = var occur: array[1000, int] for i in 0..100_000: @@ -33,11 +33,8 @@ proc main = # don't use causes integer overflow doAssert compiles(rand[int](low(int) .. high(int))) - main() -import math - block: when not defined(js): doAssert almostEqual(rand(12.5), 4.012897747078944) @@ -64,3 +61,106 @@ block: 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): + 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): + 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 diff --git a/tests/stdlib/trationals.nim b/tests/stdlib/trationals.nim index 17238af074..0a3a95a9a9 100644 --- a/tests/stdlib/trationals.nim +++ b/tests/stdlib/trationals.nim @@ -1,98 +1,103 @@ -import rationals, math +import std/[rationals, math] +template main() = + 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 -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 + doAssert a == a + doAssert a - a == z + doAssert a + b == o + doAssert a / b == o + doAssert a * b == 1 // 4 + doAssert 3 / a == 6 // 1 + doAssert a / 3 == 1 // 6 + doAssert tt * z == z + doAssert 10 * a == tt + doAssert a * 10 == tt + doAssert tt / 10 == a + doAssert a - m1 == 3 // 2 + doAssert a + m1 == -1 // 2 + doAssert m1 + tt == 16 // 4 + doAssert m1 - tt == 6 // -1 -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) + doAssert z < o + doAssert z <= o + doAssert z == z + doAssert cmp(z, o) < 0 + doAssert cmp(o, z) > 0 -assert(z < o) -assert(z <= o) -assert(z == z) -assert(cmp(z, o) < 0) -assert(cmp(o, z) > 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) -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)) + doAssert a == b + doAssert a >= b + doAssert not(b > a) + doAssert cmp(a, b) == 0 + doAssert hash(a) == hash(b) -assert(a == b) -assert(a >= b) -assert(not(b > a)) -assert(cmp(a, b) == 0) -assert(hash(a) == hash(b)) + var x = 1 // 3 -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 -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 -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 -y *= 4 -assert(y == 4//3) -y += 5 -assert(y == 19//3) -y -= 2 -assert(y == 13//3) -y /= 9 -assert(y == 13//27) + doAssert toRational(5) == 5 // 1 + doAssert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 + doAssert toInt(z) == 0 -assert toRational(5) == 5//1 -assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 -assert 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 -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 + doAssert toRational(0.1) == 1 // 10 + doAssert toRational(0.9) == 9 // 10 -assert toRational(0.1) == 1 // 10 -assert 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 -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 + 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 -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 + when sizeof(int) == 8: + doAssert almostEqual(PI.toRational.toFloat, PI) + +static: main() +main() diff --git a/tests/stdlib/tropes.nim b/tests/stdlib/tropes.nim index 0c95d5c5f6..5a9150a336 100644 --- a/tests/stdlib/tropes.nim +++ b/tests/stdlib/tropes.nim @@ -1,73 +1,102 @@ -import ropes +discard """ + targets: "c js" +""" +import std/ropes -block: - let r: Rope = nil - doAssert r[0] == '\0' +template main() = + block: + let r: Rope = nil + doAssert r[0] == '\0' + doAssert $r == "" -block: - var - r1 = rope("Hello") - r2 = rope("Nim-Lang") + block: + var + r1 = rope("Hello, ") + r2 = rope("Nim-Lang") - let r = r1 & r2 - let s = $r - for i in 0 ..< r.len: - doAssert r[i] == s[i] + 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' + doAssert r[66] == '\0' -block: - let r = rope("Hello, Nim-Lang") + block: + let r = rope("Hello, Nim-Lang") - let s = $r - for i in 0 ..< r.len: - doAssert r[i] == s[i] + let s = $r + doAssert s == "Hello, Nim-Lang" + for i in 0 ..< r.len: + doAssert r[i] == s[i] - doAssert r[66] == '\0' + 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") + 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 - for i in 0 ..< r.len: - doAssert r[i] == s[i] + 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' + doAssert r[66] == '\0' -block: - var r: Rope - r.add rope("My Conquest") - r.add rope(" is ") - r.add rope("the Sea of Stars") + block: + var r: Rope + r.add rope("My Conquest") + r.add rope(" is ") + r.add rope("the Sea of Stars") - let s = $r - for i in 0 ..< r.len: - doAssert r[i] == s[i] + 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' + doAssert r[66] == '\0' -block: - var r: Rope - r.add rope("My Conquest") - r.add rope(" is ") - r.add rope("the Sea of Stars") + block: + var r: Rope + r.add rope("My Conquest") + r.add rope(" is ") + r.add rope("the Sea of Stars") - var i: int - for item in r: - doAssert r[i] == item - inc i + doAssert $r == "My Conquest is the Sea of Stars" - doAssert r[66] == '\0' + var i: int + for item in r: + doAssert r[i] == item + inc i -block: - let r1 = "$1 $2 $3" % [rope("Nim"), rope("is"), rope("a great language")] - doAssert $r1 == "Nim is a great language" + doAssert r[66] == '\0' - let r2 = "$# $# $#" % [rope("Nim"), rope("is"), rope("a great language")] - doAssert $r2 == "Nim is a great language" + 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 6a6e6fdc08..0645e41509 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -16,7 +16,7 @@ suite "RST include directive": test "Include whole": "other.rst".writeFile("**test1**") let input = ".. include:: other.rst" - assert "test1" == rstTohtml(input, {}, defaultConfig()) + doAssert "test1" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") test "Include starting from": @@ -30,7 +30,7 @@ OtherStart .. include:: other.rst :start-after: OtherStart """ - assert "Visible" == rstTohtml(input, {}, defaultConfig()) + doAssert "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") test "Include everything before": @@ -44,7 +44,7 @@ And this should **NOT** be visible in `docs.html` .. include:: other.rst :end-before: OtherEnd """ - assert "Visible" == rstTohtml(input, {}, defaultConfig()) + doAssert "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") @@ -62,7 +62,7 @@ And this should **NOT** be visible in `docs.html` :start-after: OtherStart :end-before: OtherEnd """ - assert "Visible" == rstTohtml(input, {}, defaultConfig()) + doAssert "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") @@ -82,5 +82,5 @@ And this should **NOT** be visible in `docs.html` :start-after: OtherStart :end-before: OtherEnd """ - assert "Visible" == rstTohtml(input, {}, defaultConfig()) + doAssert "Visible" == rstTohtml(input, {}, defaultConfig()) removeFile("other.rst") diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 85a96056af..cf82cdf915 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -7,6 +7,34 @@ outputsub: "" import ../../lib/packages/docutils/rstgen import ../../lib/packages/docutils/rst import unittest, strutils, strtabs +import std/private/miscdollars + +proc toHtml(input: string, + rstOptions: RstParseOptions = {roSupportMarkdown}, + 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: + doAssert error != nil, "unexpected RST error '" & message & "'" + error[] = message + # we check only first error because subsequent ones may be meaningless + raise newException(EParseError, message) + else: + doAssert warnings != nil, "unexpected RST warning '" & message & "'" + warnings[].add message + try: + result = rstToHtml(input, rstOptions, defaultConfig(), + msgHandler=testMsgHandler) + except EParseError: + discard suite "YAML syntax highlighting": test "Basics": @@ -21,8 +49,8 @@ suite "YAML syntax highlighting": ? key : value ...""" - let output = rstTohtml(input, {}, defaultConfig()) - assert output == """
          %YAML 1.2
          +    let output = input.toHtml({})
          +    doAssert output == """
          %YAML 1.2
           ---
           a string: string
           a list:
          @@ -47,8 +75,8 @@ suite "YAML syntax highlighting":
               another literal block scalar:
                 |+ # comment after header
                allowed, since more indented than parent"""
          -    let output = rstToHtml(input, {}, defaultConfig())
          -    assert output == """
          a literal block scalar: |
          +    let output = input.toHtml({})
          +    doAssert output == """
          a literal block scalar: |
             some text
             # not a comment
            # a comment, since less indented
          @@ -73,8 +101,8 @@ suite "YAML syntax highlighting":
               % not a directive
               ...
               %TAG ! !foo:"""
          -    let output = rstToHtml(input, {}, defaultConfig())
          -    assert output == """
          %YAML 1.2
          +    let output = input.toHtml({})
          +    doAssert output == """
          %YAML 1.2
           ---
           %not a directive
           ...
          @@ -94,8 +122,8 @@ suite "YAML syntax highlighting":
                 more numbers: [-783, 11e78],
                 not numbers: [ 42e, 0023, +32.37, 8 ball]
               }"""
          -    let output = rstToHtml(input, {}, defaultConfig())
          -    assert output == """
          {
          +    let output = input.toHtml({})
          +    doAssert output == """
          {
             "quoted string": 42,
             'single quoted string': false,
             [ list, "with", 'entries' ]: 73.32e-73,
          @@ -111,8 +139,8 @@ suite "YAML syntax highlighting":
               : !localtag foo
               alias: *anchor
               """
          -    let output = rstToHtml(input, {}, defaultConfig())
          -    assert output == """
          --- !!map
          +    let output = input.toHtml({})
          +    doAssert output == """
          --- !!map
           !!str string: !<tag:yaml.org,2002:int> 42
           ? &anchor !!seq []:
           : !localtag foo
          @@ -131,8 +159,8 @@ suite "YAML syntax highlighting":
               example.com/not/a#comment:
                 ?not a map key
               """
          -    let output = rstToHtml(input, {}, defaultConfig())
          -    assert output == """
          ...
          +    let output = input.toHtml({})
          +    doAssert output == """
          ...
            %a string:
             a:string:not:a:map
           ...
          @@ -146,19 +174,17 @@ suite "YAML syntax highlighting":
           
           suite "RST/Markdown general":
             test "RST emphasis":
          -    assert rstToHtml("*Hello* **world**!", {},
          +    doAssert rstToHtml("*Hello* **world**!", {},
                 newStringTable(modeStyleInsensitive)) ==
                 "Hello world!"
           
             test "Markdown links":
          -    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]"""
          +    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 = """
          @@ -169,8 +195,8 @@ suite "RST/Markdown general":
           | E1 \| text   |
           |              | F2 without pipe
           not in table"""
          -    let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig())
          -    assert output1 == """
          +    let output1 = input1.toHtml
          +    doAssert output1 == """
          A1 headerA2 | not fooled
          @@ -180,8 +206,8 @@ not in table""" let input2 = """ | A1 header | A2 | | --- | --- |""" - let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig()) - assert output2 == """
          A1 headerA2 | not fooled
          C1C2 bold
          D1 code |D2
          E1 | text
          + let output2 = input2.toHtml + doAssert output2 == """
          A1 headerA2
          A1 headerA2
          """ test "RST tables": @@ -197,10 +223,10 @@ A2 A3 A4 A5 ==== === """ let output1 = rstToLatex(input1, {}) - assert "{|X|X|}" in output1 # 2 columns - assert count(output1, "\\\\") == 4 # 4 rows + doAssert "{|X|X|}" in output1 # 2 columns + doAssert count(output1, "\\\\") == 4 # 4 rows for cell in ["H0", "H1", "A0", "A1", "A2", "A3", "A4", "A5"]: - assert cell in output1 + doAssert cell in output1 let input2 = """ Now test 3 columns / 2 rows, and also borders containing 4 =, 3 =, 1 = signs: @@ -212,17 +238,17 @@ A0 A1 X Ax Y ==== === = """ let output2 = rstToLatex(input2, {}) - assert "{|X|X|X|}" in output2 # 3 columns - assert count(output2, "\\\\") == 2 # 2 rows + doAssert "{|X|X|X|}" in output2 # 3 columns + doAssert count(output2, "\\\\") == 2 # 2 rows for cell in ["H0", "H1", "H", "A0", "A1", "X", "Ax", "Y"]: - assert cell in output2 + 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 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + let output1 = input1.toHtml discard output1 test "RST sections": @@ -230,8 +256,8 @@ Check that a few punctuation symbols are not parsed as adornments: Long chapter name ''''''''''''''''''' """ - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) - assert "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 + 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(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 -----)") + + # the same as input9good but with overline headings + # first overline heading has a special meaning: document title + let input10 = dedent """ + ====== + Title0 + ====== + + +++++++++ + SubTitle0 + +++++++++ + + ------ + Level1 + ------ + + Level2 + ------ + + ~~~~~~ + Level3 + ~~~~~~ + + -- + L1 + -- + + Another2 + -------- + + ~~~~~ + More3 + ~~~~~ + + """ + var option: bool + var rstGenera: RstGenerator + var output10: string + rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", {}) + rstGenera.renderRstToOut(rstParse(input10, "", 1, 1, option, {}), output10) + doAssert rstGenera.meta[metaTitle] == "Title0" + doAssert rstGenera.meta[metaSubTitle] == "SubTitle0" + doAssert "

          Level1

          " in output10 + doAssert "

          Level2

          " in output10 + doAssert "

          Level3

          " in output10 + doAssert "

          L1

          " in output10 + doAssert "

          Another2

          " in output10 + doAssert "

          More3

          " in output10 + + # check that a paragraph prevents interpreting overlines as document titles + let input11 = dedent """ + Paragraph + + ====== + Title0 + ====== + + +++++++++ + SubTitle0 + +++++++++ + """ + var option11: bool + var rstGenera11: RstGenerator + var output11: string + rstGenera11.initRstGenerator(outHtml, defaultConfig(), "input", {}) + rstGenera11.renderRstToOut(rstParse(input11, "", 1, 1, option11, {}), output11) + doAssert rstGenera11.meta[metaTitle] == "" + doAssert rstGenera11.meta[metaSubTitle] == "" + doAssert "

          Title0

          " in output11 + doAssert "

          SubTitle0

          " in output11 + + # check that RST and Markdown headings don't interfere + let input12 = dedent """ + ====== + Title0 + ====== + + MySection1a + +++++++++++ + + # MySection1b + + MySection1c + +++++++++++ + + ##### MySection5a + + MySection2a + ----------- + """ + var option12: bool + var rstGenera12: RstGenerator + var output12: string + rstGenera12.initRstGenerator(outHtml, defaultConfig(), "input", {}) + rstGenera12.renderRstToOut(rstParse(input12, "", 1, 1, option12, {roSupportMarkdown}), output12) + doAssert rstGenera12.meta[metaTitle] == "Title0" + doAssert rstGenera12.meta[metaSubTitle] == "" + doAssert output12 == + "\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 links": let input1 = """ Want to learn about `my favorite programming language`_? .. _my favorite programming language: https://nim-lang.org""" - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) - assert "" in output1 + let output1 = input1.toHtml + doAssert "
          " in output1
           
             test "Markdown code block":
               let input1 = """
           ```
           let x = 1
           ``` """
          -    let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig())
          -    assert "" in output1
          -    assert "other line
          " in output1 + doAssert output1 == "



          line block
          other line

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


          Paragraph2

          \n" == 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 """ @@ -380,10 +632,10 @@ Test1 5. line5 5 """ - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + let output1 = input1.toHtml for i in 1..5: - assert ($i & ". line" & $i) notin output1 - assert ("
        • line" & $i & " " & $i & "
        • ") in output1 + doAssert ($i & ". line" & $i) notin output1 + doAssert ("
        • line" & $i & " " & $i & "
        • ") in output1 let input2 = dedent """ 3. line3 @@ -402,20 +654,20 @@ Test1 8. line8 """ - let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig()) + let output2 = input2.toHtml for i in [3, 4, 5, 7, 8]: - assert ($i & ". line" & $i) notin output2 - assert ("
        • line" & $i & "
        • ") in output2 + 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 = rstToHtml(input3, {roSupportMarkdown}, defaultConfig()) - assert count(output3, "
            ") == 2 - assert "
          1. string1
          2. " in output3 and "
          3. string2
          4. " in output3 + 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 @@ -428,13 +680,13 @@ Test1 c) string5 e) string6 """ - let output4 = rstToHtml(input4, {roSupportMarkdown}, defaultConfig()) - assert count(output4, "
                ") == 4 + let output4 = input4.toHtml + doAssert count(output4, "
                  ") == 4 for enumerator in [9, 12]: - assert "start=\"$1\"" % [$enumerator] in output4 + doAssert "start=\"$1\"" % [$enumerator] in output4 for enumerator in [2, 5]: # 2=b, 5=e - assert "start=\"$1\"" % [$enumerator] in output4 + doAssert "start=\"$1\"" % [$enumerator] in output4 let input5 = dedent """ Check that auto-numbered enumeration lists work. @@ -448,10 +700,10 @@ Test1 #) string5 #) string6 """ - let output5 = rstToHtml(input5, {roSupportMarkdown}, defaultConfig()) - assert count(output5, "
                    ") == 2 - assert count(output5, "
                  1. ") == 5 + 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. @@ -460,10 +712,10 @@ Test1 #. string2 #. string3 """ - let output5a = rstToHtml(input5a, {roSupportMarkdown}, defaultConfig()) - assert count(output5a, "
                        ") == 1 - assert count(output5a, "
                      1. ") == 3 + let output5a = input5a.toHtml + doAssert count(output5a, "
                          ") == 1 + doAssert count(output5a, "
                        1. ") == 3 let input6 = dedent """ ... And for alphabetic enumerators too! @@ -472,11 +724,11 @@ Test1 #. string2 #. string3 """ - let output6 = rstToHtml(input6, {roSupportMarkdown}, defaultConfig()) - assert count(output6, "
                            ") == 1 - assert count(output6, "
                          1. ") == 3 - assert "start=\"2\"" in output6 and "class=\"loweralpha simple\"" in output6 + 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. @@ -485,11 +737,28 @@ Test1 #. string2 #. string3 """ - let output7 = rstToHtml(input7, {roSupportMarkdown}, defaultConfig()) - assert count(output7, "
                                ") == 1 - assert count(output7, "
                              1. ") == 3 - assert "start=\"3\"" in output7 and "class=\"upperalpha simple\"" in output7 + 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

                                  \n" test "Markdown enumerated lists": let input1 = dedent """ @@ -503,12 +772,12 @@ Test1 #. lineA """ - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + let output1 = input1.toHtml for i in 1..5: - assert ($i & ". line" & $i) notin output1 - assert ("
                                2. line" & $i & "
                                3. ") in output1 - assert count(output1, "
                                    ") == 2 + doAssert ($i & ". line" & $i) notin output1 + doAssert ("
                                  1. line" & $i & "
                                  2. ") in output1 + doAssert count(output1, "
                                      ") == 2 test "RST bullet lists": let input1 = dedent """ @@ -529,11 +798,466 @@ Test1 * line5 5 """ - let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig()) + let output1 = input1.toHtml for i in 1..5: - assert ("
                                    1. line" & $i & " " & $i & "
                                    2. ") in output1 - assert count(output1, "
                                        ") == 1 + doAssert ("
                                      • line" & $i & " " & $i & "
                                      • ") 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 + 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 + 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 + # 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 + 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(error=error5) + check(error5[] == "input(6, 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(error=error6) + check(error6[] == "input(6, 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 + 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(warnings=warnings8) + check(warnings8[] == @["input(4, 1) Warning: unknown substitution " & + "\'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 + #doAssert "id=\"internal-anchor\"" in output9 + #doAssert "internal anchor" notin 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 + 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 + 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 "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 + 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 + 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 + 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 + 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 + 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 + doAssert "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 suite "RST/Code highlight": test "Basic Python code highlight": diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim index efcc9f1262..385e6e651b 100644 --- a/tests/stdlib/tsequtils.nim +++ b/tests/stdlib/tsequtils.nim @@ -15,7 +15,7 @@ block: # concat test s2 = @[4, 5] s3 = @[6, 7] total = concat(s1, s2, s3) - assert total == @[1, 2, 3, 4, 5, 6, 7] + doAssert total == @[1, 2, 3, 4, 5, 6, 7] block: # count test let @@ -35,18 +35,18 @@ block: # count test 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 + 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 @@ -62,9 +62,9 @@ block: # cycle tests 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]] + 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 @@ -80,14 +80,14 @@ block: # deduplicates test 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"] + 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 @@ -100,29 +100,29 @@ block: # zip test 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 + 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) - assert zipAb == @[(a: 1, b: "one"), (2, "two"), (3, "three")] - assert zipAb[2].b == "three" + 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) - 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" + 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] @@ -156,13 +156,13 @@ block: # map test 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] + 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") - assert a == @["142", "242", "342", "442"] + doAssert a == @["142", "242", "342", "442"] block: # filter proc test let @@ -172,34 +172,34 @@ block: # filter proc test 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"] + 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] - assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) == + doAssert 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)) == + 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) - assert floats == @[13.0, 12.5, 10.1] + doAssert 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, """\ + doAssert 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] + doAssert x == @[1, 2, 3] block: # insert tests var dest = @[1, 1, 1, 1, 1, 1, 1, 1] @@ -207,7 +207,7 @@ block: # insert tests 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, """\ + 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]""" @@ -216,57 +216,57 @@ block: # filterIt test 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] + 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') - assert candidates == @["bar", "baz"] + 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] = @[] - 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 + 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] = @[] - 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 + 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] = @[] - 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 + 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] = @[] - 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 + 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: @@ -275,7 +275,7 @@ block: # toSeq test oddNumbers = toSeq(filter(numeric) do (x: int) -> bool: if x mod 2 == 1: result = true) - assert oddNumbers == @[1, 3, 5, 7, 9] + doAssert oddNumbers == @[1, 3, 5, 7, 9] block: doAssert [1, 2].toSeq == @[1, 2] @@ -350,10 +350,10 @@ block: # foldl tests multiplication = foldl(numbers, a * b) words = @["nim", "is", "cool"] concatenation = foldl(words, a & b) - 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" + doAssert addition == 25, "Addition is (((5)+9)+11)" + doAssert subtraction == -15, "Subtraction is (((5)-9)-11)" + doAssert multiplication == 495, "Multiplication is (((5)*9)*11)" + doAssert concatenation == "nimiscool" block: # foldr tests let @@ -363,10 +363,10 @@ block: # foldr tests multiplication = foldr(numbers, a * b) words = @["nim", "is", "cool"] concatenation = foldr(words, a & b) - assert addition == 25, "Addition is (5+(9+(11)))" - assert subtraction == 7, "Subtraction is (5-(9-(11)))" - assert multiplication == 495, "Multiplication is (5*(9*(11)))" - assert concatenation == "nimiscool" + doAssert addition == 25, "Addition is (5+(9+(11)))" + doAssert subtraction == 7, "Subtraction is (5-(9-(11)))" + doAssert multiplication == 495, "Multiplication is (5*(9*(11)))" + doAssert concatenation == "nimiscool" doAssert toSeq(1..3).foldr(a + b) == 6 # issue #14404 block: # mapIt + applyIt test @@ -376,8 +376,8 @@ block: # mapIt + applyIt test strings = nums.identity.mapIt($(4 * it)) doAssert counter == 1 nums.applyIt(it * 3) - assert nums[0] + nums[3] == 15 - assert strings[2] == "12" + doAssert nums[0] + nums[3] == 15 + doAssert strings[2] == "12" block: # newSeqWith tests var seq2D = newSeqWith(4, newSeq[bool](2)) @@ -410,13 +410,11 @@ block: # mapIt with direct openArray template foo2(x: openArray[int]): seq[int] = x.mapIt(it * 10) counter = 0 doAssert foo2(openArray[int]([identity(1), identity(2)])) == @[10, 20] - # TODO: this fails; not sure how to fix this case - # doAssert counter == 2 + doAssert counter == 2 counter = 0 doAssert openArray[int]([identity(1), identity(2)]).mapIt(it) == @[1, 2] - # ditto - # doAssert counter == 2 + doAssert counter == 2 block: # mapIt empty test, see https://github.com/nim-lang/Nim/pull/8584#pullrequestreview-144723468 # NOTE: `[].mapIt(it)` is illegal, just as `let a = @[]` is (lacks type diff --git a/tests/stdlib/tsetutils.nim b/tests/stdlib/tsetutils.nim index d99807f925..f2fb81e6aa 100644 --- a/tests/stdlib/tsetutils.nim +++ b/tests/stdlib/tsetutils.nim @@ -1,14 +1,47 @@ discard """ targets: "c js" """ + import std/setutils +type + Colors = enum + red, green = 5, blue = 10 + Bar = enum + bar0 = -1, bar1, bar2 + template main = - doAssert "abcbb".toSet == {'a', 'b', 'c'} - doAssert toSet([10u8, 12, 13]) == {10u8, 12, 13} - doAssert toSet(0u16..30) == {0u16..30} - type A = distinct char - doAssert [A('x')].toSet == {A('x')} - + block: # toSet + doAssert "abcbb".toSet == {'a', 'b', 'c'} + doAssert toSet([10u8, 12, 13]) == {10u8, 12, 13} + doAssert toSet(0u16..30) == {0u16..30} + type A = distinct char + doAssert [A('x')].toSet == {A('x')} + + block: # fullSet + doAssert fullSet(Colors) == {red, green, blue} + doAssert fullSet(char) == {0.chr..255.chr} + doAssert fullSet(Bar) == {bar0, bar1, bar2} + doAssert fullSet(bool) == {true, false} + + block: # complement + doAssert {red, blue}.complement == {green} + doAssert (complement {red, green, blue}).card == 0 + doAssert (complement {false}) == {true} + doAssert {bar0}.complement == {bar1, bar2} + doAssert {range[0..10](0), 1, 2, 3}.complement == {range[0..10](4), 5, 6, 7, 8, 9, 10} + doAssert {'0'..'9'}.complement == {0.char..255.char} - {'0'..'9'} + + block: # `[]=` + type A = enum + a0, a1, a2, a3 + var s = {a0, a3} + s[a0] = false + s[a1] = false + doAssert s == {a3} + s[a2] = true + s[a3] = true + doAssert s == {a2, a3} + main() -static: main() \ No newline at end of file +static: main() diff --git a/tests/stdlib/tsharedtable.nim b/tests/stdlib/tsharedtable.nim index ce6aa96df8..0a8f7bcc09 100644 --- a/tests/stdlib/tsharedtable.nim +++ b/tests/stdlib/tsharedtable.nim @@ -11,9 +11,9 @@ block: init(table) table[1] = 10 - assert table.mget(1) == 10 - assert table.mgetOrPut(3, 7) == 7 - assert table.mgetOrPut(3, 99) == 7 + doAssert table.mget(1) == 10 + doAssert table.mgetOrPut(3, 7) == 7 + doAssert table.mgetOrPut(3, 99) == 7 deinitSharedTable(table) import sequtils, algorithm diff --git a/tests/stdlib/tsocketstreams.nim b/tests/stdlib/tsocketstreams.nim new file mode 100644 index 0000000000..0cf952810c --- /dev/null +++ b/tests/stdlib/tsocketstreams.nim @@ -0,0 +1,64 @@ +discard """ + output: ''' +OM +NIM +3 +NIM +NIM +Hello server! +Hi there client! +'''""" +import std/socketstreams, net, streams + +block UDP: + var recvSocket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) + var recvStream = newReadSocketStream(recvSocket) + recvSocket.bindAddr(Port(12345), "127.0.0.1") + + var sendSocket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) + sendSocket.connect("127.0.0.1", Port(12345)) + var sendStream = newWriteSocketStream(sendSocket) + sendStream.write "NOM\n" + sendStream.setPosition(1) + echo sendStream.peekStr(2) + sendStream.write "I" + sendStream.setPosition(0) + echo sendStream.readStr(3) + echo sendStream.getPosition() + sendStream.flush() + + echo recvStream.readLine() + recvStream.setPosition(0) + echo recvStream.readLine() + recvStream.close() + +block TCP: + var server = newSocket() + server.setSockOpt(OptReusePort, true) + server.bindAddr(Port(12345)) + server.listen() + + var + client = newSocket() + clientRequestStream = newWriteSocketStream(client) + clientResponseStream = newReadSocketStream(client) + client.connect("127.0.0.1", Port(12345)) + clientRequestStream.writeLine("Hello server!") + clientRequestStream.flush() + + var + incoming: Socket + address: string + server.acceptAddr(incoming, address) + var + serverRequestStream = newReadSocketStream(incoming) + serverResponseStream = newWriteSocketStream(incoming) + echo serverRequestStream.readLine() + serverResponseStream.writeLine("Hi there client!") + serverResponseStream.flush() + serverResponseStream.close() + serverRequestStream.close() + + echo clientResponseStream.readLine() + clientResponseStream.close() + clientRequestStream.close() diff --git a/tests/stdlib/tstdlib_various.nim b/tests/stdlib/tstdlib_various.nim index cddd43f6e1..b153fd2ba7 100644 --- a/tests/stdlib/tstdlib_various.nim +++ b/tests/stdlib/tstdlib_various.nim @@ -38,7 +38,7 @@ true """ import - critbits, cstrutils, sets, strutils, tables, random, algorithm, re, ropes, + critbits, sets, strutils, tables, random, algorithm, re, ropes, segfaults, lists, parsesql, streams, os, htmlgen, xmltree, strtabs @@ -245,24 +245,3 @@ block txmltree: ]) ]) doAssert(y.innerText == "foobar") - - -block tcstrutils: - let s = cstring "abcdef" - doAssert s.startsWith("a") - doAssert not s.startsWith("b") - doAssert s.endsWith("f") - doAssert not s.endsWith("a") - - let a = cstring "abracadabra" - doAssert a.startsWith("abra") - doAssert not a.startsWith("bra") - doAssert a.endsWith("abra") - doAssert not a.endsWith("dab") - - 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 diff --git a/tests/stdlib/tstrbasics.nim b/tests/stdlib/tstrbasics.nim new file mode 100644 index 0000000000..b340ad509e --- /dev/null +++ b/tests/stdlib/tstrbasics.nim @@ -0,0 +1,103 @@ +discard """ + targets: "c cpp js" + matrix: "--gc:refc; --gc:arc" +""" + +import std/[strbasics, sugar] + +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/tstrformat.nim b/tests/stdlib/tstrformat.nim index d483093a76..86100e4216 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -1,515 +1,501 @@ -discard """ -action: "run" -output: '''Received (name: "Foo", species: "Bar")''' -""" - -# issue #7632 +# xxx: test js target import genericstrformat -import strutils, times +import std/[strformat, strutils, times] +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" -doAssert works(5) == "formatted 5" -doAssert fails0(6) == "formatted 6" -doAssert fails(7) == "formatted 7" -doAssert fails2[0](8) == "formatted 8" + block: # other tests + type Obj = object -# other tests + proc `$`(o: Obj): string = "foobar" -import strformat + # for custom types, formatValue needs to be overloaded. + template formatValue(result: var string; value: Obj; specifier: string) = + result.formatValue($value, specifier) -type Obj = object + var o: Obj + doAssert fmt"{o}" == "foobar" + doAssert fmt"{o:10}" == "foobar " -proc `$`(o: Obj): string = "foobar" + doAssert fmt"{o=}" == "o=foobar" + doAssert fmt"{o=:10}" == "o=foobar " -# for custom types, formatValue needs to be overloaded. -template formatValue(result: var string; value: Obj; specifier: string) = - result.formatValue($value, specifier) + 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 :: " -var o: Obj -doAssert fmt"{o}" == "foobar" -doAssert fmt"{o:10}" == "foobar " + 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 :: " -doAssert fmt"{o=}" == "o=foobar" -doAssert fmt"{o=:10}" == "o=foobar " + 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" + 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" -# 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 :: " + 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 -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 :: " + 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 -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" + 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"^7.4 :: {str=:^7.4}" == "^7.4 :: str= äöüe " -doAssert fmt"^7.9 :: {str=:^7.9}" == "^7.9 :: str=äöüe\u0309\u0319o\u0307\u0359" + 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" -# 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 + block: # seq format + 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 + 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 "]" -# 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"data1: {data1:8} #" == "data1: [ 1, 10000, 10000000] #" + doAssert fmt"data2: {data2:8} =" == "data2: [10000000, 100, 1] =" -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" + doAssert fmt"data1: {data1=:8} #" == "data1: data1=[ 1, 10000, 10000000] #" + doAssert fmt"data2: {data2=:8} =" == "data2: data2=[10000000, 100, 1] =" -# seq format + block: # custom format Value + type + Vec2[T] = object + x,y: T -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: + proc formatValue[T](result: var string; value: Vec2[T]; specifier: string) = + result.add '[' + result.formatValue value.x, specifier 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] =" - -# 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 - result.add ", " - result.formatValue value.y, 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]" - -# bug #11012 - -type - Animal = object - name, species: string - AnimalRef = ref Animal - -proc print_object(animalAddr: AnimalRef) = - echo fmt"Received {animalAddr[]}" - -print_object(AnimalRef(name: "Foo", species: "Bar")) - -# 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" - -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" - - -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" - -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" - -# bug #12612 -proc my_proc = - const value = "value" - const a = &"{value}" - assert a == value - - const b = &"{value=}" - assert b == "value=" & value - -my_proc() - -block: - template fmt(pattern: string; openCloseChar: char): untyped = - fmt(pattern, openCloseChar, openCloseChar) - - 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 - """ - - -# tests from the very own strformat documentation! - -let msg = "hello" -doAssert fmt"{msg}\n" == "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" - -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" - -## tests for debug format string -block: - 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" - - -# It is space sensitive. -block: - 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: - - 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" - - doAssert fmt"{'a'} {'b'}" == "a b" \ No newline at end of file + result.formatValue value.y, 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]" + + block: # bug #11012 + type + Animal = object + name, species: string + AnimalRef = ref Animal + + proc print_object(animalAddr: AnimalRef): string = + fmt"Received {animalAddr[]}" + + doAssert print_object(AnimalRef(name: "Foo", species: "Bar")) == """Received (name: "Foo", species: "Bar")""" + + 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" + + 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" + + 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" + + 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" + + block: # bug #12612 + proc my_proc() = + const value = "value" + const a = &"{value}" + doAssert a == value + + const b = &"{value=}" + doAssert b == "value=" & value + + my_proc() + + block: + template fmt(pattern: string; openCloseChar: char): untyped = + fmt(pattern, openCloseChar, openCloseChar) + + 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 + """ + + block: # tests from the very own strformat documentation! + let msg = "hello" + doAssert fmt"{msg}\n" == "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" + + 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" + + 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: + + 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" + + doAssert fmt"{'a'} {'b'}" == "a b" + + block: # test low(int64) + doAssert &"{low(int64):-}" == "-9223372036854775808" + +# xxx static: main() +main() diff --git a/tests/stdlib/tstring.nim b/tests/stdlib/tstring.nim index 4d5a15940e..3e2ccb2518 100644 --- a/tests/stdlib/tstring.nim +++ b/tests/stdlib/tstring.nim @@ -2,105 +2,121 @@ discard """ targets: "c cpp js" """ -const characters = "abcdefghijklmnopqrstuvwxyz" -const numbers = "1234567890" - -proc test_string_slice() = - # 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] - - -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 - - -#-------------------------- -# bug #7816 -import sugar -import sequtils +from std/sequtils import toSeq, map +from std/sugar import `=>` proc tester[T](x: T) = let test = toSeq(0..4).map(i => newSeq[int]()) doAssert $test == "@[@[], @[], @[], @[], @[]]" - - -# #14497 func reverse*(a: string): string = result = a for i in 0 ..< a.len div 2: swap(result[i], result[^(i + 1)]) - proc main() = - test_string_slice() - test_string_cmp() + block: # .. + const + characters = "abcdefghijklmnopqrstuvwxyz" + numbers = "1234567890" - tester(1) - doAssert reverse("hello") == "olleh" + # 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/tstrtabs.nim b/tests/stdlib/tstrtabs.nim index d4344f95fc..f629c183c3 100644 --- a/tests/stdlib/tstrtabs.nim +++ b/tests/stdlib/tstrtabs.nim @@ -105,12 +105,12 @@ writeLine(stdout, "length of table ", $tab.len) block: var x = {"k": "v", "11": "22", "565": "67"}.newStringTable - assert x["k"] == "v" - assert x["11"] == "22" - assert x["565"] == "67" + doAssert x["k"] == "v" + doAssert x["11"] == "22" + doAssert x["565"] == "67" x["11"] = "23" - assert x["11"] == "23" + doAssert x["11"] == "23" x.clear(modeCaseInsensitive) x["11"] = "22" - assert x["11"] == "22" + doAssert x["11"] == "22" diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index 8d6fe75ae9..a6248d1e3b 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -58,9 +58,9 @@ template main() = block: # splitLines 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"] + 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"] @@ -83,207 +83,207 @@ template main() = block: # removeSuffix var s = "hello\n\r" s.removeSuffix - assert s == "hello" + doAssert s == "hello" s.removeSuffix - assert s == "hello" + doAssert s == "hello" s = "hello\n\n" s.removeSuffix - assert s == "hello" + doAssert s == "hello" s = "hello\r" s.removeSuffix - assert s == "hello" + doAssert s == "hello" s = "hello \n there" s.removeSuffix - assert s == "hello \n there" + doAssert s == "hello \n there" s = "hello" s.removeSuffix("llo") - assert s == "he" + doAssert s == "he" s.removeSuffix('e') - assert s == "h" + doAssert s == "h" s = "hellos" s.removeSuffix({'s','z'}) - assert s == "hello" + doAssert s == "hello" s.removeSuffix({'l','o'}) - assert s == "he" + doAssert s == "he" s = "aeiou" s.removeSuffix("") - assert s == "aeiou" + doAssert s == "aeiou" s = "" s.removeSuffix("") - assert s == "" + doAssert s == "" s = " " s.removeSuffix - assert s == " " + doAssert s == " " s = " " s.removeSuffix("") - assert s == " " + doAssert s == " " s = " " s.removeSuffix(" ") - assert s == " " + doAssert s == " " s = " " s.removeSuffix(' ') - assert s == "" + doAssert 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" + doAssert s == "hello\r\n\r\n" block: # removePrefix var s = "\n\rhello" s.removePrefix - assert s == "hello" + doAssert s == "hello" s.removePrefix - assert s == "hello" + doAssert s == "hello" s = "\n\nhello" s.removePrefix - assert s == "hello" + doAssert s == "hello" s = "\rhello" s.removePrefix - assert s == "hello" + doAssert s == "hello" s = "hello \n there" s.removePrefix - assert s == "hello \n there" + doAssert s == "hello \n there" s = "hello" s.removePrefix("hel") - assert s == "lo" + doAssert s == "lo" s.removePrefix('l') - assert s == "o" + doAssert s == "o" s = "hellos" s.removePrefix({'h','e'}) - assert s == "llos" + doAssert s == "llos" s.removePrefix({'l','o'}) - assert s == "s" + doAssert s == "s" s = "aeiou" s.removePrefix("") - assert s == "aeiou" + doAssert s == "aeiou" s = "" s.removePrefix("") - assert s == "" + doAssert s == "" s = " " s.removePrefix - assert s == " " + doAssert s == " " s = " " s.removePrefix("") - assert s == " " + doAssert s == " " s = " " s.removePrefix(" ") - assert s == " " + doAssert s == " " s = " " s.removePrefix(' ') - assert s == "" + doAssert 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" + doAssert s == "\r\n\r\nhello" block: # delete var s = "0123456789ABCDEFGH" delete(s, 4, 5) - assert s == "01236789ABCDEFGH" + doAssert s == "01236789ABCDEFGH" delete(s, s.len-1, s.len-1) - assert s == "01236789ABCDEFG" + doAssert s == "01236789ABCDEFG" delete(s, 0, 0) - assert s == "1236789ABCDEFG" + doAssert s == "1236789ABCDEFG" block: # find - 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 + doAssert "0123456789ABCDEFGH".find('A') == 10 + doAssert "0123456789ABCDEFGH".find('A', 5) == 10 + doAssert "0123456789ABCDEFGH".find('A', 5, 10) == 10 + doAssert "0123456789ABCDEFGH".find('A', 5, 9) == -1 + doAssert "0123456789ABCDEFGH".find("A") == 10 + doAssert "0123456789ABCDEFGH".find("A", 5) == 10 + doAssert "0123456789ABCDEFGH".find("A", 5, 10) == 10 + doAssert "0123456789ABCDEFGH".find("A", 5, 9) == -1 + doAssert "0123456789ABCDEFGH".find({'A'..'C'}) == 10 + doAssert "0123456789ABCDEFGH".find({'A'..'C'}, 5) == 10 + doAssert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 10) == 10 + doAssert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 9) == -1 block: # rfind - 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 + 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 - assert "/1/2/3".rfind('/') == 4 - assert "/1/2/3".rfind('/', last=1) == 0 - assert "/1/2/3".rfind('0') == -1 + doAssert "/1/2/3".rfind('/') == 4 + doAssert "/1/2/3".rfind('/', last=1) == 0 + doAssert "/1/2/3".rfind('0') == -1 block: # trimZeros var x = "1200" x.trimZeros() - assert x == "1200" + doAssert x == "1200" x = "120.0" x.trimZeros() - assert x == "120" + doAssert x == "120" x = "0." x.trimZeros() - assert x == "0" + doAssert x == "0" x = "1.0e2" x.trimZeros() - assert x == "1e2" + doAssert x == "1e2" x = "78.90" x.trimZeros() - assert x == "78.9" + doAssert x == "78.9" x = "1.23e4" x.trimZeros() - assert x == "1.23e4" + doAssert x == "1.23e4" x = "1.01" x.trimZeros() - assert x == "1.01" + doAssert x == "1.01" x = "1.1001" x.trimZeros() - assert x == "1.1001" + doAssert x == "1.1001" x = "0.0" x.trimZeros() - assert x == "0" + doAssert x == "0" x = "0.01" x.trimZeros() - assert x == "0.01" + doAssert x == "0.01" x = "1e0" x.trimZeros() - assert x == "1e0" + doAssert x == "1e0" block: # countLines - proc assertCountLines(s: string) = assert s.countLines == s.splitLines.len + proc assertCountLines(s: string) = doAssert s.countLines == s.splitLines.len assertCountLines("") assertCountLines("\n") assertCountLines("\n\n") @@ -295,36 +295,36 @@ template main() = block: # parseBinInt, parseHexInt, parseOctInt # 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 + 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 - 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 + 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 - assert "0o17".parseOctInt == 15 - assert "0O17".parseOctInt == 15 - assert "17".parseOctInt == 15 - assert "10".parseOctInt == 8 - assert "0o1_0_0".parseOctInt == 64 + 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 @@ -333,53 +333,53 @@ template main() = rejectParse "reject".parseOctInt block: # parseHexStr - assert "".parseHexStr == "" - assert "00Ff80".parseHexStr == "\0\xFF\x80" + doAssert "".parseHexStr == "" + doAssert "00Ff80".parseHexStr == "\0\xFF\x80" try: discard "00Ff8".parseHexStr - assert false, "Should raise ValueError" + doAssert false, "Should raise ValueError" except ValueError: discard try: discard "0k".parseHexStr - assert false, "Should raise ValueError" + doAssert false, "Should raise ValueError" except ValueError: discard - assert "".toHex == "" - assert "\x00\xFF\x80".toHex == "00FF80" - assert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF" + doAssert "".toHex == "" + doAssert "\x00\xFF\x80".toHex == "00FF80" + doAssert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF" block: # toHex - assert(toHex(100i16, 32) == "00000000000000000000000000000064") - assert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") + doAssert(toHex(100i16, 32) == "00000000000000000000000000000064") + doAssert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") when not defined js: - assert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF") - assert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF") - assert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF") + doAssert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF") + doAssert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF") + doAssert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF") block: # insertSep - assert(insertSep($1000_000) == "1_000_000") - assert(insertSep($232) == "232") - assert(insertSep($12345, ',') == "12,345") - assert(insertSep($0) == "0") + doAssert(insertSep($1000_000) == "1_000_000") + doAssert(insertSep($232) == "232") + doAssert(insertSep($12345, ',') == "12,345") + doAssert(insertSep($0) == "0") block: # repeat, spaces - assert(' '.repeat(8) == " ") - assert(" ".repeat(8) == " ") - assert(spaces(8) == " ") + doAssert(' '.repeat(8) == " ") + doAssert(" ".repeat(8) == " ") + doAssert(spaces(8) == " ") - assert(' '.repeat(0) == "") - assert(" ".repeat(0) == "") - assert(spaces(0) == "") + doAssert(' '.repeat(0) == "") + doAssert(" ".repeat(0) == "") + doAssert(spaces(0) == "") block: # toBin, toOct block:# bug #11369 var num: int64 = -1 when not defined js: - assert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111" - assert num.toOct(24) == "001777777777777777777777" + doAssert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111" + doAssert num.toOct(24) == "001777777777777777777777" block: # replace doAssert "oo".replace("", "abc") == "oo" @@ -499,26 +499,26 @@ template main() = doAssert parseEnum("invalid enum value", enC) == enC block: # indentation - assert 0 == indentation """ + doAssert 0 == indentation """ hey low there """ - assert 2 == indentation """ + doAssert 2 == indentation """ hey low there """ - assert 2 == indentation """ hey + doAssert 2 == indentation """ hey low there """ - assert 2 == indentation """ hey + doAssert 2 == indentation """ hey low there""" - assert 0 == indentation "" - assert 0 == indentation " \n \n" - assert 0 == indentation " " + doAssert 0 == indentation "" + doAssert 0 == indentation " \n \n" + doAssert 0 == indentation " " block: # indent doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim index cca1fe75a7..72abadae77 100644 --- a/tests/stdlib/tsugar.nim +++ b/tests/stdlib/tsugar.nim @@ -1,110 +1,233 @@ -import sugar +discard """ + output: ''' +x + y = 30 +''' +""" +import std/[sugar, algorithm, random, sets, tables, strutils] -block dup_with_field: - type - Foo = object - col, pos: int - name: string +template main() = + block: # `=>` + block: + let f1 = () => 42 + doAssert f1() == 42 - 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 f2 = (x: int) => x + 1 + doAssert f2(42) == 43 - 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 + let f3 = (x, y: int) => x + y + doAssert f3(1, 2) == 3 - doAssert(b == Foo(col: 2, pos: 4, name: "foobar")) + var x = 0 + let f4 = () => (x = 12) + f4() + doAssert x == 12 - block: - let b = a.dup(inc_col, pos = 3, name = "bar"): - name_append("bar") - inc_pos + let f5 = () => (discard) # simplest proc that returns void + f5() - doAssert(b == Foo(col: 2, pos: 4, name: "barbar")) + block: + proc call1(f: () -> int): int = f() + doAssert call1(() => 12) == 12 -import algorithm + proc call2(f: int -> int): int = f(42) + doAssert call2(x => x) == 42 + doAssert call2((x) => x) == 42 + doAssert call2((x: int) => x) == 42 -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) + 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 -import random + var a = 0 + proc call4(f: int -> void) = f(42) + call4((x: int) => (a = x)) + doAssert a == 42 -const b = @[0, 1, 2] -let c = b.dup shuffle() -doAssert b[0] == 0 -doAssert b[1] == 1 + proc call5(f: (int {.noSideEffect.} -> int)): int = f(42) + doAssert call5(x {.noSideEffect.} => x + 1) == 43 -#test collect -import sets, tables + 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.}" -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}) == {0: "bird", - 1: "word"}.toTable -assert initHashSet.collect(for d in data.items: {d}) == data.toHashSet + 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.}" -let x = collect(newSeqOfCap(4)): - for (i, d) in data.pairs: - if i mod 2 == 0: d -assert x == @["bird"] + 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.}" -# bug #12874 + block: # capture + var closure1: () -> int + for i in 0 .. 10: + if i == 5: + capture i: + closure1 = () => i + doAssert closure1() == 5 -let bug1 = collect( - newSeq, - for (i, d) in data.pairs:( + 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: # 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: - if i mod 2 == 0: - d - else: - d & d + 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 + ) ) -) -assert bug1 == @["bird", "wordword"] + doAssert bug == @["bird", "wordword"] -import strutils -let y = collect(newSeq): - for (i, d) in data.pairs: - try: parseInt(d) except: 0 -assert y == @[0, 0] + block: + let y = collect(newSeq): + for (i, d) in data.pairs: + try: parseInt(d) except: 0 + doAssert y == @[0, 0] -let z = collect(newSeq): - for (i, d) in data.pairs: - case d - of "bird": "word" - else: d -assert z == @["word", "word"] + block: + let z = collect(newSeq): + for (i, d) in data.pairs: + case d + of "bird": "word" + else: d + doAssert z == @["word", "word"] -proc tforum = - let ans = collect(newSeq): - for y in 0..10: - if y mod 5 == 2: - for x in 0..y: - x -tforum() + 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 - assert x == @["bird", "word"] -assert collect(for (i, d) in pairs(data): (i, d)) == @[(0, "bird"), (1, "word")] -assert collect(for d in data.items: (try: parseInt(d) except: 0)) == @[0, 0] -assert collect(for (i, d) in pairs(data): {i: d}) == {1: "word", - 0: "bird"}.toTable -assert collect(for d in data.items: {d}) == data.toHashSet + block: + let x = collect: + for d in data.items: + when d is int: "word" + else: d + doAssert x == @["bird", "word"] -# bug #14332 -template foo = - discard collect(newSeq, for i in 1..3: i) -foo() \ No newline at end of file + 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 + +static: + main() + mainProc() +main() +mainProc() diff --git a/tests/stdlib/tsums.nim b/tests/stdlib/tsums.nim index 979ffc391c..4c29d3e106 100644 --- a/tests/stdlib/tsums.nim +++ b/tests/stdlib/tsums.nim @@ -5,18 +5,18 @@ 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 in 64 bits -assert (1.0 + epsilon) - epsilon != 1.0 +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 -assert sumKbn(tc1) == 7.485470860550345 -assert sumPairs(tc1) == 7.485470860550345 +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 -assert sumKbn(tc2) == -0.6926474305598203 -assert sumPairs(tc2) == -0.6926474305598204 +doAssert sumKbn(tc2) == -0.6926474305598203 +doAssert sumPairs(tc2) == -0.6926474305598204 diff --git a/tests/stdlib/tsysrand.nim b/tests/stdlib/tsysrand.nim new file mode 100644 index 0000000000..c6d43a8fbc --- /dev/null +++ b/tests/stdlib/tsysrand.nim @@ -0,0 +1,34 @@ +discard """ + targets: "c cpp js" + matrix: "--experimental:vmopsDanger" +""" + +import std/sysrand + + +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/ttables.nim b/tests/stdlib/ttables.nim index 656d7be6bc..c1ae89b320 100644 --- a/tests/stdlib/ttables.nim +++ b/tests/stdlib/ttables.nim @@ -59,8 +59,8 @@ block: # Deletion from OrderedTable should account for collision groups. See iss }.toOrderedTable() t.del(key1) - assert(t.len == 1) - assert(key2 in t) + doAssert(t.len == 1) + doAssert(key2 in t) var t1 = initCountTable[string]() @@ -72,9 +72,9 @@ 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) +doAssert(t1["foo"] == 5) +doAssert(t1["bar"] == 3) +doAssert(t1["baz"] == 14) let t1r = newCountTable[string]() @@ -86,9 +86,9 @@ 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) +doAssert(t1r["foo"] == 5) +doAssert(t1r["bar"] == 3) +doAssert(t1r["baz"] == 14) var t1l = initCountTable[string]() @@ -127,28 +127,28 @@ block: #5482 var b = newOrderedTable[string, string](initialSize = 2) b["wrong?"] = "foo" b["wrong?"] = "foo2" - assert a == b + 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" - assert a == b + 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" - assert a == b + 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" - assert a == b + doAssert a == b block: var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable() @@ -156,22 +156,22 @@ block: var c = newOrderedTable[string, string]() # notice, default size! c["wrong?"] = "foo" c["wrong?"] = "foo2" - assert a == b - assert a == c + doAssert a == b + doAssert a == c block: #6250 let a = {3: 1}.toOrderedTable b = {3: 2}.toOrderedTable - assert((a == b) == false) - assert((b == a) == false) + doAssert((a == b) == false) + doAssert((b == a) == false) block: #6250 let a = {3: 2}.toOrderedTable b = {3: 2}.toOrderedTable - assert((a == b) == true) - assert((b == a) == true) + doAssert((a == b) == true) + doAssert((b == a) == true) block: # CountTable.smallest let t = toCountTable([0, 0, 5, 5, 5]) diff --git a/tests/stdlib/tthreadpool.nim b/tests/stdlib/tthreadpool.nim new file mode 100644 index 0000000000..897c7d1735 --- /dev/null +++ b/tests/stdlib/tthreadpool.nim @@ -0,0 +1,14 @@ +discard """ + matrix: "--threads:on --gc:arc" + disabled: "freebsd" + output: "42" +""" + +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 a7677edf96..66157b91c2 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -84,6 +84,10 @@ 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") @@ -116,7 +120,7 @@ template usingTimezone(tz: string, body: untyped) = body putEnv("TZ", oldZone) -suite "ttimes": +block: # ttimes # Generate tests for multiple timezone files where available # Set the TZ env var for each test @@ -143,7 +147,7 @@ suite "ttimes": test "parseTest": runTimezoneTests() - test "dst handling": + block: # dst handling usingTimezone("Europe/Stockholm"): # In case of an impossible time, the time is moved to after the # impossible time period @@ -163,7 +167,7 @@ suite "ttimes": check initDateTime(21, mOct, 2017, 01, 00, 00).format(f) == "2017-10-21 01:00 +02:00" - test "issue #6520": + block: # issue #6520 usingTimezone("Europe/Stockholm"): var local = fromUnix(1469275200).local var utc = fromUnix(1469275200).utc @@ -172,19 +176,19 @@ suite "ttimes": local.utcOffset = 0 check claimedOffset == utc.toTime - local.toTime - test "issue #5704": + block: # issue #5704 usingTimezone("Asia/Seoul"): let diff = parse("19700101-000000", "yyyyMMdd-hhmmss").toTime - parse("19000101-000000", "yyyyMMdd-hhmmss").toTime check diff == initDuration(seconds = 2208986872) - test "issue #6465": + block: # 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" - test "adding/subtracting time across dst": + block: # 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" @@ -192,55 +196,55 @@ suite "ttimes": var dt2 = initDateTime(29, mOct, 2017, 02, 59, 59) check $(dt2 + 1.seconds) == "2017-10-29T02:00:00+01:00" - test "datetime before epoch": + block: # datetime before epoch check $fromUnix(-2147483648).utc == "1901-12-13T20:45:52Z" - test "incorrect inputs: empty string": + block: # incorrect inputs: empty string parseTestExcp("", "yyyy-MM-dd") - test "incorrect inputs: year": + block: # incorrect inputs: year parseTestExcp("20-02-19", "yyyy-MM-dd") - test "incorrect inputs: month number": + block: # incorrect inputs: month number parseTestExcp("2018-2-19", "yyyy-MM-dd") - test "incorrect inputs: month name": + block: # incorrect inputs: month name parseTestExcp("2018-Fe", "yyyy-MMM-dd") - test "incorrect inputs: day": + block: # incorrect inputs: day parseTestExcp("2018-02-1", "yyyy-MM-dd") - test "incorrect inputs: day of week": + block: # incorrect inputs: day of week parseTestExcp("2018-Feb-Mo", "yyyy-MMM-ddd") - test "incorrect inputs: hour": + block: # incorrect inputs: hour parseTestExcp("2018-02-19 1:30", "yyyy-MM-dd hh:mm") - test "incorrect inputs: minute": + block: # incorrect inputs: minute parseTestExcp("2018-02-19 16:3", "yyyy-MM-dd hh:mm") - test "incorrect inputs: second": + block: # incorrect inputs: second parseTestExcp("2018-02-19 16:30:0", "yyyy-MM-dd hh:mm:ss") - test "incorrect inputs: timezone (z)": + block: # incorrect inputs: timezone (z) parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss z") - test "incorrect inputs: timezone (zz) 1": + block: # incorrect inputs: timezone (zz) 1 parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zz") - test "incorrect inputs: timezone (zz) 2": + block: # incorrect inputs: timezone (zz) 2 parseTestExcp("2018-02-19 16:30:00 +1", "yyyy-MM-dd hh:mm:ss zz") - test "incorrect inputs: timezone (zzz) 1": + block: # incorrect inputs: timezone (zzz) 1 parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zzz") - test "incorrect inputs: timezone (zzz) 2": + block: # incorrect inputs: timezone (zzz) 2 parseTestExcp("2018-02-19 16:30:00 +01:", "yyyy-MM-dd hh:mm:ss zzz") - test "incorrect inputs: timezone (zzz) 3": + block: # incorrect inputs: timezone (zzz) 3 parseTestExcp("2018-02-19 16:30:00 +01:0", "yyyy-MM-dd hh:mm:ss zzz") - test "incorrect inputs: year (yyyy/uuuu)": + block: # incorrect inputs: year (yyyy/uuuu) parseTestExcp("-0001", "yyyy") parseTestExcp("-0001", "YYYY") parseTestExcp("1", "yyyy") @@ -249,7 +253,7 @@ suite "ttimes": parseTestExcp("12345", "uuuu") parseTestExcp("-1 BC", "UUUU g") - test "incorrect inputs: invalid sign": + block: # incorrect inputs: invalid sign parseTestExcp("+1", "YYYY") parseTestExcp("+1", "dd") parseTestExcp("+1", "MM") @@ -257,10 +261,10 @@ suite "ttimes": parseTestExcp("+1", "mm") parseTestExcp("+1", "ss") - test "_ as a separator": + block: # _ as a separator discard parse("2000_01_01", "YYYY'_'MM'_'dd") - test "dynamic timezone": + block: # dynamic timezone let tz = staticTz(seconds = -9000) let dt = initDateTime(1, mJan, 2000, 12, 00, 00, tz) check dt.utcOffset == -9000 @@ -269,13 +273,13 @@ suite "ttimes": check $dt.utc == "2000-01-01T09:30:00Z" check $dt.utc.inZone(tz) == $dt - test "isLeapYear": + block: # isLeapYear check isLeapYear(2016) check (not isLeapYear(2015)) check isLeapYear(2000) check (not isLeapYear(1900)) - test "TimeInterval": + block: # TimeInterval let t = fromUnix(876124714).utc # Mon 6 Oct 08:58:34 BST 1997 # Interval tests let t2 = t - 2.years @@ -287,7 +291,7 @@ suite "ttimes": check (t + 1.hours).toTime.toUnix == t.toTime.toUnix + 60 * 60 check (t - 1.hours).toTime.toUnix == t.toTime.toUnix - 60 * 60 - test "TimeInterval - months": + block: # 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()) @@ -296,7 +300,7 @@ suite "ttimes": # This happens due to monthday overflow. It's consistent with Phobos. check $(dt - initTimeInterval(months = 1)) == "2017-03-03T00:00:00Z" - test "duration": + block: # 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) @@ -316,7 +320,7 @@ suite "ttimes": check (initDuration(seconds = 1, nanoseconds = 3) <= initDuration(seconds = 1, nanoseconds = 1)).not - test "large/small dates": + block: # 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) @@ -328,7 +332,7 @@ suite "ttimes": let dt2 = dt + 35_001.years check $dt2 == "0001-01-01T12:00:01Z" - test "compare datetimes": + block: # compare datetimes var dt1 = now() var dt2 = dt1 check dt1 == dt2 @@ -336,7 +340,7 @@ suite "ttimes": dt2 = dt2 + 1.seconds check dt1 < dt2 - test "adding/subtracting TimeInterval": + block: # adding/subtracting TimeInterval # add/subtract TimeIntervals and Time/TimeInfo let now = getTime().utc let isSpecial = now.isLeapDay @@ -374,14 +378,14 @@ suite "ttimes": check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100 check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100 - test "issue 7620": + block: # 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" - test "format": + block: # format var dt = initDateTime(1, mJan, -0001, 17, 01, 02, 123_456_789, staticTz(hours = 1, minutes = 2, seconds = 3)) @@ -450,7 +454,7 @@ suite "ttimes": doAssert dt.format("zz") == tz[2] doAssert dt.format("zzz") == tz[3] - test "format locale": + block: # 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"], @@ -467,7 +471,7 @@ suite "ttimes": check dt.format("MMM", loc) == "Fir" check dt.format("MMMM", loc) == "Firsty" - test "parse": + block: # parse check $parse("20180101", "yyyyMMdd", utc()) == "2018-01-01T00:00:00Z" parseTestExcp("+120180101", "yyyyMMdd") @@ -488,7 +492,7 @@ suite "ttimes": parseTestExcp("2000 A", "yyyy g") - test "parse locale": + block: # 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"], @@ -498,7 +502,7 @@ suite "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" - test "timezoneConversion": + block: # timezoneConversion var l = now() let u = l.utc l = u.local @@ -506,7 +510,7 @@ suite "ttimes": check l.timezone == local() check u.timezone == utc() - test "getDayOfWeek": + block: # getDayOfWeek check getDayOfWeek(01, mJan, 0000) == dSat check getDayOfWeek(01, mJan, -0023) == dSat check getDayOfWeek(21, mSep, 1900) == dFri @@ -515,29 +519,29 @@ suite "ttimes": check getDayOfWeek(01, mJan, 2000) == dSat check getDayOfWeek(01, mJan, 2021) == dFri - test "between - simple": + block: # 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 - test "between - dst start": + block: # 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 - test "between - empty interval": + block: # between - empty interval let x = now() let y = x doAssert x + between(x, y) == y - test "between - dst end": + block: # 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 - test "between - long day": + block: # between - long day usingTimezone("Europe/Stockholm"): # This day is 25 hours long in Europe/Stockholm let x = initDateTime(28, mOct, 2018, 00, 30, 00) @@ -545,7 +549,7 @@ suite "ttimes": doAssert between(x, y) == 24.hours + 30.minutes doAssert x + between(x, y) == y - test "between - offset change edge case": + block: # 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"): @@ -554,19 +558,19 @@ suite "ttimes": doAssert x + between(x, y) == y doAssert y + between(y, x) == x - test "between - all units": + block: # 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 - test "between - monthday overflow": + block: # 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 - test "between - misc": + block: # between - misc block: let x = initDateTime(31, mDec, 2000, 12, 00, 00, utc()) let y = initDateTime(01, mJan, 2001, 00, 00, 00, utc()) @@ -608,7 +612,7 @@ suite "ttimes": doAssert x + between(x, y) == y doAssert between(x, y) == 1.months + 1.weeks - test "default DateTime": # https://github.com/nim-lang/RFCs/issues/211 + block: # default DateTime https://github.com/nim-lang/RFCs/issues/211 var num = 0 for ai in Month: num.inc check num == 12 @@ -634,7 +638,7 @@ suite "ttimes": expect(AssertionDefect): discard a.format initTimeFormat("yyyy") expect(AssertionDefect): discard between(a, a) - test "inX procs": + block: # inX procs doAssert initDuration(seconds = 1).inSeconds == 1 doAssert initDuration(seconds = -1).inSeconds == -1 doAssert initDuration(seconds = -1, nanoseconds = 1).inSeconds == 0 diff --git a/tests/stdlib/ttypeinfo.nim b/tests/stdlib/ttypeinfo.nim index fc0bd3e53e..61c661a58e 100644 --- a/tests/stdlib/ttypeinfo.nim +++ b/tests/stdlib/ttypeinfo.nim @@ -17,16 +17,16 @@ var test = @[0,1,2,3,4] var x = toAny(test) var y = 78 x[4] = toAny(y) -assert x[2].getInt == 2 +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: assert n == "Field0" and $a.kind == "akString" - of 1: assert n == "Field1" and $a.kind == "akInt" - else: assert false + 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 @@ -36,17 +36,17 @@ var x3 = toAny(test3) i = 0 for n, a in fields(x3): case i - of 0: assert n == "test" and $a.kind == "akInt" - of 1: assert n == "asd" and $a.kind == "akInt" - of 2: assert n == "test2" and $a.kind == "akEnum" - else: assert false + 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) -assert($x4[].kind() == "akString") +doAssert($x4[].kind() == "akString") block: # gimme a new scope dammit diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim index 4b82df67be..97a45e199b 100644 --- a/tests/stdlib/tunittest.nim +++ b/tests/stdlib/tunittest.nim @@ -22,7 +22,7 @@ discard """ targets: "c js" """ -import unittest, sequtils +import std/[unittest, sequtils] proc doThings(spuds: var int): int = spuds = 24 @@ -33,12 +33,12 @@ test "#964": check spuds == 24 -from strutils import toUpperAscii +from std/strutils import toUpperAscii test "#1384": check(@["hello", "world"].map(toUpperAscii) == @["HELLO", "WORLD"]) -import options +import std/options test "unittest typedescs": check(none(int) == none(int)) check(none(int) != some(1)) @@ -49,14 +49,14 @@ test "unittest multiple requires": require(true) -import random -from strutils import parseInt +import std/random +from std/strutils import parseInt proc defectiveRobot() = 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 + else: doAssert 2 + 2 == 5 test "unittest expect": expect IOError, OSError, ValueError, AssertionDefect: defectiveRobot() @@ -177,3 +177,16 @@ suite "test name filtering": 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) diff --git a/tests/stdlib/tunittestpass.nim b/tests/stdlib/tunittestpass.nim new file mode 100644 index 0000000000..cff37a3b77 --- /dev/null +++ b/tests/stdlib/tunittestpass.nim @@ -0,0 +1,19 @@ +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/turi.nim b/tests/stdlib/turi.nim index 62fb17e4d4..1a6f375209 100644 --- a/tests/stdlib/turi.nim +++ b/tests/stdlib/turi.nim @@ -1,24 +1,12 @@ discard """ - cmd: "nim c -r --styleCheck:hint --panics:on $options $file" - targets: "c" - nimout: "" - action: "run" - exitcode: 0 - timeout: 60.0 + targets: "c js" """ -include uri +import std/uri +from std/sequtils import toSeq -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: - block: +template main() = + block: # encodeUrl, decodeUrl const test1 = "abc\L+def xyz" doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz" doAssert decodeUrl(encodeUrl(test1)) == test1 @@ -26,178 +14,173 @@ block: doAssert decodeUrl(encodeUrl(test1, false), false) == test1 doAssert decodeUrl(encodeUrl(test1)) == test1 - block: - let str = "http://localhost" - let test = parseUri(str) - doAssert test.path == "" + 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 = "http://localhost/" + let test = parseUri(str) + doAssert test.path == "/" - 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: + 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: - # 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 = "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: - 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: + # 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 = "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 = "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 = "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 = "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 = "/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 = "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/no/slash" - let test = parseUri(str) - doAssert test.path == "test/no/slash" - 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 = "//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 = "test/no/slash" + let test = parseUri(str) + doAssert test.path == "test/no/slash" + doAssert($test == str) - 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: + 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" - # Remove dot segments tests - block: - doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz" + 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" - # 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: # 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"), 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 == "/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 == "/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/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/")) - 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: + 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: # `/` + 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: + 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: + block: # bug #3207 doAssert parseUri("http://qq/1").combine(parseUri("https://qqq")).`$` == "https://qqq" - # bug #4959 - block: + block: # bug #4959 let foo = parseUri("http://example.com") / "/baz" doAssert foo.path == "/baz" - # bug found on stream 13/10/17 - block: + block: # bug found on stream 13/10/17 let foo = parseUri("http://localhost:9515") / "status" doAssert $foo == "http://localhost:9515/status" - # bug #6649 #6652 - block: + block: # bug #6649 #6652 var foo = parseUri("http://example.com") foo.hostname = "example.com" foo.path = "baz" @@ -224,8 +207,7 @@ block: foo.path = "relative" doAssert $foo == "file:relative" - # isAbsolute tests - block: + 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 @@ -265,8 +247,7 @@ block: doAssert "https://example.com/about/staff.html?".parseUri().isAbsolute == true doAssert "https://example.com/about/staff.html?parameters".parseUri().isAbsolute == true - # encodeQuery tests - block: + block: # encodeQuery tests doAssert encodeQuery({:}) == "" doAssert encodeQuery({"foo": "bar"}) == "foo=bar" doAssert encodeQuery({"foo": "bar & baz"}) == "foo=bar+%26+baz" @@ -276,17 +257,17 @@ block: 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: # `?` 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 dataUriBase64: + 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+" @@ -295,6 +276,12 @@ block: 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 - The future, for which I really worked, is mine.""", "text/plain") == + 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=2c=6")) == @[("a", "1"), ("b", "2c=6")] + +static: main() +main() diff --git a/tests/stdlib/tvarargs.nim b/tests/stdlib/tvarargs.nim new file mode 100644 index 0000000000..d56be154bc --- /dev/null +++ b/tests/stdlib/tvarargs.nim @@ -0,0 +1,18 @@ +discard """ + targets: "c js" + matrix: "--gc:refc; --gc:arc" +""" + + +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/twrapnils.nim b/tests/stdlib/twrapnils.nim index c56a65d114..af0978762d 100644 --- a/tests/stdlib/twrapnils.nim +++ b/tests/stdlib/twrapnils.nim @@ -1,15 +1,11 @@ import std/wrapnils -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 type Bar = object b1: int b2: ptr string @@ -31,8 +27,12 @@ proc main() = proc fun(a: Bar): auto = a.b2 var a: Foo - var x6 = create(Bar) - x6.b1 = 42 + + 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 @@ -50,26 +50,23 @@ proc main() = 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 gook.foo, not gook (and assume gook is not nil) doAssert ?.(gook.foo).x2.x2.x1 == 0.0 - doAssert ?.a2.x6[] == Bar(b1: 42) # deref for ptr Bar + when nimvm: discard + else: + 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 - # checks that a chain without nil but with an empty seq still throws IndexDefect - doAssertRaises(IndexDefect): discard ?.a2.x8[3] + when nimvm: discard + else: + # checks that a chain without nil but with an empty seq still raises + doAssertRaises(IndexDefect): discard ?.a2.x8[3] # make sure no double evaluation bug doAssert witness == 0 @@ -79,4 +76,10 @@ proc main() = # 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 + main() +static: main() diff --git a/tests/stdlib/txmltree.nim b/tests/stdlib/txmltree.nim index 034435dd76..d2f7132690 100644 --- a/tests/stdlib/txmltree.nim +++ b/tests/stdlib/txmltree.nim @@ -6,15 +6,15 @@ block: x: XmlNode x = <>a(href = "http://nim-lang.org", newText("Nim rules.")) - assert $x == """Nim rules.""" + doAssert $x == """Nim rules.""" x = <>outer(<>inner()) - assert $x == """ + doAssert $x == """ """ x = <>outer(<>middle(<>inner1(), <>inner2(), <>inner3(), <>inner4())) - assert $x == """ + doAssert $x == """ @@ -24,7 +24,7 @@ block: """ x = <>l0(<>l1(<>l2(<>l3(<>l4())))) - assert $x == """ + doAssert $x == """ @@ -35,14 +35,14 @@ block: """ x = <>l0(<>l1p1(), <>l1p2(), <>l1p3()) - assert $x == """ + doAssert $x == """ """ x = <>l0(<>l1(<>l2p1(), <>l2p2())) - assert $x == """ + doAssert $x == """ @@ -50,7 +50,7 @@ block: """ x = <>l0(<>l1(<>l2_1(), <>l2_2(<>l3_1(), <>l3_2(), <>l3_3(<>l4_1(), <>l4_2(), <>l4_3())), <>l2_3(), <>l2_4())) - assert $x == """ + doAssert $x == """ @@ -72,7 +72,7 @@ block: middle = newXmlTree("middle", [innermost]) innermost.add newText("innermost text") x = newXmlTree("outer", [middle]) - assert $x == """ + doAssert $x == """ innermost text @@ -82,4 +82,4 @@ block: x.add newText("my text") x.add newElement("sonTag") x.add newEntity("my entity") - assert $x == "my text&my entity;" + doAssert $x == "my text&my entity;" diff --git a/tests/strictnotnil/tnilcheck.nim b/tests/strictnotnil/tnilcheck.nim new file mode 100644 index 0000000000..5b9292522c --- /dev/null +++ b/tests/strictnotnil/tnilcheck.nim @@ -0,0 +1,382 @@ +discard """ +cmd: "nim check $file" +action: "reject" +""" + +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.unsafeAddr # {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 new file mode 100644 index 0000000000..5ec9bc575a --- /dev/null +++ b/tests/strictnotnil/tnilcheck_no_warnings.nim @@ -0,0 +1,182 @@ +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/system/tdollars.nim b/tests/system/tdollars.nim index 6ddec911fc..34801d9ee2 100644 --- a/tests/system/tdollars.nim +++ b/tests/system/tdollars.nim @@ -71,9 +71,94 @@ block: # `$`(SomeInteger) testType int64 testType BiggestInt -block: # #14350 for JS +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: + 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: + let x = 4294967295'u32 + doAssert $x == "4294967295" + + block: + doAssert $(4294967295'u32) == "4294967295" + + + block: + proc foo1(arg: int): string = + let x = uint32(arg) + $x + + doAssert $foo1(-1) == "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" + + +static: main() +main() diff --git a/tests/system/tio.nim b/tests/system/tio.nim index c4d0415600..52a21837a0 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) -suite "io": - suite "readAll": - test "stdin": +block: # io + block: # readAll + block: # stdin check: echoLoop(STRING_DATA) == STRING_DATA - test "file": + block: # file check: readFile(TEST_FILE).strip == STRING_DATA diff --git a/tests/system/tostring.nim b/tests/system/tostring.nim index 4ff363075c..fa82acc3bf 100644 --- a/tests/system/tostring.nim +++ b/tests/system/tostring.nim @@ -1,7 +1,3 @@ -discard """ - output: "DONE: tostring.nim" -""" - doAssert "@[23, 45]" == $(@[23, 45]) doAssert "[32, 45]" == $([32, 45]) doAssert """@["", "foo", "bar"]""" == $(@["", "foo", "bar"]) @@ -108,7 +104,7 @@ bar(nilstring) static: stringCompare() -# bug 8847 +# issue #8847 var a2: cstring = "fo\"o2" block: @@ -116,5 +112,14 @@ block: s.addQuoted a2 doAssert s == "\"fo\\\"o2\"" - -echo "DONE: tostring.nim" +# 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() diff --git a/tests/system/tsigexitcode.nim b/tests/system/tsigexitcode.nim new file mode 100644 index 0000000000..6922cb8ebd --- /dev/null +++ b/tests/system/tsigexitcode.nim @@ -0,0 +1,20 @@ +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 fatalSigs = [SIGINT, SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, + SIGPIPE] + for s in fatalSigs: + let (_, exitCode) = execCmdEx(quoteShellCommand [getAppFilename(), $s]) + doAssert exitCode == 128 + s, "mismatched exit code for signal " & $s + +main() diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim index 508715905e..cb879d3b3d 100644 --- a/tests/system/tsystem_misc.nim +++ b/tests/system/tsystem_misc.nim @@ -210,3 +210,10 @@ block: # Ordinal # 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/template/t17433.nim b/tests/template/t17433.nim new file mode 100644 index 0000000000..121f3c4715 --- /dev/null +++ b/tests/template/t17433.nim @@ -0,0 +1,16 @@ +# 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) +assert bar(float) == 0.0 +assert bar(string) == "" + +template main = + proc baz(a: typedesc): a = default(a) + assert baz(float) == 0.0 +main() diff --git a/tests/template/template_issues.nim b/tests/template/template_issues.nim index d12b3c3ef4..502c6d1eeb 100644 --- a/tests/template/template_issues.nim +++ b/tests/template/template_issues.nim @@ -256,7 +256,7 @@ discard foo() type IteratorF*[In] = iterator() : In {.closure.} -template foof(In: untyped) : untyped = +template foof(In: untyped) : untyped = proc ggg*(arg: IteratorF[In]) = for i in arg(): echo "foo" @@ -265,7 +265,7 @@ template foof(In: untyped) : untyped = iterator hello() : int {.closure.} = for i in 1 .. 3: yield i - + foof(int) ggg(hello) @@ -274,3 +274,25 @@ ggg(hello) 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/tmodulealias.nim b/tests/template/tmodulealias.nim index 6681379fbb..79b5ec9c62 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/utemplates.nim b/tests/template/utemplates.nim index 017166250c..7674ba7c02 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" -test "templates can be overloaded": +block: # templates can be overloaded check t(10) == "int" check t("test") == "string" -test "previous definitions can be further overloaded or hidden in local scopes": +block: # previous definitions can be further overloaded or hidden in local scopes template t(a: bool): string = "bool" check t(true) == "bool" @@ -17,7 +17,7 @@ test "previous definitions can be further overloaded or hidden in local scopes": check t(10) == "inner int" check t("test") == "string" -test "templates can be redefined multiple times": +block: # templates can be redefined multiple times template customAssert(cond: bool, msg: string): typed {.dirty.} = if not cond: fail(msg) diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index ea640cac69..2468699a4a 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -3,6 +3,8 @@ {.warning[UnusedImport]: off.} +from stdtest/specialpaths import buildDir + import std/[ # Core: bitops, typetraits, lenientops, macros, volatile, @@ -46,7 +48,7 @@ import std/[ # Parsers: htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, - # fails: parseopt + parseopt, # XML processing: xmltree, xmlparser, @@ -87,3 +89,32 @@ block: 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 new file mode 100644 index 0000000000..8d0dd57e3b --- /dev/null +++ b/tests/testament/t16576.nim @@ -0,0 +1,7 @@ +discard """ + matrix:"-d:nimTest_t16576" +""" + +# bug #16576 +doAssert defined(nimTest_t16576) +doAssert not defined(nimMegatest) diff --git a/tests/testament/tjoinable.nim b/tests/testament/tjoinable.nim new file mode 100644 index 0000000000..7a0ad7985d --- /dev/null +++ b/tests/testament/tjoinable.nim @@ -0,0 +1,8 @@ +discard """ + output: "ok" +""" + +# checks that this is joinable +doAssert defined(testing) +doAssert defined(nimMegatest) +echo "ok" # intentional to make sure this doesn't prevent `isJoinableSpec` diff --git a/tests/testament/tspecialpaths.nim b/tests/testament/tspecialpaths.nim new file mode 100644 index 0000000000..3c97dc88ad --- /dev/null +++ b/tests/testament/tspecialpaths.nim @@ -0,0 +1,9 @@ +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/threads/tjsthreads.nim b/tests/threads/tjsthreads.nim new file mode 100644 index 0000000000..1085d91579 --- /dev/null +++ b/tests/threads/tjsthreads.nim @@ -0,0 +1,6 @@ +discard """ + targets: "c cpp js" + matrix: "--threads" +""" + +echo 123 diff --git a/tests/tuples/ttuples_issues.nim b/tests/tuples/ttuples_issues.nim index f294f2f1ce..0cc505d28e 100644 --- a/tests/tuples/ttuples_issues.nim +++ b/tests/tuples/ttuples_issues.nim @@ -1,84 +1,121 @@ discard """ -output: '''(a: 1) -(a: 1) -(a: 1, b: 2) -''' + targets: "c cpp js" """ +# targets include `cpp` because in the past, there were several cpp-specific bugs with tuples. -import tables +import std/tables +template main() = + block: # bug #4479 + type + MyTuple = tuple + num: int + strings: seq[string] + ints: seq[int] -block t4479: - type - MyTuple = tuple - num: int - strings: seq[string] - ints: seq[int] + var foo = MyTuple(( + num: 7, + strings: @[], + ints: @[], + )) - var foo = MyTuple(( - num: 7, - strings: @[], - ints: @[], - )) + var bar = MyTuple ( + num: 7, + strings: @[], + ints: @[], + ) - var bar = ( - num: 7, - strings: @[], - ints: @[], - ).MyTuple + var fooUnnamed = MyTuple((7, @[], @[])) + var n = 7 + var fooSym = MyTuple((num: n, strings: @[], ints: @[])) - var fooUnnamed = MyTuple((7, @[], @[])) - var n = 7 - var fooSym = MyTuple((num: n, strings: @[], ints: @[])) + block: # bug #1910 + 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: # bug #2121 + type + Item[K,V] = tuple + key: K + value: V -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 + var q = newseq[Item[int,int]](1) + let (x,y) = q[0] + block: # bug #2369 + type HashedElem[T] = tuple[num: int, storedVal: ref T] -block t2121: - type - Item[K,V] = tuple - key: K - value: V + 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 q = newseq[Item[int,int]](1) - let (x,y) = q[0] + var g: seq[HashedElem[int]] = @[] + proc foo() = + var x: ref int + new(x) + x[] = 77 + g.append(44, x) -block t2369: - type HashedElem[T] = tuple[num: int, storedVal: ref T] + block: # bug #1986 + proc test(): int64 = + return 0xdeadbeef.int64 - 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) + const items = [ + (var1: test(), var2: 100'u32), + (var1: test(), var2: 192'u32) + ] - var g: seq[HashedElem[int]] = @[] + block: # bug #14911 + doAssert $(a: 1) == "(a: 1)" # works + doAssert $(`a`: 1) == "(a: 1)" # works + doAssert $(`a`: 1, `b`: 2) == "(a: 1, b: 2)" # was: Error: named expression expected - proc foo() = - var x: ref int - new(x) - x[] = 77 - g.append(44, x) + block: # bug #16822 + var scores: seq[(set[char], int)] = @{{'/'} : 10} + var x1: set[char] + for item in items(scores): + x1 = item[0] -block t1986: - proc test(): int64 = - return 0xdeadbeef.int64 + doAssert x1 == {'/'} - const items = [ - (var1: test(), var2: 100'u32), - (var1: test(), var2: 192'u32) - ] + var x2: set[char] + for (chars, value) in items(scores): + x2 = chars -# bug #14911 -echo (a: 1) # works -echo (`a`: 1) # works -echo (`a`: 1, `b`: 2) # Error: named expression expected + doAssert x2 == {'/'} + + block: # bug #14574 + proc fn(): auto = + let a = @[("foo", (12, 13))] + for (k,v) in a: + return (k,v) + doAssert fn() == ("foo", (12, 13)) + + block: # bug #14574 + iterator fn[T](a:T): lent T = yield a + let a = (10, (11,)) + proc bar(): auto = + for (x,y) in fn(a): + return (x,y) + doAssert bar() == (10, (11,)) + +proc mainProc() = + # other tests should be in `main` + block: + type A = tuple[x: int, y: int] + doAssert (x: 1, y: 2).A == A (x: 1, y: 2) # MCS => can't use a template + +static: + main() + mainProc() + +main() +mainProc() diff --git a/tests/typerel/ttypedesc_as_genericparam1.nim b/tests/typerel/ttypedesc_as_genericparam1.nim index b7c3e727de..3998a6a5fa 100644 --- a/tests/typerel/ttypedesc_as_genericparam1.nim +++ b/tests/typerel/ttypedesc_as_genericparam1.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "type mismatch: got " + errormsg: "type mismatch: got " line: 6 """ # bug #3079, #1146 diff --git a/tests/typerel/ttypenoval.nim b/tests/typerel/ttypenoval.nim index c7829f9dd1..ca6c920ec4 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 9af9784665..4664253ea6 100644 --- a/tests/typerel/ttypenovalue.nim +++ b/tests/typerel/ttypenovalue.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "invalid type: 'type seq[tuple[title: string, body: string]]' for var" + errormsg: "invalid type: 'typedesc[seq[tuple[title: string, body: string]]]' for var" line: 7 """ diff --git a/tests/typerel/typedescs2.nim b/tests/typerel/typedescs2.nim index 0b0b12986b..a0308719d8 100644 --- a/tests/typerel/typedescs2.nim +++ b/tests/typerel/typedescs2.nim @@ -1,10 +1,10 @@ discard """ - errormsg: "invalid type: 'type Table' for const" + errormsg: "invalid type: 'typedesc[Table]' for const" file: "typedescs2.nim" line: 16 """ -# issue #9961 +# bug #9961 import typetraits import tables diff --git a/tests/types/tisop.nim b/tests/types/tisop.nim index ad5928016f..5f9cba0d8c 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: assert(f.y.type.name == "string") +static: doAssert(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: assert false + static: doAssert false var f: TFoo[m(a.type), b.type] static: - assert f.x.type.name == "int" + doAssert f.x.type.name == "int" echo f.y.type.name - assert f.y.type.name == "float" + doAssert f.y.type.name == "float" echo f.z.type.name - assert f.z.type.name == "float" + doAssert f.z.type.name == "float" p(A, f) diff --git a/tests/untestable/gdb/gdb_pretty_printer_test.py b/tests/untestable/gdb/gdb_pretty_printer_test.py index f002941ec8..5b34bcb3d2 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test.py +++ b/tests/untestable/gdb/gdb_pretty_printer_test.py @@ -6,31 +6,47 @@ import gdb # frontends might still be broken. gdb.execute("source ../../../tools/nim-gdb.py") -# debug all instances of the generic function `myDebug`, should be 8 +# debug all instances of the generic function `myDebug`, should be 14 gdb.execute("rbreak myDebug") gdb.execute("run") outputs = [ 'meTwo', + '""', '"meTwo"', '{meOne, meThree}', 'MyOtherEnum(1)', '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) = {["two"] = 2, ["three"] = 3, ["one"] = 1}', + 'Table(3, 64) = {[4] = "four", [5] = "five", [6] = "six"}', + 'Table(3, 8) = {["two"] = 2, ["three"] = 3, ["one"] = 1}', ] for i, expected in enumerate(outputs): + gdb.write(f"{i+1}) expecting: {expected}: ", gdb.STDLOG) + gdb.flush() + functionSymbol = gdb.selected_frame().block().function assert functionSymbol.line == 21 - if i == 5: + if i == 6: # myArray is passed as pointer to int to myDebug. I look up myArray up in the stack gdb.execute("up") - output = str(gdb.parse_and_eval("myArray")) + 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") else: - output = str(gdb.parse_and_eval("arg")) + raw = gdb.parse_and_eval("arg") + + output = str(raw) assert output == expected, output + " != " + expected + gdb.write(f"passed\n", gdb.STDLOG) gdb.execute("continue") diff --git a/tests/untestable/gdb/gdb_pretty_printer_test_program.nim b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim index 458435c1ac..c376ef89ad 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test_program.nim +++ b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim @@ -23,29 +23,56 @@ proc myDebug[T](arg: T): void = proc testProc(): void = var myEnum = meTwo - myDebug(myEnum) + myDebug(myEnum) #1 + + # create a string, but don't allocate it + var myString: string + myDebug(myString) #2 + # create a string object but also make the NTI for MyEnum is generated - var myString = $myEnum - myDebug(myString) + myString = $myEnum + myDebug(myString) #3 + var mySet = {meOne,meThree} - myDebug(mySet) + myDebug(mySet) #4 # for MyOtherEnum there is no NTI. This tests the fallback for the pretty printer. var moEnum = moTwo - myDebug(moEnum) + myDebug(moEnum) #5 + var moSet = {moOne,moThree} - myDebug(moSet) + myDebug(moSet) #6 let myArray = [1,2,3,4,5] - myDebug(myArray) - let mySeq = @["one","two","three"] - myDebug(mySeq) + myDebug(myArray) #7 - var myTable = initTable[string, int]() - myTable["one"] = 1 - myTable["two"] = 2 - myTable["three"] = 3 - myDebug(myTable) + # implicitly initialized seq test + var mySeq: seq[string] + myDebug(mySeq) #8 + + # 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 echo(counter) diff --git a/tests/untestable/thttpclient_ssl.nim b/tests/untestable/thttpclient_ssl.nim deleted file mode 100644 index 038eba99d1..0000000000 --- a/tests/untestable/thttpclient_ssl.nim +++ /dev/null @@ -1,207 +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. -## Test with: -## ./bin/nim c -d:ssl -p:. --threads:on -r tests/untestable/thttpclient_ssl.nim -## -## See https://github.com/FedericoCeratto/ssl-comparison/blob/master/README.md -## for a comparison with other clients. - -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..55, 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/", dubious_broken, "no-common-name"), - ("https://no-subject.badssl.com/", dubious_broken, "no-subject"), - ("https://incomplete-chain.badssl.com/", dubious_broken, "incomplete-chain"), - ("https://sha1-intermediate.badssl.com/", bad, "sha1-intermediate"), - ("https://sha256.badssl.com/", good, "sha256"), - ("https://sha384.badssl.com/", good, "sha384"), - ("https://sha512.badssl.com/", good, "sha512"), - ("https://1000-sans.badssl.com/", good, "1000-sans"), - ("https://10000-sans.badssl.com/", good_broken, "10000-sans"), - ("https://ecc256.badssl.com/", good, "ecc256"), - ("https://ecc384.badssl.com/", good, "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. Testes 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 - if raised: - echo " $# ($#) raised: $#" % [desc, $category, exception_msg] - else: - echo " $# ($#) did not raise" % [desc, $category] - if category in {good, dubious, bad}: - fail() - - -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": - - # 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) - - -# 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/thttpclient_ssl_disabled.nim b/tests/untestable/thttpclient_ssl_disabled.nim index 0f7e958317..b95dad2c64 100644 --- a/tests/untestable/thttpclient_ssl_disabled.nim +++ b/tests/untestable/thttpclient_ssl_disabled.nim @@ -5,36 +5,32 @@ # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## Warning: this test performs external networking. ## Compile and run with: -## ./bin/nim c -d:nimDisableCertificateValidation -d:ssl -r -p:. tests/untestable/thttpclient_ssl_disabled.nim +## nim r --putenv:NIM_TESTAMENT_REMOTE_NETWORKING:1 -d:nimDisableCertificateValidation -d:ssl -p:. tests/untestable/thttpclient_ssl_disabled.nim -import httpclient, - net, - unittest, - os +from stdtest/testutils import enableRemoteNetworking +when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(openbsd)): + import httpclient, net, unittest -from strutils import contains + const expired = "https://expired.badssl.com/" -const expired = "https://expired.badssl.com/" + doAssert defined(nimDisableCertificateValidation) -doAssert defined(nimDisableCertificateValidation) + suite "SSL certificate check - disabled": -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 = 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 "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 + 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_remotenetwork.nim b/tests/untestable/thttpclient_ssl_remotenetwork.nim new file mode 100644 index 0000000000..eea65bf0b6 --- /dev/null +++ b/tests/untestable/thttpclient_ssl_remotenetwork.nim @@ -0,0 +1,208 @@ +# +# +# 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..55, 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/", dubious_broken, "no-common-name"), + ("https://no-subject.badssl.com/", dubious_broken, "no-subject"), + ("https://incomplete-chain.badssl.com/", dubious_broken, "incomplete-chain"), + ("https://sha1-intermediate.badssl.com/", bad, "sha1-intermediate"), + ("https://sha256.badssl.com/", good, "sha256"), + ("https://sha384.badssl.com/", good, "sha384"), + ("https://sha512.badssl.com/", good, "sha512"), + ("https://1000-sans.badssl.com/", good, "1000-sans"), + ("https://10000-sans.badssl.com/", good_broken, "10000-sans"), + ("https://ecc256.badssl.com/", good, "ecc256"), + ("https://ecc384.badssl.com/", good, "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 + if raised: + echo " $# ($#) raised: $#" % [desc, $category, exception_msg] + else: + echo " $# ($#) did not raise" % [desc, $category] + if category in {good, dubious, bad}: + fail() + + + 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/valgrind/tleak_arc.nim b/tests/valgrind/tleak_arc.nim index 8dea7c62aa..c47ee137ad 100644 --- a/tests/valgrind/tleak_arc.nim +++ b/tests/valgrind/tleak_arc.nim @@ -4,7 +4,7 @@ cmd: "nim $target --gc:arc -d:useMalloc $options $file" exitcode: 1 outputsub: " definitely lost: 7 bytes in 2 blocks" disabled: "freebsd" -disabled: "macosx" +disabled: "osx" disabled: "openbsd" disabled: "windows" disabled: "32bit" diff --git a/tests/vm/t17039.nim b/tests/vm/t17039.nim new file mode 100644 index 0000000000..f92c93f30a --- /dev/null +++ b/tests/vm/t17039.nim @@ -0,0 +1,10 @@ +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/tableinstatic.nim b/tests/vm/tableinstatic.nim index 4080a52865..934c3a8dda 100644 --- a/tests/vm/tableinstatic.nim +++ b/tests/vm/tableinstatic.nim @@ -35,4 +35,4 @@ static: otherTable["hallo"] = "123" otherTable["welt"] = "456" - assert otherTable == {"hallo": "123", "welt": "456"}.newTable + doAssert otherTable == {"hallo": "123", "welt": "456"}.newTable diff --git a/tests/vm/tcastint.nim b/tests/vm/tcastint.nim index acff0d2b14..a97c81ed27 100644 --- a/tests/vm/tcastint.nim +++ b/tests/vm/tcastint.nim @@ -1,7 +1,3 @@ -discard """ - output: "OK" -""" - import macros type @@ -292,16 +288,12 @@ proc test_float32_castB() = # any surprising content. doAssert cast[uint64](c) == 3270918144'u64 -test() -test_float_cast() -test_float32_cast() -free_integer_casting() -test_float32_castB() -static: +template main() = test() test_float_cast() test_float32_cast() free_integer_casting() test_float32_castB() -echo "OK" +static: main() +main() diff --git a/tests/vm/tcompilesetting.nim b/tests/vm/tcompilesetting.nim index 98565ab94f..5bf559c745 100644 --- a/tests/vm/tcompilesetting.nim +++ b/tests/vm/tcompilesetting.nim @@ -3,18 +3,15 @@ cmd: "nim c --nimcache:build/myNimCache --nimblePath:myNimblePath $file" joinable: false """ -import strutils +import std/[strutils,compilesettings] +from std/os import fileExists, `/` -import std / compilesettings +template main = + doAssert querySetting(nimcacheDir) == nimcacheDir.querySetting + doAssert "myNimCache" in nimcacheDir.querySetting + doAssert "myNimblePath" in nimblePaths.querySettingSeq[0] + doAssert querySetting(backend) == "c" + doAssert fileExists(libPath.querySetting / "system.nim") -const - nc = querySetting(nimcacheDir) - np = querySettingSeq(nimblePaths) - -static: - echo nc - echo np - -doAssert "myNimCache" in nc -doAssert "myNimblePath" in np[0] -doAssert querySetting(backend) == "c" +static: main() +main() diff --git a/tests/vm/tissues.nim b/tests/vm/tissues.nim index 063559d2e5..1cf3afc002 100644 --- a/tests/vm/tissues.nim +++ b/tests/vm/tissues.nim @@ -25,4 +25,4 @@ block t4952: static: let tree = newTree(nnkExprColonExpr) let t = (n: tree) - assert: t.n.kind == tree.kind + doAssert: t.n.kind == tree.kind diff --git a/tests/vm/toverflowopcaddimmint.nim b/tests/vm/toverflowopcaddimmint.nim index c36b9ed9b3..4ff614e5bd 100644 --- a/tests/vm/toverflowopcaddimmint.nim +++ b/tests/vm/toverflowopcaddimmint.nim @@ -7,5 +7,5 @@ static: var x = int64.high discard x + 1 - assert false + doAssert false p() diff --git a/tests/vm/toverflowopcaddint.nim b/tests/vm/toverflowopcaddint.nim index 6d96afc78b..d494245b19 100644 --- a/tests/vm/toverflowopcaddint.nim +++ b/tests/vm/toverflowopcaddint.nim @@ -8,5 +8,5 @@ static: x = int64.high y = 1 discard x + y - assert false + doAssert false p() diff --git a/tests/vm/toverflowopcmulint.nim b/tests/vm/toverflowopcmulint.nim index 5607c59a7e..936eea6c25 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 - assert false + doAssert false p() diff --git a/tests/vm/toverflowopcsubimmint.nim b/tests/vm/toverflowopcsubimmint.nim index 09d6f745bc..08356590cf 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 - assert false + doAssert false p() diff --git a/tests/vm/toverflowopcsubint.nim b/tests/vm/toverflowopcsubint.nim index 8d114f200e..74e34c6a42 100644 --- a/tests/vm/toverflowopcsubint.nim +++ b/tests/vm/toverflowopcsubint.nim @@ -8,5 +8,5 @@ static: x = int64.low y = 1 discard x - y - assert false + doAssert false p() diff --git a/tests/vm/tstring_openarray.nim b/tests/vm/tstring_openarray.nim index 1b8a1304c9..9318344f85 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..` should work on windows, if not, we can use `execCmdEx` + let cmd = "pdflatex -interaction=nonstopmode -output-directory=$# $# > $#" % [outDir.quoteShell, texFile.quoteShell, pdflatexLog.quoteShell] + exec(cmd) # on error, user can inspect `pdflatexLog` + moveFile(texFile.changeFileExt("pdf"), dst) + proc buildPdfDoc*(nimArgs, destPath: string) = + var pdfList: seq[string] createDir(destPath) if os.execShellCmd("pdflatex -version") != 0: - echo "pdflatex not found; no PDF documentation generated" + doAssert false, "pdflatex not found" # or, raise an exception else: - const pdflatexcmd = "pdflatex -interaction=nonstopmode " - for d in items(pdf): - exec(findNim().quoteShell() & " rst2tex $# $#" % [nimArgs, d]) - let tex = splitFile(d).name & ".tex" - removeFile("doc" / tex) - moveFile(tex, "doc" / tex) - # 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 fileExists(changeFileExt(pdf, "toc")): - removeFile(changeFileExt(pdf, "toc")) - removeFile(changeFileExt(pdf, "log")) - removeFile(changeFileExt(pdf, "out")) - removeFile(changeFileExt(d, "tex")) + for src in items(rstPdfList): + 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 proc buildJS(): string = let nim = findNim() - exec(nim.quoteShell() & " js -d:release --out:$1 tools/nimblepkglist.nim" % - [webUploadOutput / "nimblepkglist.js"]) + 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) diff --git a/tools/nim-gdb.py b/tools/nim-gdb.py index e994531b62..8143b94d5e 100644 --- a/tools/nim-gdb.py +++ b/tools/nim-gdb.py @@ -34,6 +34,14 @@ def getNimRti(type_name): except: return None +def getNameFromNimRti(rti_val): + """ 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 + class NimTypeRecognizer: # this type map maps from types that are generated in the C files to # how they are called in nim. To not mix up the name ``int`` from @@ -42,30 +50,25 @@ 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' + + 'NIM_BOOL': 'bool', + + 'NIM_CHAR': 'char', 'NCSTRING': 'cstring', 'NimStringDesc': 'string' } - # 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$") + # 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: @@ -75,44 +78,43 @@ class NimTypeRecognizer: # handle pointer types if not tname: - if type_obj.code == gdb.TYPE_CODE_PTR: + target_type = type_obj + if type_obj.code in [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 not tname: - # We are not resposible for this type printing. - # Basically this means we don't print pointer types. - return None + 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) - result = self.type_map_static.get(tname, None) - if result: - return result + if tname: + result = self.type_map_static.get(tname, None) + if result: + return result - rti = getNimRti(tname) - if rti: - return rti['name'].string("utf-8", "ignore") - else: - return None + rti = getNimRti(tname) + if rti: + return getNameFromNimRti(rti) + + 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): @@ -309,9 +311,25 @@ class NimStringPrinter: def to_string(self): if self.val: l = int(self.val['Sup']['len']) - return self.val['data'][0].address.string("utf-8", "ignore", l) + return self.val['data'].lazy_string(encoding="utf-8", length=l) else: - return "" + return "" + +# class NimStringPrinter: +# pattern = re.compile(r'^NimStringDesc$') + +# def __init__(self, val): +# self.val = val + +# def display_hint(self): +# return 'string' + +# def to_string(self): +# if self.val: +# l = int(self.val['Sup']['len']) +# return self.val['data'].lazy_string(encoding="utf-8", length=l) +# else: +# return "" class NimRopePrinter: pattern = re.compile(r'^tyObject_RopeObj__([A-Za-z0-9]*) \*$') @@ -372,14 +390,15 @@ class NimEnumPrinter: pattern = re.compile(r'^tyEnum_(\w*)__([A-Za-z0-9]*)$') def __init__(self, val): - self.val = val - match = self.pattern.match(self.val.type.name) + self.val = val + typeName = self.val.type.name + match = self.pattern.match(typeName) self.typeNimName = match.group(1) 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") + printErrorOnce(typeInfoName, f"NimEnumPrinter: lookup global symbol '{typeInfoName}' failed for {typeName}.\n") def to_string(self): if self.nti: @@ -476,11 +495,31 @@ class NimSeqPrinter: def children(self): if self.val: - length = int(self.val['Sup']['len']) - #align = len(str(length - 1)) - for i in range(length): - yield ("data[{0}]".format(i), self.val["data"][i]) + val = self.val + valType = val.type + length = int(val['Sup']['len']) + if length <= 0: + return + + dataType = valType['data'].type + data = val['data'] + + if self.val.type.name is None: + dataType = valType['data'].type.target().pointer() + data = val['data'].cast(dataType) + + inaccessible = False + 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" + ################################################################################ class NimArrayPrinter: @@ -524,9 +563,9 @@ class NimStringTablePrinter: def children(self): if self.val: - data = NimSeqPrinter(self.val['data']) + data = NimSeqPrinter(self.val['data'].dereference()) for idxStr, entry in data.children(): - if int(entry['Field2']) > 0: + if int(entry['Field0']) != 0: yield (idxStr + ".Field0", entry['Field0']) yield (idxStr + ".Field1", entry['Field1']) @@ -537,7 +576,6 @@ class NimTablePrinter: def __init__(self, val): self.val = val - # match = self.pattern.match(self.val.type.name) def display_hint(self): return 'map' @@ -556,11 +594,10 @@ 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']) - ################################################################ # this is untested, therefore disabled @@ -651,7 +688,7 @@ def register_nim_pretty_printers_for_object(objfile): if nimMainSym and nimMainSym.symtab.objfile == objfile: print("set Nim pretty printers for ", objfile.filename) - objfile.type_printers = [NimTypePrinter()] + gdb.types.register_type_printer(objfile, 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/niminst/niminst.nim b/tools/niminst/niminst.nim index 47137f8f35..d81b98be9f 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -477,8 +477,6 @@ 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) diff --git a/tools/vccexe/vccexe.nim b/tools/vccexe/vccexe.nim index 1b5b2fb820..abe68c0a04 100644 --- a/tools/vccexe/vccexe.nim +++ b/tools/vccexe/vccexe.nim @@ -93,7 +93,7 @@ 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. @@ -104,12 +104,12 @@ Microsoft (R) C/C++ Optimizing Compiler if no secondary command was specified """ -proc parseVccexeCmdLine(argseq: seq[TaintedString], +proc parseVccexeCmdLine(argseq: seq[string], 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, verboseArg: var bool, - clArgs: var seq[TaintedString]) = + clArgs: var seq[string]) = ## Cannot use usual command-line argument parser here ## Since vccexe command-line arguments are intermingled ## with the secondary command-line arguments which have @@ -160,7 +160,7 @@ when isMainModule: var sdkVersionArg: string var verboseArg: bool = false - var clArgs: seq[TaintedString] = @[] + var clArgs: seq[string] = @[] let wrapperArgs = commandLineParams() parseVccexeCmdLine(wrapperArgs, vccversionArg, printPathArg, vcvarsallArg,