Compare commits

..

2 Commits

Author SHA1 Message Date
ringabout
aacf94d72c tiny 2022-12-15 17:07:11 +08:00
ringabout
c1b90783eb fixes setInheritable 2022-12-15 17:01:27 +08:00
397 changed files with 4665 additions and 10502 deletions

1
.gitignore vendored
View File

@@ -67,7 +67,6 @@ testament.db
/csources
/csources_v1
/csources_v2
/dist/
# /lib/fusion # fusion is now unbundled; `git status` should reveal if it's there so users can act on it

View File

@@ -14,7 +14,7 @@ else
fi
# Find out where the pretty printer Python module is
GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/debug/nim-gdb.py"
GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/nim-gdb.py"
# Run GDB with the additional arguments that load the pretty printers
# Set the environment variable `NIM_GDB` to overwrite the call to a

View File

@@ -3,7 +3,7 @@ for %%i in (nim.exe) do (set NIM_BIN=%%~dp$PATH:i)
for %%i in ("%NIM_BIN%\..\") do (set NIM_ROOT=%%~fi)
set @GDB_PYTHON_MODULE_PATH=%NIM_ROOT%\tools\debug\nim-gdb.py
set @GDB_PYTHON_MODULE_PATH=%NIM_ROOT%\tools\nim-gdb.py
set @NIM_GDB=gdb.exe
@echo source %@GDB_PYTHON_MODULE_PATH%> wingdbcommand.txt

View File

@@ -1,31 +1,319 @@
# v2.2.0 - yyyy-mm-dd
# v2.0.0 - yyyy-mm-dd
## Changes affecting backward compatibility
- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response, it followed Apache HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behavior. Previously it raised `ValueError`.
- `addr` is now available for all addressable locations,
`unsafeAddr` is now deprecated and an alias for `addr`.
- Certain definitions from the default `system` module have been moved to
the following new modules:
- `std/syncio`
- `std/assertions`
- `std/formatfloat`
- `std/objectdollar`
- `std/widestrs`
- `std/typedthreads`
- `std/sysatomics`
In the future, these definitions will be removed from the `system` module,
and their respective modules will have to be imported to use them.
Currently, to make these imports required, the `-d:nimPreviewSlimSystem` option
may be used.
- Enabling `-d:nimPreviewSlimSystem` also removes the following deprecated
symbols in the `system` module:
- Aliases with `Error` suffix to exception types that have a `Defect` suffix
(see [exceptions](https://nim-lang.org/docs/exceptions.html)):
`ArithmeticError`, `DivByZeroError`, `OverflowError`,
`AccessViolationError`, `AssertionError`, `OutOfMemError`, `IndexError`,
`FieldError`, `RangeError`, `StackOverflowError`, `ReraiseError`,
`ObjectAssignmentError`, `ObjectConversionError`, `FloatingPointError`,
`FloatOverflowError`, `FloatUnderflowError`, `FloatInexactError`,
`DeadThreadError`, `NilAccessError`
- `addQuitProc`, replaced by `exitprocs.addExitProc`
- Legacy unsigned conversion operations: `ze`, `ze64`, `toU8`, `toU16`, `toU32`
- `TaintedString`, formerly a distinct alias to `string`
- `PInt32`, `PInt64`, `PFloat32`, `PFloat64`, aliases to
`ptr int32`, `ptr int64`, `ptr float32`, `ptr float64`
- Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in
in the `system` module.
- Enabling `-d:nimPreviewCstringConversion`, `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` don't support conversion to cstring anymore.
- The `gc:v2` option is removed.
- The `mainmodule` and `m` options are removed.
- The `threads:on` option is now the default.
- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via
`experimental:flexibleOptionalParams`.
- Automatic dereferencing (experimental feature) is removed.
- The `Math.trunc` polyfill for targeting Internet Explorer was
previously included in most JavaScript output files.
Now, it is only included with `-d:nimJsMathTruncPolyfill`.
If you are targeting Internet Explorer, you may choose to enable this option
or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma).
Nim uses `Math.trunc` for the division and modulo operators for integers.
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
`sink` for optimization purposes.
- The `nimPreviewDotLikeOps` define is going to be removed or deprecated.
- The `{.this.}` pragma, deprecated since 0.19, has been removed.
- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead.
```nim
type Foo = distinct ptr int
# Before:
var x: Foo = nil
# After:
var x: Foo = Foo(nil)
```
- Removed two type pragma syntaxes deprecated since 0.20, namely
`type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`.
- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent
with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`.
This decision was made with the assumption that the old syntax was used rarely;
if your code used the old syntax, please be aware of this change.
- [Overloadable enums](https://nim-lang.github.io/Nim/manual.html#overloadable-enum-value-names) and Unicode Operators
are no longer experimental.
- Removed the `nimIncrSeqV3` define.
- `macros.getImpl` for `const` symbols now returns the full definition node
(as `nnkConstDef`) rather than the AST of the constant value.
- Lock levels are deprecated, now a noop.
- ORC is now the default memory management strategy. Use
`--mm:refc` for a transition period.
- `strictEffects` are no longer experimental.
Use `legacy:laxEffects` to keep backward compatibility.
- The `gorge`/`staticExec` calls will now return a descriptive message in the output
if the execution fails for whatever reason. To get back legacy behaviour use `-d:nimLegacyGorgeErrors`.
- Pointer to `cstring` conversion now triggers a `[PtrToCstringConv]` warning.
This warning will become an error in future versions! Use a `cast` operation
like `cast[cstring](x)` instead.
- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`.
- Object fields now support default values, see https://nim-lang.github.io/Nim/manual.html#types-default-values-for-object-fields for details.
- Redefining templates with the same signature was previously
allowed to support certain macro code. To do this explicitly, the
`{.redefine.}` pragma has been added. Note that this is only for templates.
Implicit redefinition of templates is now deprecated and will give an error in the future.
- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead.
- Several Standard libraries are moved to nimble packages, use `nimble` to install them:
- `std/punycode` => `punycode`
- `std/asyncftpclient` => `asyncftpclient`
- `std/smtp` => `smtp`
- `std/db_common` => `db_connector/db_common`
- `std/db_sqlite` => `db_connector/db_sqlite`
- `std/db_mysql` => `db_connector/db_mysql`
- `std/db_postgres` => `db_connector/db_postgres`
- `std/db_odbc` => `db_connector/db_odbc`
- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of
`foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`.
This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead.
## Standard library additions and changes
[//]: # "Changes:"
- OpenSSL 3 is now supported.
- `macros.parseExpr` and `macros.parseStmt` now accept an optional
filename argument for more informative errors.
- Module `colors` expanded with missing colors from the CSS color standard.
`colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard.
- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)).
- The `md5` module now works at compile time and in JavaScript.
- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef` to support `const` tables.
- `strutils.find` now uses and defaults to `last = -1` for whole string searches,
making limiting it to just the first char (`last = 0`) valid.
- `random.rand` now works with `Ordinal`s.
- Undeprecated `os.isvalidfilename`.
- `std/oids` now uses `int64` to store time internally (before it was int32).
- `std/uri.Uri` dollar `$` improved, precalculates the `string` result length from the `Uri`.
- `std/uri.Uri.isIpv6` is now exported.
- `std/logging.ConsoleLogger` and `FileLogger` now have a `flushThreshold` attribute to set what log message levels are automatically flushed. For Nim v1 use `-d:nimFlushAllLogs` to automatically flush all message levels. Flushing all logs is the default behavior for Nim v2.
- `std/net.IpAddress` dollar `$` improved, uses a fixed capacity for the `string` result based from the `IpAddressFamily`.
- `std/jsfetch.newFetchOptions` now has default values for all parameters
- `std/jsformdata` now accepts `Blob` data type.
[//]: # "Additions:"
- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes.
- Added ISO 8601 week date utilities in `times`:
- Added `IsoWeekRange`, a range type for weeks in a week-based year.
- Added `IsoYear`, a distinct type for a week-based year in contrast to a regular year.
- Added a `initDateTime` overload to create a datetime from an ISO week date.
- Added `getIsoWeekAndYear` to get an ISO week number and week-based year from a datetime.
- Added `getIsoWeeksInYear` to return the number of weeks in a week-based year.
- Added new modules which were part of `std/os`:
- Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling.
- Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`.
- Added `std/cmdline` for reading command line parameters.
- Added `sep` parameter in `std/uri` to specify the query separator.
- Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift)
and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask)
in `jscore` for JavaScript targets.
- Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`.
- Added `complex.sgn` for obtaining the phase of complex numbers.
- Added `insertAdjacentText`, `insertAdjacentElement`, `insertAdjacentHTML`,
`after`, `before`, `closest`, `append`, `hasAttributeNS`, `removeAttributeNS`,
`hasPointerCapture`, `releasePointerCapture`, `requestPointerLock`,
`replaceChildren`, `replaceWith`, `scrollIntoViewIfNeeded`, `setHTML`,
`toggleAttribute`, and `matches` to `std/dom`.
- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices)
- Added `capacity` for `string` and `seq` to return the current capacity, see https://github.com/nim-lang/RFCs/issues/460
- Added `openArray[char]` overloads for `std/parseutils` allowing more code reuse.
- Added `openArray[char]` overloads for `std/unicode` allowing more code reuse.
- Added `safe` parameter to `base64.encodeMime`.
[//]: # "Deprecations:"
- Deprecated `selfExe` for Nimscript.
- Deprecated `std/sums`.
- Deprecated `std/base64.encode` for collections of arbitrary integer element type.
Now only `byte` and `char` are supported.
[//]: # "Removals:"
- Removed deprecated module `parseopt2`.
- Removed deprecated module `sharedstrings`.
- Removed deprecated module `dom_extensions`.
- Removed deprecated module `LockFreeHash`.
- Removed deprecated module `events`.
- Removed deprecated `oids.oidToString`.
- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`.
- Removed deprecated `jsre.test` and `jsre.toString`.
- Removed deprecated `math.c_frexp`.
- Removed deprecated `` httpcore.`==` ``.
- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types.
- Removed deprecated `osproc.poDemon`, symbol with typo.
- Removed deprecated `tables.rightSize`.
- Removed deprecated `posix.CLONE_STOPPED`.
## Language changes
- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) supports the definition of forbidden tags by the `.forbids` pragma
which can be used to disable certain effects in proc types.
- [Case statement macros](https://nim-lang.github.io/Nim/manual.html#macros-case-statement-macros) are no longer experimental,
meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them.
- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed
for the right-hand side of type definitions in type sections. Previously
they would error with "invalid indentation".
- Compile-time define changes:
- `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`.
In the command line, this is defined as `-d:a.b.c`. Older versions can
use accents as in ``defined(`a.b.c`)`` to access such defines.
- [Define pragmas for constants](https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-compileminustime-define-pragmas)
now support a string argument for qualified define names.
```nim
# -d:package.FooBar=42
const FooBar {.intdefine: "package.FooBar".}: int = 5
echo FooBar # 42
```
This was added to help disambiguate similar define names for different packages.
In older versions, this could only be achieved with something like the following:
```nim
const FooBar = block:
const `package.FooBar` {.intdefine.}: int = 5
`package.FooBar`
```
- A generic `define` pragma for constants has been added that interprets
the value of the define based on the type of the constant value.
See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-define-pragma)
for a list of supported types.
- [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes:
- Templates now accept macro pragmas.
- Macro pragmas for var/let/const sections have been redesigned in a way that works
similarly to routine macro pragmas. The new behavior is documented in the
[experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#extended-macro-pragmas).
- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`,
allowing multiple type definitions to be injected in place of the original type definition.
```nim
import macros
macro multiply(amount: static int, s: untyped): untyped =
let name = $s[0].basename
result = newNimNode(nnkTypeSection)
for i in 1 .. amount:
result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2]))
type
Foo = object
Bar {.multiply: 3.} = object
x, y, z: int
Baz = object
# becomes
type
Foo = object
Bar1 = object
x, y, z: int
Bar2 = object
x, y, z: int
Bar3 = object
x, y, z: int
Baz = object
```
- A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference)
has been implemented for a variety of basic cases. For example, code like the following now compiles:
```nim
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
```
- `cstring` is now accepted as a selector in `case` statements, removing the
need to convert to `string`. On the JS backend, this is translated directly
to a `switch` statement.
- Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters).
- Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`.
## Compiler changes
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
reality better. (Nim moved away from all techniques based on "tracing".)
- Defines the `gcRefc` symbol which allows writing specific code for the refc GC.
- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`,
without requiring `-d:nimVersion140` which is now a noop.
- `--styleCheck`, `--hintAsError` and `--warningAsError` now only apply to the current package.
- The switch `--nimMainPrefix:prefix` has been added to add a prefix to the names of `NimMain` and
related functions produced on the backend. This prevents conflicts with other Nim
static libraries.
- When compiling for Release the flag `-fno-math-errno` is used for GCC.
## Tool changes
- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`).

33
changelogs/changelog.md Normal file
View File

@@ -0,0 +1,33 @@
# v1.xx.x - yyyy-mm-dd
## Changes affecting backward compatibility
## Standard library additions and changes
- `std/sharedlist` and `std/sharedtables` are now deprecated, see RFC [#433](https://github.com/nim-lang/RFCs/issues/433).
### New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall
This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17.
On linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall.
When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be:
```sh
$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details
$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8
$ sh build.sh # per unix install instructions
$ bin/nim c koch # per unix install instructions
$ ./koch boot -d:release # per unix install instructions
$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall
```
This is necessary to pass when building nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for stdlib (sysrand in particular).
## Language changes
## Compiler changes
## Tool changes

View File

@@ -1,367 +0,0 @@
# v2.0.0 - yyyy-mm-dd
## Changes affecting backward compatibility
- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response. It follows Apache HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behavior. Previously it raised `ValueError`.
- `addr` is now available for all addressable locations,
`unsafeAddr` is now deprecated and an alias for `addr`.
- Certain definitions from the default `system` module have been moved to
the following new modules:
- `std/syncio`
- `std/assertions`
- `std/formatfloat`
- `std/objectdollar`
- `std/widestrs`
- `std/typedthreads`
- `std/sysatomics`
In the future, these definitions will be removed from the `system` module,
and their respective modules will have to be imported to use them.
Currently, to make these imports required, the `-d:nimPreviewSlimSystem` option
may be used.
- Enabling `-d:nimPreviewSlimSystem` also removes the following deprecated
symbols in the `system` module:
- Aliases with `Error` suffix to exception types that have a `Defect` suffix
(see [exceptions](https://nim-lang.github.io/Nim/exceptions.html)):
`ArithmeticError`, `DivByZeroError`, `OverflowError`,
`AccessViolationError`, `AssertionError`, `OutOfMemError`, `IndexError`,
`FieldError`, `RangeError`, `StackOverflowError`, `ReraiseError`,
`ObjectAssignmentError`, `ObjectConversionError`, `FloatingPointError`,
`FloatOverflowError`, `FloatUnderflowError`, `FloatInexactError`,
`DeadThreadError`, `NilAccessError`
- `addQuitProc`, replaced by `exitprocs.addExitProc`
- Legacy unsigned conversion operations: `ze`, `ze64`, `toU8`, `toU16`, `toU32`
- `TaintedString`, formerly a distinct alias to `string`
- `PInt32`, `PInt64`, `PFloat32`, `PFloat64`, aliases to
`ptr int32`, `ptr int64`, `ptr float32`, `ptr float64`
- Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in
in the `system` module.
- Enabling `-d:nimPreviewCstringConversion`, `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` don't support conversion to cstring anymore.
- The `gc:v2` option is removed.
- The `mainmodule` and `m` options are removed.
- The `threads:on` option is now the default.
- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via
`experimental:flexibleOptionalParams`.
- Automatic dereferencing (experimental feature) is removed.
- The `Math.trunc` polyfill for targeting Internet Explorer was
previously included in most JavaScript output files.
Now, it is only included with `-d:nimJsMathTruncPolyfill`.
If you are targeting Internet Explorer, you may choose to enable this option
or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma).
Nim uses `Math.trunc` for the division and modulo operators for integers.
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
`sink` for optimization purposes.
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fullfill its promises.
- The `{.this.}` pragma, deprecated since 0.19, has been removed.
- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead.
```nim
type Foo = distinct ptr int
# Before:
var x: Foo = nil
# After:
var x: Foo = Foo(nil)
```
- Removed two type pragma syntaxes deprecated since 0.20, namely
`type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`.
- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent
with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`.
This decision was made with the assumption that the old syntax was used rarely;
if your code used the old syntax, please be aware of this change.
- [Overloadable enums](https://nim-lang.github.io/Nim/manual.html#overloadable-enum-value-names) and Unicode Operators
are no longer experimental.
- Removed the `nimIncrSeqV3` define.
- `macros.getImpl` for `const` symbols now returns the full definition node
(as `nnkConstDef`) rather than the AST of the constant value.
- Lock levels are deprecated, now a noop.
- ORC is now the default memory management strategy. Use
`--mm:refc` for a transition period.
- `strictEffects` are no longer experimental.
Use `legacy:laxEffects` to keep backward compatibility.
- The `gorge`/`staticExec` calls will now return a descriptive message in the output
if the execution fails for whatever reason. To get back legacy behaviour use `-d:nimLegacyGorgeErrors`.
- Pointer to `cstring` conversion now triggers a `[PtrToCstringConv]` warning.
This warning will become an error in future versions! Use a `cast` operation
like `cast[cstring](x)` instead.
- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`.
- Redefining templates with the same signature was previously
allowed to support certain macro code. To do this explicitly, the
`{.redefine.}` pragma has been added. Note that this is only for templates.
Implicit redefinition of templates is now deprecated and will give an error in the future.
- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead.
- Several Standard libraries are moved to nimble packages, use `nimble` to install them:
- `std/punycode` => `punycode`
- `std/asyncftpclient` => `asyncftpclient`
- `std/smtp` => `smtp`
- `std/db_common` => `db_connector/db_common`
- `std/db_sqlite` => `db_connector/db_sqlite`
- `std/db_mysql` => `db_connector/db_mysql`
- `std/db_postgres` => `db_connector/db_postgres`
- `std/db_odbc` => `db_connector/db_odbc`
- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of
`foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`.
This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead.
- If no exception or any exception deriving from Exception but not Defect or CatchableError given in except, a `warnBareExcept` warning will be triggered.
- The experimental strictFuncs feature now disallows a store to the heap via a `ref` or `ptr` indirection.
- Underscores (`_`) as routine parameters are now ignored and cannot be used in the routine body.
The following code now does not compile:
```nim
proc foo(_: int): int = _ + 1
echo foo(1)
```
Instead, the following code now compiles:
```nim
proc foo(_, _: int): int = 123
echo foo(1, 2)
```
- Underscores (`_`) as generic parameters are not supported and cannot be used.
Generics that use `_` as parameters will no longer compile requires you to replace `_` with something else:
```nim
proc foo[_](t: typedesc[_]): string = "BAR" # Can not compile
proc foo[T](t: typedesc[T]): string = "BAR" # Can compile
```
- - Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages.
## Standard library additions and changes
[//]: # "Changes:"
- OpenSSL 3 is now supported.
- `macros.parseExpr` and `macros.parseStmt` now accept an optional
filename argument for more informative errors.
- Module `colors` expanded with missing colors from the CSS color standard.
`colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard.
- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)).
- The `md5` module now works at compile time and in JavaScript.
- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef` to support `const` tables.
- `strutils.find` now uses and defaults to `last = -1` for whole string searches,
making limiting it to just the first char (`last = 0`) valid.
- `random.rand` now works with `Ordinal`s.
- Undeprecated `os.isvalidfilename`.
- `std/oids` now uses `int64` to store time internally (before it was int32).
- `std/uri.Uri` dollar `$` improved, precalculates the `string` result length from the `Uri`.
- `std/uri.Uri.isIpv6` is now exported.
- `std/logging.ConsoleLogger` and `FileLogger` now have a `flushThreshold` attribute to set what log message levels are automatically flushed. For Nim v1 use `-d:nimFlushAllLogs` to automatically flush all message levels. Flushing all logs is the default behavior for Nim v2.
- `std/net.IpAddress` dollar `$` improved, uses a fixed capacity for the `string` result based from the `IpAddressFamily`.
- `std/jsfetch.newFetchOptions` now has default values for all parameters
- `std/jsformdata` now accepts `Blob` data type.
- `std/sharedlist` and `std/sharedtables` are now deprecated, see RFC [#433](https://github.com/nim-lang/RFCs/issues/433).
- New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall.
This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17.
On linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall.
When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be:
```sh
$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details
$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8
$ sh build.sh # per unix install instructions
$ bin/nim c koch # per unix install instructions
$ ./koch boot -d:release # per unix install instructions
$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall
```
This is necessary to pass when building nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for stdlib (sysrand in particular).
[//]: # "Additions:"
- Added ISO 8601 week date utilities in `times`:
- Added `IsoWeekRange`, a range type for weeks in a week-based year.
- Added `IsoYear`, a distinct type for a week-based year in contrast to a regular year.
- Added a `initDateTime` overload to create a datetime from an ISO week date.
- Added `getIsoWeekAndYear` to get an ISO week number and week-based year from a datetime.
- Added `getIsoWeeksInYear` to return the number of weeks in a week-based year.
- Added new modules which were part of `std/os`:
- Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling.
- Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`.
- Added `std/cmdline` for reading command line parameters.
- Added `sep` parameter in `std/uri` to specify the query separator.
- Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift)
and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask)
in `jscore` for JavaScript targets.
- Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`.
- Added `complex.sgn` for obtaining the phase of complex numbers.
- Added `insertAdjacentText`, `insertAdjacentElement`, `insertAdjacentHTML`,
`after`, `before`, `closest`, `append`, `hasAttributeNS`, `removeAttributeNS`,
`hasPointerCapture`, `releasePointerCapture`, `requestPointerLock`,
`replaceChildren`, `replaceWith`, `scrollIntoViewIfNeeded`, `setHTML`,
`toggleAttribute`, and `matches` to `std/dom`.
- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices)
- Added `capacity` for `string` and `seq` to return the current capacity, see https://github.com/nim-lang/RFCs/issues/460
- Added `openArray[char]` overloads for `std/parseutils` allowing more code reuse.
- Added `openArray[char]` overloads for `std/unicode` allowing more code reuse.
- Added `safe` parameter to `base64.encodeMime`.
[//]: # "Deprecations:"
- Deprecated `selfExe` for Nimscript.
- Deprecated `std/sums`.
- Deprecated `std/base64.encode` for collections of arbitrary integer element type.
Now only `byte` and `char` are supported.
[//]: # "Removals:"
- Removed deprecated module `parseopt2`.
- Removed deprecated module `sharedstrings`.
- Removed deprecated module `dom_extensions`.
- Removed deprecated module `LockFreeHash`.
- Removed deprecated module `events`.
- Removed deprecated `oids.oidToString`.
- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`.
- Removed deprecated `jsre.test` and `jsre.toString`.
- Removed deprecated `math.c_frexp`.
- Removed deprecated `` httpcore.`==` ``.
- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types.
- Removed deprecated `osproc.poDemon`, symbol with typo.
- Removed deprecated `tables.rightSize`.
- Removed deprecated `posix.CLONE_STOPPED`.
## Language changes
- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) supports the definition of forbidden tags by the `.forbids` pragma
which can be used to disable certain effects in proc types.
- [Case statement macros](https://nim-lang.github.io/Nim/manual.html#macros-case-statement-macros) are no longer experimental,
meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them.
- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed
for the right-hand side of type definitions in type sections. Previously
they would error with "invalid indentation".
- Compile-time define changes:
- `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`.
In the command line, this is defined as `-d:a.b.c`. Older versions can
use accents as in ``defined(`a.b.c`)`` to access such defines.
- [Define pragmas for constants](https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-compileminustime-define-pragmas)
now support a string argument for qualified define names.
```nim
# -d:package.FooBar=42
const FooBar {.intdefine: "package.FooBar".}: int = 5
echo FooBar # 42
```
This was added to help disambiguate similar define names for different packages.
In older versions, this could only be achieved with something like the following:
```nim
const FooBar = block:
const `package.FooBar` {.intdefine.}: int = 5
`package.FooBar`
```
- A generic `define` pragma for constants has been added that interprets
the value of the define based on the type of the constant value.
See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-define-pragma)
for a list of supported types.
- [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes:
- Templates now accept macro pragmas.
- Macro pragmas for var/let/const sections have been redesigned in a way that works
similarly to routine macro pragmas. The new behavior is documented in the
[experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#extended-macro-pragmas).
- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`,
allowing multiple type definitions to be injected in place of the original type definition.
```nim
import macros
macro multiply(amount: static int, s: untyped): untyped =
let name = $s[0].basename
result = newNimNode(nnkTypeSection)
for i in 1 .. amount:
result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2]))
type
Foo = object
Bar {.multiply: 3.} = object
x, y, z: int
Baz = object
# becomes
type
Foo = object
Bar1 = object
x, y, z: int
Bar2 = object
x, y, z: int
Bar3 = object
x, y, z: int
Baz = object
```
- A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference)
has been implemented for a variety of basic cases. For example, code like the following now compiles:
```nim
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
```
- `cstring` is now accepted as a selector in `case` statements, removing the
need to convert to `string`. On the JS backend, this is translated directly
to a `switch` statement.
- Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters).
- Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`.
- IBM Z architecture and macOS m1 arm64 architecture are supported.
- `=wasMoved` can be overridden by users.
## Compiler changes
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
reality better. (Nim moved away from all techniques based on "tracing".)
- Defines the `gcRefc` symbol which allows writing specific code for the refc GC.
- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`,
without requiring `-d:nimVersion140` which is now a noop.
- `--styleCheck`, `--hintAsError` and `--warningAsError` now only apply to the current package.
- The switch `--nimMainPrefix:prefix` has been added to add a prefix to the names of `NimMain` and
related functions produced on the backend. This prevents conflicts with other Nim
static libraries.
- When compiling for Release the flag `-fno-math-errno` is used for GCC.
## Tool changes
- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`).

View File

@@ -510,7 +510,7 @@ type
nfLastRead # this node is a last read
nfFirstWrite # this node is a first write
nfHasComment # node has a comment
nfSkipFieldChecking # node skips field visable checking
nfUseDefaultField # node has a default value (object constructor)
TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 46)
@@ -706,7 +706,7 @@ type
mNctPut, mNctLen, mNctGet, mNctHasNext, mNctNext,
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetStrVal, mNLineInfo,
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mNSigHash, mNSizeOf,
mNBindSym, mNCallSite,
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym,
@@ -796,8 +796,6 @@ type
ident*: PIdent
else:
sons*: TNodeSeq
when defined(nimsuggest):
endInfo*: TLineInfo
TStrTable* = object # a table[PIdent] of PSym
counter*: int
@@ -894,8 +892,6 @@ type
typ*: PType
name*: PIdent
info*: TLineInfo
when defined(nimsuggest):
endInfo*: TLineInfo
owner*: PSym
flags*: TSymFlags
ast*: PNode # syntax tree of proc, iterator, etc.:
@@ -935,7 +931,6 @@ type
TTypeSeq* = seq[PType]
TTypeAttachedOp* = enum ## as usual, order is important here
attachedWasMoved,
attachedDestructor,
attachedAsgn,
attachedSink,
@@ -1081,7 +1076,7 @@ const
nfIsRef, nfIsPtr, nfPreventCg, nfLL,
nfFromTemplate, nfDefaultRefsParam,
nfExecuteOnReload, nfLastRead,
nfFirstWrite, nfSkipFieldChecking}
nfFirstWrite, nfUseDefaultField}
namePos* = 0
patternPos* = 1 # empty except for term rewriting macros
genericParamsPos* = 2
@@ -1503,7 +1498,7 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
const
AttachedOpToStr*: array[TTypeAttachedOp, string] = [
"=wasMoved", "=destroy", "=copy", "=sink", "=trace", "=deepcopy"]
"=destroy", "=copy", "=sink", "=trace", "=deepcopy"]
proc `$`*(s: PSym): string =
if s != nil:
@@ -1695,8 +1690,6 @@ proc copyNode*(src: PNode): PNode =
of nkIdent: result.ident = src.ident
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
else: discard
when defined(nimsuggest):
result.endInfo = src.endInfo
template transitionNodeKindCommon(k: TNodeKind) =
let obj {.inject.} = n[]
@@ -1749,8 +1742,6 @@ template copyNodeImpl(dst, src, processSonsStmt) =
if src == nil: return
dst = newNode(src.kind)
dst.info = src.info
when defined(nimsuggest):
result.endInfo = src.endInfo
dst.typ = src.typ
dst.flags = src.flags * PersistentNodeFlags
dst.comment = src.comment

View File

@@ -20,6 +20,9 @@ import strutils except addf
when defined(nimPreviewSlimSystem):
import std/assertions
when not defined(nimHasCursor):
{.pragma: cursor.}
proc hashNode*(p: RootRef): Hash
proc treeToYaml*(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
# Convert a tree into its YAML representation; this is used by the
@@ -330,7 +333,7 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
sonsRope = rope("null")
elif containsOrIncl(marker, n.id):
sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
strutils.toHex(cast[int](n), sizeof(n) * 2))]
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
else:
if n.len > 0:
sonsRope = rope("[")

View File

@@ -1,25 +0,0 @@
import pragmas, options, ast, trees
proc pushBackendOption(optionsStack: var seq[TOptions], options: var TOptions) =
optionsStack.add options
proc popBackendOption(optionsStack: var seq[TOptions], options: var TOptions) =
options = optionsStack[^1]
optionsStack.setLen(optionsStack.len-1)
proc processPushBackendOption*(optionsStack: var seq[TOptions], options: var TOptions,
n: PNode, start: int) =
pushBackendOption(optionsStack, options)
for i in start..<n.len:
let it = n[i]
if it.kind in nkPragmaCallKinds and it.len == 2 and it[1].kind == nkIntLit:
let sw = whichPragma(it[0])
let opts = pragmaToOptions(sw)
if opts != {}:
if it[1].intVal != 0:
options.incl opts
else:
options.excl opts
template processPopBackendOption*(optionsStack: var seq[TOptions], options: var TOptions) =
popBackendOption(optionsStack, options)

View File

@@ -156,7 +156,7 @@ proc reifiedOpenArray(n: PNode): bool {.inline.} =
else:
result = true
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) =
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope, Rope) =
var a, b, c: TLoc
initLocExpr(p, q[1], a)
initLocExpr(p, q[2], b)
@@ -164,8 +164,6 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
# but first produce the required index checks:
if optBoundsCheck in p.options:
genBoundsCheck(p, a, b, c)
if prepareForMutation:
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
let ty = skipTypes(a.t, abstractVar+{tyPtr})
let dest = getTypeDesc(p.module, destType)
let lengthExpr = "($1)-($2)+1" % [rdLoc(c), rdLoc(b)]
@@ -475,7 +473,6 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
discard "resetLoc(p, d)"
pl.add(addrLoc(p.config, d))
genCallPattern()
if canRaise: raiseExit(p)
else:
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)

View File

@@ -1647,7 +1647,6 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
return
if d.k == locNone:
getTemp(p, n.typ, d)
initLocExpr(p, n[1], a)
# generate call to newSeq before adding the elements per hand:
let L = toInt(lengthOrd(p.config, n[1].typ))
if optSeqDestructors in p.config.globalOptions:
@@ -1659,6 +1658,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
var lit = newRopeAppender()
intLiteral(L, lit)
genNewSeqAux(p, d, lit, L == 0)
initLocExpr(p, n[1], a)
# bug #5007; do not produce excessive C source code:
if L < 10:
for i in 0..<L:
@@ -1704,7 +1704,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo; result: var Rope) =
if optTinyRtti in p.config.globalOptions:
let token = $genDisplayElem(MD5Digest(hashType(dest, p.config)))
let token = $genDisplayElem(MD5Digest(hashType(dest)))
appcg(p.module, result, "#isObjDisplayCheck($#.m_type, $#, $#)", [a, getObjDepth(dest), token])
else:
# unfortunately 'genTypeInfoV1' sets tfObjHasKids as a side effect, so we
@@ -2126,7 +2126,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mCard:
var a: TLoc
initLocExpr(p, e[1], a)
putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [addrLoc(p.config, a), size]))
putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [rdCharLoc(a), size]))
of mLtSet, mLeSet:
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter
initLocExpr(p, e[1], a)
@@ -2408,10 +2408,7 @@ proc genDispose(p: BProc; n: PNode) =
lineCg(p, cpsStmts, ["#nimDestroyAndDispose($#)", rdLoc(a)])
proc genSlice(p: BProc; e: PNode; d: var TLoc) =
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon,
prepareForMutation = e[1].kind == nkHiddenDeref and
e[1].typ.skipTypes(abstractInst).kind == tyString and
p.config.selectedGC in {gcArc, gcOrc})
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon)
if d.k == locNone: getTemp(p, e.typ, d)
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", [rdLoc(d), x, y])
when false:
@@ -2779,7 +2776,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
rdMType(p, a, nilCheck, r)
if optTinyRtti in p.config.globalOptions:
let checkFor = $getObjDepth(dest)
let token = $genDisplayElem(MD5Digest(hashType(dest, p.config)))
let token = $genDisplayElem(MD5Digest(hashType(dest)))
if nilCheck != "":
linefmt(p, cpsStmts, "if ($1 && !#isObjDisplayCheck($2, $3, $4)){ #raiseObjectConversionError(); ",
[nilCheck, r, checkFor, token])
@@ -3203,8 +3200,6 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Rope) =
result.add "}"
of tyTuple:
result.add "{"
if p.vccAndC and t.len == 0:
result.add "0"
for i in 0..<t.len:
if i > 0: result.add ", "
getDefaultValue(p, t[i], info, result)
@@ -3334,8 +3329,6 @@ proc genConstObjConstr(p: BProc; n: PNode; isConst: bool; result: var Rope) =
proc genConstSimpleList(p: BProc, n: PNode; isConst: bool; result: var Rope) =
result.add "{"
if p.vccAndC and n.len == 0 and n.typ.kind == tyArray:
getDefaultValue(p, n.typ[1], n.info, result)
for i in 0..<n.len:
let it = n[i]
if i > 0: result.add ",\n"
@@ -3345,8 +3338,6 @@ proc genConstSimpleList(p: BProc, n: PNode; isConst: bool; result: var Rope) =
proc genConstTuple(p: BProc, n: PNode; isConst: bool; tup: PType; result: var Rope) =
result.add "{"
if p.vccAndC and n.len == 0:
result.add "0"
for i in 0..<n.len:
let it = n[i]
if i > 0: result.add ",\n"

View File

@@ -8,6 +8,7 @@
#
# included from cgen.nim
const
RangeExpandLimit = 256 # do not generate ranges
# over 'RangeExpandLimit' elements
@@ -1081,7 +1082,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
if optTinyRtti in p.config.globalOptions:
let checkFor = $getObjDepth(typeNode.typ)
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(typeNode.typ, p.config)))])
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(typeNode.typ)))])
else:
let checkFor = genTypeInfoV1(p.module, typeNode.typ, typeNode.info)
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
@@ -1300,7 +1301,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
if optTinyRtti in p.config.globalOptions:
let checkFor = $getObjDepth(t[i][j].typ)
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ)))])
else:
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
@@ -1445,7 +1446,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
if optTinyRtti in p.config.globalOptions:
let checkFor = $getObjDepth(t[i][j].typ)
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ)))])
else:
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
@@ -1537,7 +1538,7 @@ proc determineSection(n: PNode): TCFileSection =
result = cfsProcHeaders
if n.len >= 1 and n[0].kind in {nkStrLit..nkTripleStrLit}:
let sec = n[0].strVal
if sec.startsWith("/*TYPESECTION*/"): result = cfsForwardTypes # TODO WORKAROUND
if sec.startsWith("/*TYPESECTION*/"): result = cfsTypes
elif sec.startsWith("/*VARSECTION*/"): result = cfsVars
elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders
@@ -1554,14 +1555,9 @@ proc genEmit(p: BProc, t: PNode) =
line(p, cpsStmts, s)
proc genPragma(p: BProc, n: PNode) =
for i in 0..<n.len:
let it = n[i]
for it in n.sons:
case whichPragma(it)
of wEmit: genEmit(p, it)
of wPush:
processPushBackendOption(p.optionsStack, p.options, n, i+1)
of wPop:
processPopBackendOption(p.optionsStack, p.options)
else: discard
@@ -1579,8 +1575,6 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
"#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
lit])
if p.config.exc == excGoto:
raiseExit(p)
when false:
proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) =
@@ -1605,7 +1599,7 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
initLocExpr(p, e[0], a)
getTemp(p, a.t, tmp)
expr(p, e[1], tmp)
if p.inUncheckedAssignSection == 0:
if optTinyRtti notin p.config.globalOptions and p.inUncheckedAssignSection == 0:
let field = dotExpr[1].sym
genDiscriminantCheck(p, a, tmp, dotExpr[0].typ, field)
message(p.config, e.info, warnCaseTransition)
@@ -1626,7 +1620,6 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
initLoc(a, locNone, le, OnUnknown)
a.flags.incl(lfEnforceDeref)
a.flags.incl(lfPrepareForMutation)
genLineDir(p, le) # it can be a nkBracketExpr, which may raise
expr(p, le, a)
a.flags.excl(lfPrepareForMutation)
if fastAsgn: incl(a.flags, lfNoDeepCopy)

View File

@@ -43,14 +43,16 @@ proc fillBackendName(m: BModule; s: PSym) =
result.add rope s.itemId.item
if m.hcrOn:
result.add "_"
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config))
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts))
s.loc.r = result
writeMangledName(m.ndi, s, m.config)
proc fillParamName(m: BModule; s: PSym) =
## we cannot use 'sigConflicts' here since we have a BModule, not a BProc.
## Fortunately C's scoping rules are sane enough so that that doesn't
## cause any trouble.
if s.loc.r == "":
var res = s.name.s.mangle
res.add idOrSig(s, res, m.sigConflicts, m.config)
# Take into account if HCR is on because of the following scenario:
# if a module gets imported and it has some more importc symbols in it,
# some param names might receive the "_0" suffix to distinguish from what
@@ -67,6 +69,8 @@ proc fillParamName(m: BModule; s: PSym) =
# and a function called in main or proxy uses `socket` as a parameter name.
# That would lead to either needing to reload `proxy` or to overwrite the
# executable file for the main module, which is running (or both!) -> error.
if m.hcrOn or isKeyword(s.name) or m.g.config.cppDefines.contains(res):
res.add "_0"
s.loc.r = res.rope
writeMangledName(m.ndi, s, m.config)
@@ -302,7 +306,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
else: result = ""
if result != "" and typ.isImportedType():
let sig = hashType(typ, m.config)
let sig = hashType typ
if cacheGetType(m.typeCache, sig) == "":
m.typeCache[sig] = result
@@ -362,10 +366,10 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): R
if isImportedCppType(etB) and t.kind == tyGenericInst:
result = getTypeDescAux(m, t, check, kind)
else:
result = getTypeForward(m, t, hashType(t, m.config))
result = getTypeForward(m, t, hashType(t))
pushType(m, t)
of tySequence:
let sig = hashType(t, m.config)
let sig = hashType(t)
if optSeqDestructors in m.config.globalOptions:
if skipTypes(etB[0], typedescInst).kind == tyEmpty:
internalError(m.config, "cannot map the empty seq type to a C type")
@@ -398,7 +402,7 @@ proc getSeqPayloadType(m: BModule; t: PType): Rope =
#result = getTypeForward(m, t, hashType(t)) & "_Content"
proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) =
let sig = hashType(t, m.config)
let sig = hashType(t)
let result = cacheGetType(m.typeCache, sig)
if result == "":
discard getTypeDescAux(m, t, check, skVar)
@@ -664,7 +668,7 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
else: result.elemType
proc getOpenArrayDesc(m: BModule, t: PType, check: var IntSet; kind: TSymKind): Rope =
let sig = hashType(t, m.config)
let sig = hashType(t)
if kind == skParam:
result = getTypeDescWeak(m, t[0], check, kind) & "*"
else:
@@ -688,7 +692,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
# C type generation into an analysis and a code generation phase somehow.
if t.sym != nil: useHeader(m, t.sym)
if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym)
let sig = hashType(origTyp, m.config)
let sig = hashType(origTyp)
defer: # defer is the simplest in this case
if isImportedType(t) and not m.typeABICache.containsOrIncl(sig):
@@ -717,7 +721,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
result = getTypeDescAux(m, et, check, kind) & star
else:
# no restriction! We have a forward declaration for structs
let name = getTypeForward(m, et, hashType(et, m.config))
let name = getTypeForward(m, et, hashType et)
result = name & star
m.typeCache[sig] = result
of tySequence:
@@ -726,7 +730,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
m.typeCache[sig] = result
else:
# no restriction! We have a forward declaration for structs
let name = getTypeForward(m, et, hashType(et, m.config))
let name = getTypeForward(m, et, hashType et)
result = name & seqStar(m) & star
m.typeCache[sig] = result
pushType(m, et)
@@ -826,8 +830,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
m.s[cfsTypes].addf("typedef $1 $2[$3];$n",
[foo, result, rope(n)])
of tyObject, tyTuple:
let tt = origTyp.skipTypes({tyDistinct})
if isImportedCppType(t) and tt.kind == tyGenericInst:
if isImportedCppType(t) and origTyp.kind == tyGenericInst:
let cppNameAsRope = getTypeName(m, t, sig)
let cppName = $cppNameAsRope
var i = 0
@@ -850,7 +853,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
result.add cppName.substr(chunkStart, chunkEnd)
chunkStart = i
let typeInSlot = resolveStarsInCppType(tt, idx + 1, stars)
let typeInSlot = resolveStarsInCppType(origTyp, idx + 1, stars)
addResultType(typeInSlot)
else:
inc i
@@ -859,9 +862,9 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
result.add cppName.substr(chunkStart)
else:
result = cppNameAsRope & "<"
for i in 1..<tt.len-1:
for i in 1..<origTyp.len-1:
if i > 1: result.add(" COMMA ")
addResultType(tt[i])
addResultType(origTyp[i])
result.add("> ")
# always call for sideeffects:
assert t.kind != tyTuple
@@ -893,7 +896,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
# Don't use the imported name as it may be scoped: 'Foo::SomeKind'
result = rope("tySet_")
t.lastSon.typeName(result)
result.add $t.lastSon.hashType(m.config)
result.add $t.lastSon.hashType
m.typeCache[sig] = result
if not isImportedType(t):
let s = int(getSize(m.config, t))
@@ -1066,7 +1069,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
objtype = objtype[0].skipTypes(abstractPtrs)
if objtype.sym == nil:
internalError(m.config, d.info, "anonymous obj with discriminator")
result = "NimDT_$1_$2" % [rope($hashType(objtype, m.config)), rope(d.name.s.mangle)]
result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)]
proc rope(arg: Int128): Rope = rope($arg)
@@ -1285,7 +1288,7 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope =
result.add m.name.s & "."
result.add it.sym.name.s
else:
result = $hashType(it, m.config)
result = $hashType(it)
result = makeCString(result)
proc isTrivialProc(g: ModuleGraph; s: PSym): bool {.inline.} = getBody(g, s).len == 0
@@ -1329,14 +1332,14 @@ proc genDisplayElem(d: MD5Digest): uint32 =
result += uint32(d[i])
result = result shl 8
proc genDisplay(m: BModule, t: PType, depth: int): Rope =
proc genDisplay(t: PType, depth: int): Rope =
result = Rope"{"
var x = t
var seqs = newSeq[string](depth+1)
var i = 0
while x != nil:
x = skipTypes(x, skipPtrs)
seqs[i] = $genDisplayElem(MD5Digest(hashType(x, m.config)))
seqs[i] = $genDisplayElem(MD5Digest(hashType(x)))
x = x[0]
inc i
@@ -1376,7 +1379,7 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin
[name, getTypeDesc(m, t), rope(objDepth), rope(flags)])
if objDepth >= 0:
let objDisplay = genDisplay(m, t, objDepth)
let objDisplay = genDisplay(t, objDepth)
let objDisplayStore = getTempName(m)
m.s[cfsVars].addf("static $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), skVar), objDisplayStore, rope(objDepth+1), objDisplay])
addf(typeEntry, "$1.display = $2;$n", [name, rope(objDisplayStore)])
@@ -1408,7 +1411,7 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn
[getTypeDesc(m, t), rope(objDepth)])
if objDepth >= 0:
let objDisplay = genDisplay(m, t, objDepth)
let objDisplay = genDisplay(t, objDepth)
let objDisplayStore = getTempName(m)
m.s[cfsVars].addf("static NIM_CONST $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), skVar), objDisplayStore, rope(objDepth+1), objDisplay])
addf(typeEntry, ", .display = $1", [rope(objDisplayStore)])
@@ -1435,7 +1438,7 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope =
let prefixTI = if m.hcrOn: "(" else: "(&"
let sig = hashType(origType, m.config)
let sig = hashType(origType)
result = m.typeInfoMarkerV2.getOrDefault(sig)
if result != "":
return prefixTI.rope & result & ")".rope
@@ -1509,7 +1512,7 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
let prefixTI = if m.hcrOn: "(" else: "(&"
let sig = hashType(origType, m.config)
let sig = hashType(origType)
result = m.typeInfoMarker.getOrDefault(sig)
if result != "":
return prefixTI.rope & result & ")".rope

View File

@@ -53,7 +53,7 @@ proc hashString*(conf: ConfigRef; s: string): BiggestInt =
a = a + (a shl 3)
a = a xor (a shr 11)
a = a + (a shl 15)
result = cast[Hash](uint(a))
result = cast[Hash](a)
template getUniqueType*(key: PType): PType = key

View File

@@ -12,12 +12,10 @@
import
ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
nversion, nimsets, msgs, bitsets, idents, types,
ccgutils, os, ropes, math, wordrecg, treetab, cgmeth,
ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
rodutils, renderer, cgendata, aliases,
lowerings, tables, sets, ndi, lineinfos, pathutils, transf,
injectdestructors, astmsgs, modulepaths, backendpragmas
import pipelineutils
injectdestructors, astmsgs, modulepaths
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -228,12 +226,8 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
result.add newCall(ident"rope", resVar)
proc addIndent(p: BProc; result: var Rope) =
var i = result.len
let newLen = i + p.blocks.len
result.setLen newLen
while i < newLen:
result[i] = '\t'
inc i
for i in 0..<p.blocks.len:
result.add "\t".rope
template appcg(m: BModule, c: var Rope, frmt: FormatStr,
args: untyped) =
@@ -277,8 +271,7 @@ proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
[rope(makeSingleLineCString(filename)), rope(line)])
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
if optLineDir in conf.options:
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf)
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf)
proc freshLineInfo(p: BProc; info: TLineInfo): bool =
if p.lastLineInfo.line != info.line or
@@ -292,7 +285,7 @@ proc genLineDir(p: BProc, t: PNode) =
if optEmbedOrigSrc in p.config.globalOptions:
p.s(cpsStmts).add("//" & sourceLine(p.config, t.info) & "\L")
genCLineDir(p.s(cpsStmts), t.info, p.config)
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config)
if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
if freshLineInfo(p, t.info):
@@ -487,9 +480,6 @@ proc resetLoc(p: BProc, loc: var TLoc) =
# on the bytes following the m_type field?
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
proc isOrHasImportedCppType(typ: PType): bool =
searchTypeFor(typ.skipTypes({tyRef}), isImportedCppType)
proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
let typ = loc.t
if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}:
@@ -507,7 +497,7 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
if not isTemp or containsGarbageCollectedRef(loc.t):
# don't use nimZeroMem for temporary values for performance if we can
# avoid it:
if not isOrHasImportedCppType(typ):
if not isImportedCppType(typ):
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))])
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
@@ -527,10 +517,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
inc(p.labels)
result.r = "T" & rope(p.labels) & "_"
if p.module.compileToCpp and isOrHasImportedCppType(t):
linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, skVar), result.r])
else:
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r])
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
@@ -571,9 +558,6 @@ proc localVarDecl(p: BProc; n: PNode): Rope =
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
result.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
genCLineDir(result, n.info, p.config)
result.add getTypeDesc(p.module, s.typ, skVar)
if s.constraint.isNil:
if sfRegister in s.flags: result.add(" register")
@@ -591,7 +575,7 @@ proc assignLocalVar(p: BProc, n: PNode) =
# this need not be fulfilled for inline procs; they are regenerated
# for each module that uses them!
let nl = if optLineDir in p.config.options: "" else: "\L"
let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};" else: ";") & nl
let decl = localVarDecl(p, n) & ";" & nl
line(p, cpsLocals, decl)
include ccgthreadvars
@@ -1640,7 +1624,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
hcrModuleMeta.addf("\t\"\"};$n", [])
hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(void**, HcrGetImportedModules)() { return (void**)hcr_module_list; }$n", [])
hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(char*, HcrGetSigHash)() { return \"$1\"; }$n$n",
[($sigHash(m.module, m.config)).rope])
[($sigHash(m.module)).rope])
if sfMainModule in m.module.flags:
g.mainModProcs.add(hcrModuleMeta)
g.mainModProcs.addf("static void* hcr_handle;$N", [])
@@ -1817,9 +1801,6 @@ proc genInitCode(m: BModule) =
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
prc.add(deinitFrame(m.initProc))
elif sfMainModule in m.module.flags and m.config.exc == excGoto:
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
prc.addf("}$N", [])
@@ -1948,7 +1929,10 @@ template injectG() {.dirty.} =
graph.backend = newModuleList(graph)
let g = BModuleList(graph.backend)
proc setupCgen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
when not defined(nimHasSinkInference):
{.pragma: nosinks.}
proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} =
injectG()
result = newModule(g, module, graph.config)
result.idgen = idgen
@@ -2016,7 +2000,7 @@ proc addHcrInitGuards(p: BProc, n: PNode, inInitGuard: var bool) =
proc genTopLevelStmt*(m: BModule; n: PNode) =
## Also called from `ic/cbackend.nim`.
if pipelineutils.skipCodegen(m.config, n): return
if passes.skipCodegen(m.config, n): return
m.initProc.options = initProcOptions(m)
#softRnl = if optLineDir in m.config.options: noRnl else: rnl
# XXX replicate this logic!
@@ -2029,6 +2013,12 @@ proc genTopLevelStmt*(m: BModule; n: PNode) =
else:
genProcBody(m.initProc, transformedN)
proc myProcess(b: PPassContext, n: PNode): PNode =
result = n
if b != nil:
var m = BModule(b)
genTopLevelStmt(m, n)
proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
if optForceFullMake notin m.config.globalOptions:
if not moduleHasChanged(m.g.graph, m.module):
@@ -2105,7 +2095,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
if {optGenStaticLib, optGenDynLib, optNoMain} * m.config.globalOptions == {}:
for i in countdown(high(graph.globalDestructors), 0):
n.add graph.globalDestructors[i]
if pipelineutils.skipCodegen(m.config, n): return
if passes.skipCodegen(m.config, n): return
if moduleHasChanged(graph, m.module):
# if the module is cached, we don't regenerate the main proc
# nor the dispatchers? But if the dispatchers changed?
@@ -2146,6 +2136,12 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: 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
@@ -2172,3 +2168,5 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
m.writeModule(pending=true)
writeMapping(config, g.mapping)
if g.generatedHeader != nil: writeHeader(g.generatedHeader)
const cgenPass* = makePass(myOpen, myProcess, myClose)

View File

@@ -86,7 +86,6 @@ type
options*: TOptions # options that should be used for code
# generation; this is the same as prc.options
# unless prc == nil
optionsStack*: seq[TOptions]
module*: BModule # used to prevent excessive parameter passing
withinLoop*: int # > 0 if we are within a loop
splitDecls*: int # > 0 if we are in some context for C++ that
@@ -173,7 +172,6 @@ type
template config*(m: BModule): ConfigRef = m.g.config
template config*(p: BProc): ConfigRef = p.module.g.config
template vccAndC*(p: BProc): bool = p.module.config.cCompiler == ccVcc and p.module.config.backend == backendC
proc includeHeader*(this: BModule; header: string) =
if not this.headerFiles.contains header:

View File

@@ -649,8 +649,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "backend", "b":
let backend = parseEnum(arg.normalize, TBackend.default)
if backend == TBackend.default: localError(conf, info, "invalid backend: '$1'" % arg)
if backend == backendJs: # bug #21209
conf.globalOptions.excl {optThreadAnalysis, optThreads}
conf.backend = backend
of "doccmd": conf.docCmd = arg
of "define", "d":
@@ -822,13 +820,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
if conf != nil: conf.headerFile = arg
incl(conf.globalOptions, optGenIndex)
of "index":
case arg.normalize
of "", "on": conf.globalOptions.incl {optGenIndex}
of "only": conf.globalOptions.incl {optGenIndexOnly, optGenIndex}
of "off": conf.globalOptions.excl {optGenIndex, optGenIndexOnly}
else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
of "noimportdoc":
processOnOffSwitchG(conf, {optNoImportdoc}, arg, pass, info)
processOnOffSwitchG(conf, {optGenIndex}, arg, pass, info)
of "import":
expectArg(conf, switch, arg, pass, info)
if pass in {passCmd2, passPP}:
@@ -1008,9 +1000,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
expectNoArg(conf, switch, arg, pass, info)
conf.exc = low(ExceptionSystem)
defineSymbol(conf.symbols, "noCppExceptions")
of "shownonexports":
expectNoArg(conf, switch, arg, pass, info)
showNonExportedFields(conf)
of "exceptions":
case arg.normalize
of "cpp": conf.exc = excCpp

View File

@@ -274,7 +274,7 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
proc matchSyms(c: PContext, n: PNode; kinds: set[TSymKind]; m: var MatchCon): bool =
## Walk the current scope, extract candidates which the same name as 'n[namePos]',
## 'n' is the nkProcDef or similar from the concept that we try to match.
let candidates = searchInScopesAllCandidatesFilterBy(c, n[namePos].sym.name, kinds)
let candidates = searchInScopesFilterBy(c, n[namePos].sym.name, kinds)
for candidate in candidates:
#echo "considering ", typeToString(candidate.typ), " ", candidate.magic
m.magic = candidate.magic

View File

@@ -25,7 +25,7 @@ proc undefSymbol*(symbols: StringTableRef; symbol: string) =
# result = if isDefined(symbol): gSymbols[symbol] else: nil
iterator definedSymbolNames*(symbols: StringTableRef): string =
for key in keys(symbols):
for key, val in pairs(symbols):
yield key
proc countDefinedSymbols*(symbols: StringTableRef): int =
@@ -84,24 +84,10 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasSignatureHashInMacro") # deadcode
defineSymbol("nimHasDefault") # deadcode
defineSymbol("nimMacrosSizealignof") # deadcode
defineSymbol("nimNoZeroExtendMagic") # deadcode
defineSymbol("nimMacrosGetNodeId") # deadcode
defineSymbol("nimFixedForwardGeneric") # deadcode
defineSymbol("nimToOpenArrayCString") # deadcode
defineSymbol("nimHasUsed") # deadcode
defineSymbol("nimnomagic64") # deadcode
defineSymbol("nimNewShiftOps") # deadcode
defineSymbol("nimHasCursor") # deadcode
defineSymbol("nimAlignPragma") # deadcode
defineSymbol("nimHasExceptionsQuery") # deadcode
defineSymbol("nimHasIsNamedTuple") # deadcode
defineSymbol("nimHashOrdinalFixed") # deadcode
defineSymbol("nimHasSinkInference") # deadcode
defineSymbol("nimNewIntegerOps") # deadcode
defineSymbol("nimHasInvariant") # deadcode
# > 0.20.0
defineSymbol("nimNoZeroExtendMagic")
defineSymbol("nimMacrosGetNodeId")
for f in Feature:
defineSymbol("nimHas" & $f)
@@ -112,18 +98,31 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimFixedOwned")
defineSymbol("nimHasStyleChecks")
defineSymbol("nimToOpenArrayCString")
defineSymbol("nimHasUsed")
defineSymbol("nimFixedForwardGeneric")
defineSymbol("nimnomagic64")
defineSymbol("nimNewShiftOps")
defineSymbol("nimHasCursor")
defineSymbol("nimAlignPragma")
defineSymbol("nimHasExceptionsQuery")
defineSymbol("nimHasIsNamedTuple")
defineSymbol("nimHashOrdinalFixed")
when defined(nimHasLibFFI):
# Renaming as we can't conflate input vs output define flags; e.g. this
# will report the right thing regardless of whether user adds
# `-d:nimHasLibFFI` in his user config.
defineSymbol("nimHasLibFFIEnabled") # deadcode
defineSymbol("nimHasLibFFIEnabled")
defineSymbol("nimHasStacktraceMsgs") # deadcode
defineSymbol("nimHasSinkInference")
defineSymbol("nimNewIntegerOps")
defineSymbol("nimHasInvariant")
defineSymbol("nimHasStacktraceMsgs")
defineSymbol("nimDoesntTrackDefects")
defineSymbol("nimHasLentIterators") # deadcode
defineSymbol("nimHasDeclaredMagic") # deadcode
defineSymbol("nimHasStacktracesModule") # deadcode
defineSymbol("nimHasLentIterators")
defineSymbol("nimHasDeclaredMagic")
defineSymbol("nimHasStacktracesModule")
defineSymbol("nimHasEffectTraitsModule")
defineSymbol("nimHasCastPragmaBlocks")
defineSymbol("nimHasDeclaredLocs")
@@ -134,8 +133,8 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasCustomLiterals")
defineSymbol("nimHasUnifiedTuple")
defineSymbol("nimHasIterable")
defineSymbol("nimHasTypeofVoid") # deadcode
defineSymbol("nimHasDragonBox") # deadcode
defineSymbol("nimHasTypeofVoid")
defineSymbol("nimHasDragonBox")
defineSymbol("nimHasHintAll")
defineSymbol("nimHasTrace")
defineSymbol("nimHasEffectsOf")
@@ -147,10 +146,8 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasCallsitePragma")
defineSymbol("nimHasAmbiguousEnumHint")
defineSymbol("nimHasWarnCastSizes")
defineSymbol("nimHasOutParams")
defineSymbol("nimHasSystemRaisesDefect")
defineSymbol("nimHasWarnUnnamedBreak")
defineSymbol("nimHasGenericDefine")
defineSymbol("nimHasDefineAliases")
defineSymbol("nimHasWarnBareExcept")

View File

@@ -9,7 +9,7 @@
# This module implements a dependency file generator.
import options, ast, ropes, pathutils, msgs, lineinfos
import options, ast, ropes, passes, pathutils, msgs, lineinfos
import modulegraphs
@@ -79,7 +79,7 @@ proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
let child = nativeToUnixPath(path.dir / path.name).toNimblePath(belongsToStdlib(g.graph, n.sym))
addDependencyAux(b, parent, child)
proc addDotDependency*(c: PPassContext, n: PNode): PNode =
proc addDotDependency(c: PPassContext, n: PNode): PNode =
result = n
let g = PGen(c)
let b = Backend(g.graph.backend)
@@ -100,7 +100,10 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
rope(project.splitFile.name), b.dotGraph],
changeFileExt(project, "dot"))
proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
when not defined(nimHasSinkInference):
{.pragma: nosinks.}
proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} =
var g: PGen
new(g)
g.module = module
@@ -109,3 +112,6 @@ proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPa
if graph.backend == nil:
graph.backend = Backend(dotGraph: "")
result = g
const gendependPass* = makePass(open = myOpen, process = addDotDependency)

View File

@@ -7,17 +7,13 @@
# distribution, for details about the copyright.
#
## This is the Nim documentation generator. Cross-references are generated
## by knowing how the anchors are going to be named.
##
## .. importdoc:: ../docgen.md
##
## For corresponding users' documentation see [Nim DocGen Tools Guide].
# This is the documentation generator. Cross-references are generated
# by knowing how the anchors are going to be named.
import
ast, strutils, strtabs, algorithm, sequtils, options, msgs, os, idents,
wordrecg, syntaxes, renderer, lexer,
packages/docutils/[rst, rstidx, rstgen, dochelpers],
packages/docutils/[rst, rstgen, dochelpers],
json, xmltree, trees, types,
typesrenderer, astalgo, lineinfos, intsets,
pathutils, tables, nimpaths, renderverbatim, osproc, packages
@@ -95,7 +91,7 @@ type
jEntriesFinal: JsonNode # final JSON after RST pass 2 and rendering
types: TStrTable
sharedState: PRstSharedState
standaloneDoc: bool # is markup (.rst/.md) document?
standaloneDoc: bool
conf*: ConfigRef
cache*: IdentCache
exampleCounter: int
@@ -229,7 +225,7 @@ proc attachToType(d: PDoc; p: PSym): PSym =
if params.len > 0: check(0)
for i in 2..<params.len: check(i)
template declareClosures(currentFilename: AbsoluteFile, destFile: string) =
template declareClosures =
proc compilerMsgHandler(filename: string, line, col: int,
msgKind: rst.MsgKind, arg: string) {.gcsafe.} =
# translate msg kind:
@@ -253,7 +249,6 @@ template declareClosures(currentFilename: AbsoluteFile, destFile: string) =
of mwBrokenLink: k = warnRstBrokenLink
of mwUnsupportedLanguage: k = warnRstLanguageXNotSupported
of mwUnsupportedField: k = warnRstFieldXNotSupported
of mwUnusedImportdoc: k = warnRstUnusedImportdoc
of mwRstStyle: k = warnRstStyle
{.gcsafe.}:
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
@@ -264,29 +259,10 @@ template declareClosures(currentFilename: AbsoluteFile, destFile: string) =
result = getCurrentDir() / s
if not fileExists(result): result = ""
proc docgenFindRefFile(targetRelPath: string):
tuple[targetPath: string, linkRelPath: string] {.gcsafe.} =
let fromDir = splitFile(destFile).dir # dir where we reference from
let basedir = os.splitFile(currentFilename.string).dir
let outDirPath: RelativeFile =
presentationPath(conf, AbsoluteFile(basedir / targetRelPath))
# use presentationPath because `..` path can be be mangled to `_._`
result.targetPath = string(conf.outDir / outDirPath)
if not fileExists(result.targetPath):
# this can happen if targetRelPath goes to parent directory `OUTDIR/..`.
# Trying it, this may cause ambiguities, but allows us to insert
# "packages" into each other, which is actually used in Nim repo itself.
let destPath = fromDir / targetRelPath
if destPath != result.targetPath and fileExists(destPath):
result.targetPath = destPath
result.linkRelPath = relativePath(result.targetPath.splitFile.dir,
fromDir).replace('\\', '/')
proc parseRst(text: string,
line, column: int,
conf: ConfigRef, sharedState: PRstSharedState): PRstNode =
declareClosures()
result = rstParsePass1(text, line, column, sharedState)
proc getOutFile2(conf: ConfigRef; filename: RelativeFile,
@@ -307,8 +283,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
outExt: string = HtmlExt, module: PSym = nil,
standaloneDoc = false, preferMarkdown = true,
hasToc = true): PDoc =
let destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false).string
declareClosures(currentFilename = filename, destFile = destFile)
declareClosures()
new(result)
result.module = module
result.conf = conf
@@ -323,7 +298,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
result.hasToc = hasToc
result.sharedState = newRstSharedState(
options, filename.string,
docgenFindFile, docgenFindRefFile, compilerMsgHandler, hasToc)
docgenFindFile, compilerMsgHandler, hasToc)
initRstGenerator(result[], (if conf.isLatexCmd: outLatex else: outHtml),
conf.configVars, filename.string,
docgenFindFile, compilerMsgHandler)
@@ -398,7 +373,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
if gotten != status:
rawMessage(conf, errGenerated, "snippet failed: cmd: '$1' status: $2 expected: $3 output: $4" % [cmd, $gotten, $status, output])
result.emitted = initIntSet()
result.destFile = destFile
result.destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false).string
result.thisDir = result.destFile.AbsoluteFile.splitFile.dir
template dispA(conf: ConfigRef; dest: var string, xml, tex: string,
@@ -790,24 +765,21 @@ proc isVisible(d: PDoc; n: PNode): bool =
elif n.kind == nkPragmaExpr:
result = isVisible(d, n[0])
proc getName(n: PNode): string =
proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
case n.kind
of nkPostfix: result = getName(n[1])
of nkPragmaExpr: result = getName(n[0])
of nkSym: result = n.sym.renderDefinitionName
of nkIdent: result = n.ident.s
of nkPostfix: result = getName(d, n[1], splitAfter)
of nkPragmaExpr: result = getName(d, n[0], splitAfter)
of nkSym: result = esc(d.target, n.sym.renderDefinitionName, splitAfter)
of nkIdent: result = esc(d.target, n.ident.s, splitAfter)
of nkAccQuoted:
result = "`"
for i in 0..<n.len: result.add(getName(n[i]))
result = "`"
result = esc(d.target, "`")
for i in 0..<n.len: result.add(getName(d, n[i], splitAfter))
result.add esc(d.target, "`")
of nkOpenSymChoice, nkClosedSymChoice:
result = getName(n[0])
result = getName(d, n[0], splitAfter)
else:
result = ""
proc getNameEsc(d: PDoc, n: PNode): string =
esc(d.target, getName(n))
proc getNameIdent(cache: IdentCache; n: PNode): PIdent =
case n.kind
of nkPostfix: result = getNameIdent(cache, n[1])
@@ -956,13 +928,6 @@ proc symbolPriority(k: TSymKind): int =
else: 0 # including skProc which have higher priority
# documentation itself has even higher priority 1
proc getTypeKind(n: PNode): string =
case n[2].kind
of nkEnumTy: "enum"
of nkObjectTy: "object"
of nkTupleTy: "tuple"
else: ""
proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
## Converts symbol info (names/types/parameters) in `n` into format
## `LangSymbol` convenient for ``rst.nim``/``dochelpers.nim``.
@@ -1006,13 +971,17 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
if kind != tkSpaces:
result.generics.add(literal.nimIdentNormalize)
if k == skType: result.symTypeKind = getTypeKind(n)
if k == skType:
case n[2].kind
of nkEnumTy: result.symTypeKind = "enum"
of nkObjectTy: result.symTypeKind = "object"
of nkTupleTy: result.symTypeKind = "tuple"
else: discard
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonExports: bool = false) =
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
if (docFlags != kForceExport) and not isVisible(d, nameNode): return
let
name = getName(nameNode)
nameEsc = esc(d.target, name)
name = getName(d, nameNode)
var plainDocstring = getPlainDocstring(n) # call here before genRecComment!
var result = ""
var literal, plainName = ""
@@ -1039,12 +1008,9 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
inc(d.id)
let
plainNameEsc = esc(d.target, plainName.strip)
typeDescr =
if k == skType and getTypeKind(n) != "": getTypeKind(n)
else: k.toHumanStr
detailedName = typeDescr & " " & (
detailedName = k.toHumanStr & " " & (
if k in routineKinds: plainName else: name)
uniqueName = if k in routineKinds: plainNameEsc else: nameEsc
uniqueName = if k in routineKinds: plainNameEsc else: name
sortName = if k in routineKinds: plainName.strip else: name
cleanPlainSymbol = renderPlainSymbolName(nameNode)
complexSymbol = complexName(k, n, cleanPlainSymbol)
@@ -1058,15 +1024,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
let lineinfo = rstast.TLineInfo(
line: nameNode.info.line, col: nameNode.info.col,
fileIndex: addRstFileIndex(d, nameNode.info))
addAnchorNim(d.sharedState, external = false, refn = symbolOrId,
tooltip = detailedName, langSym = rstLangSymbol,
priority = symbolPriority(k), info = lineinfo)
addAnchorNim(d.sharedState, refn = symbolOrId, tooltip = detailedName,
rstLangSymbol, priority = symbolPriority(k), info = lineinfo)
let renderFlags =
if nonExports: {renderNoBody, renderNoComments, renderDocComments, renderSyms,
renderExpandUsing, renderNonExportedFields}
else: {renderNoBody, renderNoComments, renderDocComments, renderSyms, renderExpandUsing}
nodeToHighlightedHtml(d, n, result, renderFlags, symbolOrIdEnc)
nodeToHighlightedHtml(d, n, result, {renderNoBody, renderNoComments,
renderDocComments, renderSyms, renderExpandUsing}, symbolOrIdEnc)
let seeSrc = genSeeSrc(d, toFullPath(d.conf, n.info), n.info.line.int)
@@ -1098,10 +1060,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
if e.sym.kind != skEnumField: continue
let plain = renderPlainSymbolName(e)
let symbolOrId = d.newUniquePlainSymbol(plain)
setIndexTerm(d[], ieNim, htmlFile = external, id = symbolOrId,
term = plain, linkTitle = nameNode.sym.name.s & '.' & plain,
linkDesc = xmltree.escape(getPlainDocstring(e).docstringSummary),
line = n.info.line.int)
setIndexTerm(d[], external, symbolOrId, plain, nameNode.sym.name.s & '.' & plain,
xmltree.escape(getPlainDocstring(e).docstringSummary))
d.tocSimple[k].add TocItem(
sortName: sortName,
@@ -1116,17 +1076,22 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
"itemSymOrID", symbolOrId.replace(",", ",<wbr>"),
"itemSymOrIDEnc", symbolOrIdEnc])
setIndexTerm(d[], ieNim, htmlFile = external, id = symbolOrId, term = name,
linkTitle = detailedName,
linkDesc = xmltree.escape(plainDocstring.docstringSummary),
line = n.info.line.int)
# Ironically for types the complexSymbol is *cleaner* than the plainName
# because it doesn't include object fields or documentation comments. So we
# use the plain one for callable elements, and the complex for the rest.
var linkTitle = changeFileExt(extractFilename(d.filename), "") & ": "
if n.kind in routineDefs: linkTitle.add(xmltree.escape(plainName.strip))
else: linkTitle.add(xmltree.escape(complexSymbol.strip))
setIndexTerm(d[], external, symbolOrId, name, linkTitle,
xmltree.escape(plainDocstring.docstringSummary))
if k == skType and nameNode.kind == nkSym:
d.types.strTableAdd nameNode.sym
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonItem =
if not isVisible(d, nameNode): return
var
name = getNameEsc(d, nameNode)
name = getName(d, nameNode)
comm = genRecComment(d, n)
r: TSrcGen
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing})
@@ -1314,13 +1279,12 @@ proc documentRaises*(cache: IdentCache; n: PNode) =
if p5 != nil: n[pragmasPos].add p5
if p6 != nil: n[pragmasPos].add p6
proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags = kDefault) =
proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) =
## Goes through nim nodes recursively and collects doc comments.
## Main function for `doc`:option: command,
## which is implemented in ``docgen2.nim``.
template genItemAux(skind) =
genItem(d, n, n[namePos], skind, docFlags)
let showNonExports = optShowNonExportedFields in config.globalOptions
case n.kind
of nkPragma:
let pragmaNode = findPragma(n, wDeprecated)
@@ -1347,20 +1311,20 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags
if n[i].kind != nkCommentStmt:
# order is always 'type var let const':
genItem(d, n[i], n[i][0],
succ(skType, ord(n.kind)-ord(nkTypeSection)), docFlags, showNonExports)
succ(skType, ord(n.kind)-ord(nkTypeSection)), docFlags)
of nkStmtList:
for i in 0..<n.len: generateDoc(d, n[i], orig, config)
for i in 0..<n.len: generateDoc(d, n[i], orig)
of nkWhenStmt:
# generate documentation for the first branch only:
if not checkForFalse(n[0][0]):
generateDoc(d, lastSon(n[0]), orig, config)
generateDoc(d, lastSon(n[0]), orig)
of nkImportStmt:
for it in n: traceDeps(d, it)
of nkExportStmt:
for it in n:
if it.kind == nkSym:
if d.module != nil and d.module == it.sym.owner:
generateDoc(d, it.sym.ast, orig, config, kForceExport)
generateDoc(d, it.sym.ast, orig, kForceExport)
elif it.sym.ast != nil:
exportSym(d, it.sym)
of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept"
@@ -1373,31 +1337,9 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags
proc overloadGroupName(s: string, k: TSymKind): string =
## Turns a name like `f` into anchor `f-procs-all`
#s & " " & k.toHumanStr & "s all"
s & "-" & k.toHumanStr & "s-all"
proc setIndexTitle(d: PDoc, useMetaTitle: bool) =
let titleKind = if d.standaloneDoc: ieMarkupTitle else: ieNimTitle
let external = AbsoluteFile(d.destFile)
.relativeTo(d.conf.outDir, '/')
.changeFileExt(HtmlExt)
.string
var term, linkTitle: string
if useMetaTitle and d.meta[metaTitle].len != 0:
term = d.meta[metaTitleRaw]
linkTitle = d.meta[metaTitleRaw]
else:
let filename = extractFilename(d.filename)
term =
if d.standaloneDoc: filename # keep .rst/.md extension
else: changeFileExt(filename, "") # rm .nim extension
linkTitle =
if d.standaloneDoc: term # keep .rst/.md extension
else: canonicalImport(d.conf, AbsoluteFile d.filename)
if not d.standaloneDoc:
linkTitle = "module " & linkTitle
setIndexTerm(d[], titleKind, htmlFile = external, id = "",
term = term, linkTitle = linkTitle)
proc finishGenerateDoc*(d: var PDoc) =
## Perform 2nd RST pass for resolution of links/footnotes/headings...
# copy file map `filenames` to ``rstgen.nim`` for its warnings
@@ -1410,24 +1352,7 @@ proc finishGenerateDoc*(d: var PDoc) =
firstRst = fragment.rst
break
d.hasToc = d.hasToc or d.sharedState.hasToc
# in --index:only mode we do NOT want to load other .idx, only write ours:
let importdoc = optGenIndexOnly notin d.conf.globalOptions and
optNoImportdoc notin d.conf.globalOptions
preparePass2(d.sharedState, firstRst, importdoc)
if optGenIndexOnly in d.conf.globalOptions:
# Top-level doc.comments may contain titles and :idx: statements:
for fragment in d.modDescPre:
if fragment.isRst:
traverseForIndex(d[], fragment.rst)
setIndexTitle(d, useMetaTitle = d.standaloneDoc)
# Symbol-associated doc.comments may contain :idx: statements:
for k in TSymKind:
for _, overloadChoices in d.section[k].secItems:
for item in overloadChoices:
for fragment in item.descRst:
if fragment.isRst:
traverseForIndex(d[], fragment.rst)
preparePass2(d.sharedState, firstRst)
# add anchors to overload groups before RST resolution
for k in TSymKind:
@@ -1437,25 +1362,14 @@ proc finishGenerateDoc*(d: var PDoc) =
let refn = overloadGroupName(plainName, k)
let tooltip = "$1 ($2 overloads)" % [
k.toHumanStr & " " & plainName, $overloadChoices.len]
let name = nimIdentBackticksNormalize(plainName)
# save overload group to ``.idx``
let external = d.destFile.AbsoluteFile.relativeTo(d.conf.outDir, '/').
changeFileExt(HtmlExt).string
setIndexTerm(d[], ieNimGroup, htmlFile = external, id = refn,
term = name, linkTitle = k.toHumanStr,
linkDesc = "", line = overloadChoices[0].info.line.int)
if optGenIndexOnly in d.conf.globalOptions: continue
addAnchorNim(d.sharedState, external=false, refn, tooltip,
addAnchorNim(d.sharedState, refn, tooltip,
LangSymbol(symKind: k.toHumanStr,
name: name,
name: nimIdentBackticksNormalize(plainName),
isGroup: true),
priority = symbolPriority(k),
# select index `0` just to have any meaningful warning:
info = overloadChoices[0].info)
if optGenIndexOnly in d.conf.globalOptions:
return
# Finalize fragments of ``.nim`` or ``.rst`` file
proc renderItemPre(d: PDoc, fragments: ItemPre, result: var string) =
for f in fragments:
@@ -1507,9 +1421,6 @@ proc finishGenerateDoc*(d: var PDoc) =
d.jEntriesFinal.add entry.json # generates docs
setIndexTitle(d, useMetaTitle = d.standaloneDoc)
completePass2(d.sharedState)
proc add(d: PDoc; j: JsonItem) =
if j.json != nil or j.rst != nil: d.jEntriesPre.add j
@@ -1556,7 +1467,7 @@ proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) =
else: discard
proc genTagsItem(d: PDoc, n, nameNode: PNode, k: TSymKind): string =
result = getNameEsc(d, nameNode) & "\n"
result = getName(d, nameNode) & "\n"
proc generateTags*(d: PDoc, n: PNode, r: var string) =
case n.kind
@@ -1663,7 +1574,13 @@ proc genOutFile(d: PDoc, groupedToc = false): string =
# Extract the title. Non API modules generate an entry in the index table.
if d.meta[metaTitle].len != 0:
title = d.meta[metaTitle]
let external = AbsoluteFile(d.destFile)
.relativeTo(d.conf.outDir, '/')
.changeFileExt(HtmlExt)
.string
setIndexTerm(d[], external, "", title)
else:
# Modules get an automatic title for the HTML, but no entry in the index.
title = canonicalImport(d.conf, AbsoluteFile d.filename)
title = esc(d.target, title)
var subtitle = ""
@@ -1702,17 +1619,11 @@ proc genOutFile(d: PDoc, groupedToc = false): string =
code = content
result = code
proc indexFile(d: PDoc): AbsoluteFile =
let dir = d.conf.outDir
result = dir / changeFileExt(presentationPath(d.conf,
AbsoluteFile d.filename),
IndexExt)
let (finalDir, _, _) = result.string.splitFile
createDir(finalDir)
proc generateIndex*(d: PDoc) =
if optGenIndex in d.conf.globalOptions:
let dest = indexFile(d)
let dir = d.conf.outDir
createDir(dir)
let dest = dir / changeFileExt(presentationPath(d.conf, AbsoluteFile d.filename), IndexExt)
writeIndexFile(d[], dest.string)
proc updateOutfile(d: PDoc, outfile: AbsoluteFile) =
@@ -1723,9 +1634,6 @@ proc updateOutfile(d: PDoc, outfile: AbsoluteFile) =
d.conf.outFile = splitPath(d.conf.outFile.string)[1].RelativeFile
proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) =
if optGenIndexOnly in d.conf.globalOptions:
d.conf.outFile = indexFile(d).relativeTo(d.conf.outDir) # just for display
return
runAllExamples(d)
var content = genOutFile(d, groupedToc)
if optStdout in d.conf.globalOptions:
@@ -1790,7 +1698,7 @@ proc commandDoc*(cache: IdentCache, conf: ConfigRef) =
var ast = parseFile(conf.projectMainIdx, cache, conf)
if ast == nil: return
var d = newDocumentor(conf.projectFull, cache, conf, hasToc = true)
generateDoc(d, ast, ast, conf)
generateDoc(d, ast, ast)
finishGenerateDoc(d)
writeOutput(d)
generateIndex(d)
@@ -1838,7 +1746,7 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) =
let filename = getOutFile(conf, RelativeFile conf.projectName, JsonExt)
try:
writeFile(filename, content)
except IOError:
except:
rawMessage(conf, errCannotOpenFile, filename.string)
proc commandTags*(cache: IdentCache, conf: ConfigRef) =
@@ -1860,12 +1768,10 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) =
let filename = getOutFile(conf, RelativeFile conf.projectName, TagsExt)
try:
writeFile(filename, content)
except IOError:
except:
rawMessage(conf, errCannotOpenFile, filename.string)
proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") =
if optGenIndexOnly in conf.globalOptions:
return
var content = mergeIndexes(dir)
var outFile = outFile
@@ -1883,7 +1789,7 @@ proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"")
try:
writeFile(filename, code)
except IOError:
except:
rawMessage(conf, errCannotOpenFile, filename.string)
proc commandBuildIndexJson*(conf: ConfigRef, dir: string, outFile = RelativeFile"") =
@@ -1897,5 +1803,5 @@ proc commandBuildIndexJson*(conf: ConfigRef, dir: string, outFile = RelativeFile
try:
writeFile(filename, $body)
except IOError:
except:
rawMessage(conf, errCannotOpenFile, filename.string)

View File

@@ -11,7 +11,7 @@
# semantic checking.
import
options, ast, msgs, docgen, lineinfos, pathutils, packages
options, ast, msgs, passes, docgen, lineinfos, pathutils, packages
from modulegraphs import ModuleGraph, PPassContext
@@ -38,21 +38,21 @@ template closeImpl(body: untyped) {.dirty.} =
except IOError:
discard
proc closeDoc*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl:
writeOutput(g.doc, useWarning, groupedToc)
proc closeJson*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl:
writeOutputJson(g.doc, useWarning)
proc processNode*(c: PPassContext, n: PNode): PNode =
proc processNode(c: PPassContext, n: PNode): PNode =
result = n
var g = PGen(c)
if shouldProcess(g):
generateDoc(g.doc, n, n, g.config)
generateDoc(g.doc, n, n)
proc processNodeJson*(c: PPassContext, n: PNode): PNode =
proc processNodeJson(c: PPassContext, n: PNode): PNode =
result = n
var g = PGen(c)
if shouldProcess(g):
@@ -68,11 +68,20 @@ template myOpenImpl(ext: untyped) {.dirty.} =
g.doc = d
result = g
proc openHtml*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
myOpenImpl(HtmlExt)
proc openTex*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
proc myOpenTex(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
myOpenImpl(TexExt)
proc openJson*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
proc myOpenJson(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
myOpenImpl(JsonExt)
const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
const docgen2TexPass* = makePass(open = myOpenTex, process = processNode,
close = close)
const docgen2JsonPass* = makePass(open = myOpenJson, process = processNodeJson,
close = closeJson)
proc finishDoc2Pass*(project: string) =
discard

View File

@@ -77,7 +77,7 @@ proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode =
theAddr = dllhandle.symAddr(name.cstring)
if theAddr.isNil: globalError(conf, sym.info,
"cannot import symbol: " & name & " from " & libPathMsg)
result.intVal = cast[int](theAddr)
result.intVal = cast[ByteAddress](theAddr)
proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type =
if t == nil: return addr libffi.type_void
@@ -113,7 +113,7 @@ proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI
template rd(typ, p: untyped): untyped = (cast[ptr typ](p))[]
template wr(typ, p, v: untyped): untyped = (cast[ptr typ](p))[] = v
template `+!`(x, y: untyped): untyped =
cast[pointer](cast[int](x) + y)
cast[pointer](cast[ByteAddress](x) + y)
proc packSize(conf: ConfigRef, v: PNode, typ: PType): int =
## computes the size of the blob
@@ -369,13 +369,13 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
# in their unboxed representation so nothing it to be unpacked:
result = n
else:
awi(nkPtrLit, cast[int](p))
awi(nkPtrLit, cast[ByteAddress](p))
of tyPtr, tyRef, tyVar, tyLent:
let p = rd(pointer, x)
if p.isNil:
setNil()
elif n == nil or n.kind == nkPtrLit:
awi(nkPtrLit, cast[int](p))
awi(nkPtrLit, cast[ByteAddress](p))
elif n != nil and n.len == 1:
internalAssert(conf, n.kind == nkRefTy)
n[0] = unpack(conf, p, typ.lastSon, n[0])

View File

@@ -328,9 +328,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
platform.OS[conf.target.targetOS].name & '.' &
CC[c].name & fullSuffix
result = getConfigVar(conf, fullCCname)
if existsConfigVar(conf, fullCCname):
result = getConfigVar(conf, fullCCname)
else:
if result.len == 0:
# not overridden for this cross compilation setting?
result = getConfigVar(conf, CC[c].name & fullSuffix)
else:
@@ -530,7 +528,7 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool =
var exe = getConfigVar(conf, conf.cCompiler, ".exe")
if exe.len == 0: exe = CC[conf.cCompiler].compilerExe
# NOTE: should we need the full version, use -dumpfullversion
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except IOError, OSError, ValueError: ("", 1)
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except: ("", 1)
if exitCode == 0:
var major: int
discard parseInt(s, major)
@@ -836,15 +834,6 @@ proc linkViaResponseFile(conf: ConfigRef; cmd: string) =
finally:
removeFile(linkerArgs)
proc linkViaShellScript(conf: ConfigRef; cmd: string) =
let linkerScript = conf.projectName & "_" & "linkerScript.sh"
writeFile(linkerScript, cmd)
let shell = getEnv("SHELL")
try:
execLinkCmd(conf, shell & " " & linkerScript)
finally:
removeFile(linkerScript)
proc getObjFilePath(conf: ConfigRef, f: Cfile): string =
if noAbsolutePaths(conf): f.obj.extractFilename
else: f.obj.string
@@ -862,20 +851,6 @@ proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string =
else:
result = MsgKindToStr[hintCC] % demangleModuleName(path.splitFile.name)
proc preventLinkCmdMaxCmdLen(conf: ConfigRef, linkCmd: string) =
# Prevent linkcmd from exceeding the maximum command line length.
# Windows's command line limit is about 8K (8191 characters) so C compilers on
# Windows support a feature where the command line can be passed via ``@linkcmd``
# to them.
const MaxCmdLen = when defined(windows): 8_000 elif defined(macosx): 260_000 else: 32_000
if linkCmd.len > MaxCmdLen:
when defined(macosx):
linkViaShellScript(conf, linkCmd)
else:
linkViaResponseFile(conf, linkCmd)
else:
execLinkCmd(conf, linkCmd)
proc callCCompiler*(conf: ConfigRef) =
var
linkCmd: string
@@ -952,7 +927,14 @@ proc callCCompiler*(conf: ConfigRef) =
linkCmd = getLinkCmd(conf, mainOutput, objfiles, removeStaticFile = true)
extraCmds = getExtraCmds(conf, mainOutput)
if optCompileOnly notin conf.globalOptions:
preventLinkCmdMaxCmdLen(conf, linkCmd)
const MaxCmdLen = when defined(windows): 8_000 else: 32_000
if linkCmd.len > MaxCmdLen:
# Windows's command line limit is about 8K (don't laugh...) so C compilers on
# Windows support a feature where the command line can be passed via ``@linkcmd``
# to them.
linkViaResponseFile(conf, linkCmd)
else:
execLinkCmd(conf, linkCmd)
for cmd in extraCmds:
execExternalProgram(conf, cmd, hintExecuting)
else:
@@ -1036,7 +1018,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
var bcache: BuildCache
try: bcache.fromJson(jsonFile.string.parseFile)
except ValueError, KeyError, JsonKindError:
except:
let e = getCurrentException()
conf.quitOrRaise "\ncaught exception:\n$#\nstacktrace:\n$#error evaluating JSON file: $#" %
[e.msg, e.getStackTrace(), jsonFile.string]
@@ -1053,7 +1035,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
cmds.add cmd
prettyCmds.add displayProgressCC(conf, name, cmd)
execCmdsInParallel(conf, cmds, prettyCb)
preventLinkCmdMaxCmdLen(conf, bcache.linkcmd)
execLinkCmd(conf, bcache.linkcmd)
for cmd in bcache.extraCmds: execExternalProgram(conf, cmd, hintExecuting)
proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope =

View File

@@ -17,12 +17,12 @@ import
intsets, strtabs, ast, astalgo, msgs, renderer, magicsys, types, idents,
strutils, options, lowerings, tables, modulegraphs,
lineinfos, parampatterns, sighashes, liftdestructors, optimizer,
varpartitions, aliasanalysis, dfa, wordrecg
varpartitions, aliasanalysis, dfa
when defined(nimPreviewSlimSystem):
import std/assertions
from trees import exprStructuralEquivalent, getRoot, whichPragma
from trees import exprStructuralEquivalent, getRoot
type
Con = object
@@ -35,7 +35,6 @@ type
idgen: IdGenerator
body: PNode
otherUsage: TLineInfo
inUncheckedAssignSection: int
Scope = object # we do scope-based memory management.
# a scope is comparable to an nkStmtListExpr like
@@ -218,7 +217,7 @@ proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode
var op = getAttachedOp(c.graph, t, kind)
if op == nil or op.ast.isGenericRoutine:
# give up and find the canonical type instead:
let h = sighashes.hashType(t, c.graph.config, {CoType, CoConsiderOwned, CoDistinct})
let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct})
let canon = c.graph.canonTypes.getOrDefault(h)
if canon != nil:
op = getAttachedOp(c.graph, canon, kind)
@@ -343,31 +342,23 @@ It is best to factor out piece of object that needs custom destructor into separ
return
# generate: if le != tmp: `=destroy`(le)
if c.inUncheckedAssignSection != 0:
let branchDestructor = produceDestructorForDiscriminator(c.graph, objType, leDotExpr[1].sym, n.info, c.idgen)
let cond = newNodeIT(nkInfix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
cond.add newSymNode(getMagicEqSymForType(c.graph, le.typ, n.info))
cond.add le
cond.add tmp
let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
notExpr.add newSymNode(createMagic(c.graph, c.idgen, "not", mNot))
notExpr.add cond
result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, c.genOp(branchDestructor, le)))
let branchDestructor = produceDestructorForDiscriminator(c.graph, objType, leDotExpr[1].sym, n.info, c.idgen)
let cond = newNodeIT(nkInfix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
cond.add newSymNode(getMagicEqSymForType(c.graph, le.typ, n.info))
cond.add le
cond.add tmp
let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
notExpr.add newSymNode(createMagic(c.graph, c.idgen, "not", mNot))
notExpr.add cond
result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, c.genOp(branchDestructor, le)))
result.add newTree(nkFastAsgn, le, tmp)
proc genWasMoved(c: var Con, n: PNode): PNode =
let typ = n.typ.skipTypes({tyGenericInst, tyAlias, tySink})
let op = getAttachedOp(c.graph, n.typ, attachedWasMoved)
if op != nil:
if sfError in op.flags:
c.checkForErrorPragma(n.typ, n, "=wasMoved")
result = genOp(c, op, n)
else:
result = newNodeI(nkCall, n.info)
result.add(newSymNode(createMagic(c.graph, c.idgen, "wasMoved", mWasMoved)))
result.add copyTree(n) #mWasMoved does not take the address
#if n.kind != nkSym:
# message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")")
result = newNodeI(nkCall, n.info)
result.add(newSymNode(createMagic(c.graph, c.idgen, "wasMoved", mWasMoved)))
result.add copyTree(n) #mWasMoved does not take the address
#if n.kind != nkSym:
# message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")")
proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
result = newNodeI(nkCall, info)
@@ -879,7 +870,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
result = n
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange:
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock:
result = shallowCopy(n)
for i in 0 ..< n.len:
result[i] = p(n[i], c, s, normal)
@@ -887,25 +878,6 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if mode == normal:
result = ensureDestruction(result, n, c, s)
of nkPragmaBlock:
var inUncheckedAssignSection = 0
let pragmaList = n[0]
for pi in pragmaList:
if whichPragma(pi) == wCast:
case whichPragma(pi[1])
of wUncheckedAssign:
inUncheckedAssignSection = 1
else:
discard
result = shallowCopy(n)
inc c.inUncheckedAssignSection, inUncheckedAssignSection
for i in 0 ..< n.len:
result[i] = p(n[i], c, s, normal)
dec c.inUncheckedAssignSection, inUncheckedAssignSection
if n.typ != nil and hasDestructor(c, n.typ):
if mode == normal:
result = ensureDestruction(result, n, c, s)
of nkHiddenSubConv, nkHiddenStdConv, nkConv:
# we have an "ownership invariance" for all constructors C(x).
# See the comment for nkBracket construction. If the caller wants

View File

@@ -65,12 +65,11 @@ Files: "compiler"
Files: "doc"
Files: "doc/html"
Files: "tools"
Files: "tools/debug/nim-gdb.py"
Files: "tools/nim-gdb.py"
Files: "nimpretty"
Files: "testament"
Files: "nimsuggest"
Files: "nimsuggest/tests/*.nim"
Files: "changelogs/*.md"
[Lib]
Files: "lib"
@@ -121,7 +120,6 @@ Files: "bin/nim"
InstallScript: "yes"
UninstallScript: "yes"
Files: "bin/nim-gdb"
Files: "build_all.sh"
[InnoSetup]

View File

@@ -33,27 +33,26 @@ template high*(t: typedesc[Int128]): Int128 = Max
proc `$`*(a: Int128): string
proc toInt128*[T: SomeInteger | bool](arg: T): Int128 =
{.noSideEffect.}:
when T is bool: result.sdata(0) = int32(arg)
elif T is SomeUnsignedInt:
when sizeof(arg) <= 4:
result.udata[0] = uint32(arg)
else:
result.udata[0] = uint32(arg and T(0xffffffff))
result.udata[1] = uint32(arg shr 32)
elif sizeof(arg) <= 4:
result.sdata(0) = int32(arg)
if arg < 0: # sign extend
result.sdata(1) = -1
result.sdata(2) = -1
result.sdata(3) = -1
when T is bool: result.sdata(0) = int32(arg)
elif T is SomeUnsignedInt:
when sizeof(arg) <= 4:
result.udata[0] = uint32(arg)
else:
let tmp = int64(arg)
result.udata[0] = uint32(tmp and 0xffffffff)
result.sdata(1) = int32(tmp shr 32)
if arg < 0: # sign extend
result.sdata(2) = -1
result.sdata(3) = -1
result.udata[0] = uint32(arg and T(0xffffffff))
result.udata[1] = uint32(arg shr 32)
elif sizeof(arg) <= 4:
result.sdata(0) = int32(arg)
if arg < 0: # sign extend
result.sdata(1) = -1
result.sdata(2) = -1
result.sdata(3) = -1
else:
let tmp = int64(arg)
result.udata[0] = uint32(tmp and 0xffffffff)
result.sdata(1) = int32(tmp shr 32)
if arg < 0: # sign extend
result.sdata(2) = -1
result.sdata(3) = -1
template isNegative(arg: Int128): bool =
arg.sdata(3) < 0

View File

@@ -31,11 +31,9 @@ implements the required case distinction.
import
ast, trees, magicsys, options,
nversion, msgs, idents, types,
ropes, ccgutils, wordrecg, renderer,
ropes, passes, ccgutils, wordrecg, renderer,
cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
transf, injectdestructors, sourcemap, astmsgs, backendpragmas
import pipelineutils
transf, injectdestructors, sourcemap, astmsgs
import json, sets, math, tables, intsets
import strutils except addf
@@ -100,7 +98,6 @@ type
prc: PSym
globals, locals, body: Rope
options: TOptions
optionsStack: seq[TOptions]
module: BModule
g: PGlobals
generatedParamCopies: IntSet
@@ -264,7 +261,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
if m.config.hcrOn:
# When hot reloading is enabled, we must ensure that the names
# of functions and types will be preserved across rebuilds:
result.add(idOrSig(s, m.module.name.s, m.sigConflicts, m.config))
result.add(idOrSig(s, m.module.name.s, m.sigConflicts))
else:
result.add("_")
result.add(rope(s.id))
@@ -735,8 +732,6 @@ proc genLineDir(p: PProc, n: PNode) =
let line = toLinenumber(n.info)
if line < 0:
return
if optEmbedOrigSrc in p.config.globalOptions:
lineF(p, "//$1$n", [sourceLine(p.config, n.info)])
if optLineDir in p.options or optLineDir in p.config.options:
lineF(p, "$1", [lineDir(p.config, n.info, line)])
if hasFrameInfo(p):
@@ -2489,18 +2484,17 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
if prc.typ[0] != nil and sfPure notin prc.flags:
resultSym = prc.ast[resultPos].sym
let mname = mangleName(p.module, resultSym)
# otherwise uses "fat pointers"
let useRawPointer = not isIndirect(resultSym) and
let returnAddress = not isIndirect(resultSym) and
resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and
mapType(p, resultSym.typ) == etyBaseIndex
if useRawPointer:
if returnAddress:
resultAsgn = p.indentLine(("var $# = null;$n") % [mname])
resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
else:
let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar])
gen(p, prc.ast[resultPos], a)
if mapType(p, resultSym.typ) == etyBaseIndex:
if returnAddress:
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
else:
returnStmt = "return $#;$n" % [a.res]
@@ -2562,14 +2556,9 @@ proc genStmt(p: PProc, n: PNode) =
if r.res != "": lineF(p, "$#;$n", [r.res])
proc genPragma(p: PProc, n: PNode) =
for i in 0..<n.len:
let it = n[i]
for it in n.sons:
case whichPragma(it)
of wEmit: genAsmOrEmitStmt(p, it[1])
of wPush:
processPushBackendOption(p.optionsStack, p.options, n, i+1)
of wPop:
processPopBackendOption(p.optionsStack, p.options)
else: discard
proc genCast(p: PProc, n: PNode, r: var TCompRes) =
@@ -2817,7 +2806,7 @@ proc genModule(p: PProc, n: PNode) =
if p.config.hcrOn and n.kind == nkStmtList:
let moduleSym = p.module.module
var moduleLoadedVar = rope(moduleSym.name.s) & "_loaded" &
idOrSig(moduleSym, moduleSym.name.s, p.module.sigConflicts, p.config)
idOrSig(moduleSym, moduleSym.name.s, p.module.sigConflicts)
lineF(p, "var $1;$n", [moduleLoadedVar])
var inGuardedBlock = false
@@ -2834,11 +2823,11 @@ proc genModule(p: PProc, n: PNode) =
if optStackTrace in p.options:
p.body.add(frameDestroy(p))
proc processJSCodeGen*(b: PPassContext, n: PNode): PNode =
proc myProcess(b: PPassContext, n: PNode): PNode =
## Generate JS code for a node.
result = n
let m = BModule(b)
if pipelineutils.skipCodegen(m.config, n): return n
if passes.skipCodegen(m.config, n): return n
if m.module == nil: internalError(m.config, n.info, "myProcess")
let globals = PGlobals(m.graph.backend)
var p = newInitProc(globals, m)
@@ -2873,7 +2862,7 @@ proc getClassName(t: PType): Rope =
if s.loc.r != "": result = s.loc.r
else: result = rope(s.name.s)
proc finalJSCodeGen*(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
## Finalize JS code generation of a Nim module.
## Param `n` may contain nodes returned from the last module close call.
var m = BModule(b)
@@ -2883,14 +2872,14 @@ proc finalJSCodeGen*(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
for i in countdown(high(graph.globalDestructors), 0):
n.add graph.globalDestructors[i]
# Process any nodes left over from the last call to `myClose`.
result = processJSCodeGen(b, n)
result = myProcess(b, n)
# Some codegen is different (such as no stacktraces; see `initProcOptions`)
# when `std/system` is being processed.
if sfSystemModule in m.module.flags:
PGlobals(graph.backend).inSystem = false
# Check if codegen should continue before any files are generated.
# It may bail early is if too many errors have been raised.
if pipelineutils.skipCodegen(m.config, n): return n
if passes.skipCodegen(m.config, n): return n
# Nim modules are compiled into a single JS file.
# If this is the main module, then this is the final call to `myClose`.
if sfMainModule in m.module.flags:
@@ -2908,6 +2897,9 @@ proc finalJSCodeGen*(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
if not writeRope(code, outFile):
rawMessage(m.config, errCannotOpenFile, outFile.string)
proc setupJSgen*(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext =
proc myOpen(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext =
## Create the JS backend pass context `BModule` for a Nim module.
result = newModule(graph, s)
result.idgen = idgen
const JSgenPass* = makePass(myOpen, myProcess, myClose)

View File

@@ -133,7 +133,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
[result, rope(ord(t.kind))]
prepend(p.g.typeInfo, s)
of tyVar, tyLent, tyRef, tyPtr, tySequence, tyRange, tySet, tyOpenArray:
of tyVar, tyLent, tyRef, tyPtr, tySequence, tyRange, tySet:
var s =
"var $1 = {size: 0, kind: $2, base: null, node: null, finalizer: null};$n" %
[result, rope(ord(t.kind))]

View File

@@ -859,7 +859,7 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType;
fn.typ.callConv = oldCC
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
idgen: IdGenerator, force: bool): PNode =
idgen: IdGenerator): PNode =
# XXX backend == backendJs does not suffice! The compiletime stuff needs
# the transformation even when compiling to JS ...
@@ -868,7 +868,7 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
if body.kind == nkEmpty or (
g.config.backend == backendJs and not isCompileTime) or
(fn.skipGenericOwner.kind != skModule and not force):
fn.skipGenericOwner.kind != skModule:
# ignore forward declaration:
result = body

View File

@@ -127,8 +127,6 @@ type
cache*: IdentCache
when defined(nimsuggest):
previousToken: TLineInfo
tokenEnd*: TLineInfo
previousTokenEnd*: TLineInfo
config*: ConfigRef
proc getLineInfo*(L: Lexer, tok: Token): TLineInfo {.inline.} =
@@ -1226,10 +1224,6 @@ proc skip(L: var Lexer, tok: var Token) =
proc rawGetTok*(L: var Lexer, tok: var Token) =
template atTokenEnd() {.dirty.} =
when defined(nimsuggest):
L.previousTokenEnd.line = L.tokenEnd.line
L.previousTokenEnd.col = L.tokenEnd.col
L.tokenEnd.line = tok.line.uint16
L.tokenEnd.col = getColNumber(L, L.bufpos).int16
# we attach the cursor to the last *strong* token
if tok.tokType notin weakTokens:
L.previousToken.line = tok.line.uint16

View File

@@ -8,7 +8,7 @@
#
## This module implements lifting for type-bound operations
## (``=sink``, ``=copy``, ``=destroy``, ``=deepCopy``).
## (``=sink``, ``=``, ``=destroy``, ``=deepCopy``).
import modulegraphs, lineinfos, idents, ast, renderer, semdata,
sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils
@@ -88,8 +88,6 @@ proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let call = genBuiltin(c, mDefault, "default", x)
call.typ = t
body.add newAsgnStmt(x, call)
elif c.kind == attachedWasMoved:
body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc genAddr(c: var TLiftCtx; x: PNode): PNode =
if x.kind == nkHiddenDeref:
@@ -147,11 +145,6 @@ proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
else:
result = destroy
proc genWasMovedCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
result = newNodeIT(nkCall, x.info, op.typ[0])
result.add(newSymNode(op))
result.add genAddr(c, x)
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) =
case n.kind
of nkSym:
@@ -449,20 +442,6 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
body.add newDeepCopyCall(c, op, x, y)
result = true
of attachedWasMoved:
var op = getAttachedOp(c.g, t, attachedWasMoved)
if op != nil and sfOverriden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
op = instantiateGeneric(c, op, t, t.typeInst)
setAttachedOp(c.g, c.idgen.module, t, attachedWasMoved, op)
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op)
body.add genWasMovedCall(c, op, x)
result = true
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info)
temp.typ = getSysType(c.g, body.info, tyInt)
@@ -545,7 +524,6 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if canFormAcycle(t.elemType):
# follow all elements:
forallElements(c, t, body, x, y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
createTypeBoundOps(c.g, c.c, t, body.info, c.idgen)
@@ -553,7 +531,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# operation here:
var t = t
if t.assignment == nil or t.destructor == nil:
let h = sighashes.hashType(t,c.g.config, {CoType, CoConsiderOwned, CoDistinct})
let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct})
let canon = c.g.canonTypes.getOrDefault(h)
if canon != nil: t = canon
@@ -583,7 +561,6 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if op == nil:
return # protect from recursion
body.add newHookCall(c, op, x, y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
@@ -599,7 +576,6 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genBuiltin(c, mDestroy, "destroy", x)
of attachedTrace:
discard "strings are atomic and have no inner elements that are to trace"
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc cyclicType*(t: PType): bool =
case t.kind
@@ -633,11 +609,6 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen)
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType)
let isInheritableAcyclicRef = c.g.config.selectedGC == gcOrc and
(not isPureObject(elemType)) and
tfAcyclic in skipTypes(elemType, abstractInst+{tyOwned}-{tyTypeDesc}).flags
# dynamic Acyclic refs need to use dyn decRef
let tmp =
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
declareTempOf(c, body, x)
@@ -661,8 +632,6 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo)
else:
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp)
elif isInheritableAcyclicRef:
cond = callCodegenProc(c.g, "nimDecRefIsLastDyn", c.info, x)
else:
cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x)
cond.typ = getSysType(c.g, x.info, tyBool)
@@ -698,8 +667,6 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# If the ref is polymorphic we have to account for this
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x, c.idgen), y)
#echo "can follow ", elemType, " static ", isFinal(elemType)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
## Closures are really like refs except they always use a virtual destructor
@@ -748,7 +715,6 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace:
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
@@ -773,7 +739,6 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.sons.insert(des, 0)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
var actions = newNodeI(nkStmtList, c.info)
@@ -799,7 +764,6 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, x, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if c.kind == attachedDeepCopy:
@@ -834,7 +798,6 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.sons.insert(des, 0)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
@@ -850,7 +813,6 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, xx, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case t.kind
@@ -966,7 +928,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
result.typ = newProcType(info, nextTypeId(idgen), owner)
result.typ.addParam dest
if kind notin {attachedDestructor, attachedWasMoved}:
if kind != attachedDestructor:
result.typ.addParam src
if kind == attachedAsgn and g.config.selectedGC == gcOrc and
@@ -1006,7 +968,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
let dest = result.typ.n[1].sym
let d = newDeref(newSymNode(dest))
let src = if kind in {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
let src = if kind == attachedDestructor: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
else: newSymNode(result.typ.n[2].sym)
# register this operation already:
@@ -1085,7 +1047,13 @@ proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: I
let op = getAttachedOp(g, t, kind)
if op != nil and op.ast != nil and op.ast.isGenericRoutine:
if t.typeInst != nil:
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, idgen: idgen)
var a: TLiftCtx
a.info = info
a.g = g
a.kind = kind
a.c = c
a.idgen = idgen
let opInst = instantiateGeneric(a, op, t, t.typeInst)
if opInst.ast != nil:
patchBody(g, c, opInst.ast, info, a.idgen)
@@ -1107,7 +1075,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink})
if isEmptyContainer(skipped) or skipped.kind == tyStatic: return
let h = sighashes.hashType(skipped, g.config, {CoType, CoConsiderOwned, CoDistinct})
let h = sighashes.hashType(skipped, {CoType, CoConsiderOwned, CoDistinct})
var canon = g.canonTypes.getOrDefault(h)
if canon == nil:
g.canonTypes[h] = skipped
@@ -1128,15 +1096,15 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
# bug #15122: We need to produce all prototypes before entering the
# mind boggling recursion. Hacks like these imply we should rewrite
# this module.
var generics: array[attachedWasMoved..attachedTrace, bool]
for k in attachedWasMoved..lastAttached:
var generics: array[attachedDestructor..attachedTrace, bool]
for k in attachedDestructor..lastAttached:
generics[k] = getAttachedOp(g, canon, k) != nil
if not generics[k]:
setAttachedOp(g, idgen.module, canon, k,
symPrototype(g, canon, canon.owner, k, info, idgen))
# we generate the destructor first so that other operators can depend on it:
for k in attachedWasMoved..lastAttached:
for k in attachedDestructor..lastAttached:
if not generics[k]:
discard produceSym(g, c, canon, k, info, idgen)
else:

View File

@@ -57,7 +57,6 @@ type
warnRstBrokenLink = "BrokenLink",
warnRstLanguageXNotSupported = "LanguageXNotSupported",
warnRstFieldXNotSupported = "FieldXNotSupported",
warnRstUnusedImportdoc = "UnusedImportdoc",
warnRstStyle = "warnRstStyle",
warnCommentXIgnored = "CommentXIgnored",
warnTypelessParam = "TypelessParam",
@@ -87,7 +86,6 @@ type
warnImplicitTemplateRedefinition = "ImplicitTemplateRedefinition",
warnUnnamedBreak = "UnnamedBreak",
warnStmtListLambda = "StmtListLambda",
warnBareExcept = "BareExcept",
warnUser = "User",
# hints
hintSuccess = "Success", hintSuccessX = "SuccessX",
@@ -143,7 +141,6 @@ const
warnRstBrokenLink: "broken link '$1'",
warnRstLanguageXNotSupported: "language '$1' not supported",
warnRstFieldXNotSupported: "field '$1' not supported",
warnRstUnusedImportdoc: "importdoc for '$1' is not used",
warnRstStyle: "RST style: $1",
warnCommentXIgnored: "comment '$1' ignored",
warnTypelessParam: "", # deadcode
@@ -188,7 +185,6 @@ const
warnImplicitTemplateRedefinition: "template '$1' is implicitly redefined; this is deprecated, add an explicit .redefine pragma",
warnUnnamedBreak: "Using an unnamed break in a block is deprecated; Use a named block with a named break instead",
warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead",
warnBareExcept: "$1",
warnUser: "$1",
hintSuccess: "operation successful: $#",
# keep in sync with `testament.isSuccess`

View File

@@ -15,7 +15,7 @@ when defined(nimPreviewSlimSystem):
import
intsets, ast, astalgo, idents, semdata, types, msgs, options,
renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs, sets
renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
@@ -170,7 +170,6 @@ iterator allSyms*(c: PContext): (PSym, int, bool) =
# really iterate over all symbols in all the scopes. This is expensive
# and only used by suggest.nim.
var isLocal = true
var scopeN = 0
for scope in allScopes(c.currentScope):
if scope == c.topLevelScope: isLocal = false
@@ -185,17 +184,6 @@ iterator allSyms*(c: PContext): (PSym, int, bool) =
assert s != nil
yield (s, scopeN, isLocal)
iterator uniqueSyms*(c: PContext): (PSym, int, bool) =
## Like [allSyms] except only returns unique symbols (Uniqueness determined by line + name)
# Track seen symbols so we don't duplicate them.
# The int is for the symbols name, and line info is
# to be able to tell apart symbols with same name but on different lines
var seen = initHashSet[(TLineInfo, int)]()
for res in allSyms(c):
if not seen.containsOrIncl((res[0].info, res[0].name.id)):
yield res
proc someSymFromImportTable*(c: PContext; name: PIdent; ambiguous: var bool): PSym =
var marked = initIntSet()
var symSet = OverloadableSyms
@@ -228,23 +216,6 @@ proc debugScopes*(c: PContext; limit=0, max = int.high) {.deprecated.} =
if i == limit: return
inc i
proc searchInScopesAllCandidatesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
result = @[]
for scope in allScopes(c.currentScope):
var ti: TIdentIter
var candidate = initIdentIter(ti, scope.symbols, s)
while candidate != nil:
if candidate.kind in filter:
result.add candidate
candidate = nextIdentIter(ti, scope.symbols)
if result.len == 0:
var marked = initIntSet()
for im in c.imports.mitems:
for s in symbols(im, marked, s, c.graph):
if s.kind in filter:
result.add s
proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
result = @[]
block outer:
@@ -340,11 +311,9 @@ proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string;
# xxx pending bootstrap >= 1.4, replace all those overloads with a single one:
# proc addDecl*(c: PContext, sym: PSym, info = sym.info, scope = c.currentScope) {.inline.} =
proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) =
if sym.name.s == "_": return
let conflict = scope.addUniqueSym(sym)
if conflict != nil:
if sym.kind == skModule and conflict.kind == skModule and
sym.position == conflict.position:
if sym.kind == skModule and conflict.kind == skModule and sym.owner == conflict.owner:
# e.g.: import foo; import foo
# xxx we could refine this by issuing a different hint for the case
# where a duplicate import happens inside an include.
@@ -476,13 +445,12 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) =
let dist = editDistance(name0, sym.name.s.nimIdentNormalize)
var msg: string
msg.add "\n ($1, $2): '$3'" % [$dist, $depth, sym.name.s]
addDeclaredLoc(msg, c.config, sym) # `msg` needed for deterministic ordering.
list.push SpellCandidate(dist: dist, depth: depth, msg: msg, sym: sym)
if list.len == 0: return
let e0 = list[0]
var
count = 0
last: PIdent = nil
var count = 0
while true:
# pending https://github.com/timotheecour/Nim/issues/373 use more efficient `itemsSorted`.
if list.len == 0: break
@@ -498,10 +466,8 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) =
elif count >= c.config.spellSuggestMax: break
if count == 0:
result.add "\ncandidates (edit distance, scope distance); see '--spellSuggest': "
if e.sym.name != last:
result.add e.msg
count.inc
last = e.sym.name
result.add e.msg
count.inc
proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PSym =
var err = "ambiguous identifier: '" & s.name.s & "'"

View File

@@ -16,9 +16,9 @@ import
std/[strutils, os, times, tables, sha1, with, json],
llstream, ast, lexer, syntaxes, options, msgs,
condsyms,
idents, extccomp,
sem, idents, passes, extccomp,
cgen, nversion,
platform, nimconf, depends,
platform, nimconf, passaux, depends, vm,
modules,
modulegraphs, lineinfos, pathutils, vmprofiler
@@ -29,10 +29,12 @@ when defined(nimPreviewSlimSystem):
import ic / [cbackend, integrity, navigator]
from ic / ic import rodViewer
import pipelines
when not defined(leanCompiler):
import docgen
import jsgen, docgen, docgen2
proc semanticPasses(g: ModuleGraph) =
registerPass g, verbosePass
registerPass g, semPass
proc writeDepsFile(g: ModuleGraph) =
let fname = g.config.nimcacheDir / RelativeFile(g.config.projectName & ".deps")
@@ -66,18 +68,12 @@ proc writeCMakeDepsFile(conf: ConfigRef) =
fl.close()
proc commandGenDepend(graph: ModuleGraph) =
setPipeLinePass(graph, GenDependPass)
compilePipelineProject(graph)
semanticPasses(graph)
registerPass(graph, gendependPass)
compileProject(graph)
let project = graph.config.projectFull
writeDepsFile(graph)
generateDot(graph, project)
# dot in graphivz tool kit is required
let graphvizDotPath = findExe("dot")
if graphvizDotPath.len == 0:
quit("gendepend: Graphviz's tool dot is required," &
"see https://graphviz.org/download for downloading")
execExternalProgram(graph.config, "dot -Tpng -o" &
changeFileExt(project, "png").string &
' ' & changeFileExt(project, "dot").string)
@@ -91,8 +87,8 @@ proc commandCheck(graph: ModuleGraph) =
defineSymbol(conf.symbols, "nimconfig")
elif conf.backend == backendJs:
setTarget(conf.target, osJS, cpuJS)
setPipeLinePass(graph, SemPass)
compilePipelineProject(graph)
semanticPasses(graph) # use an empty backend for semantic checking only
compileProject(graph)
if conf.symbolFiles != disabledSf:
case conf.ideCmd
@@ -106,20 +102,22 @@ when not defined(leanCompiler):
proc commandDoc2(graph: ModuleGraph; ext: string) =
handleDocOutputOptions graph.config
graph.config.setErrorMaxHighMaybe
semanticPasses(graph)
case ext:
of TexExt:
setPipeLinePass(graph, Docgen2TexPass)
of JsonExt:
setPipeLinePass(graph, Docgen2JsonPass)
of HtmlExt:
setPipeLinePass(graph, Docgen2Pass)
of TexExt: registerPass(graph, docgen2TexPass)
of JsonExt: registerPass(graph, docgen2JsonPass)
of HtmlExt: registerPass(graph, docgen2Pass)
else: doAssert false, $ext
compilePipelineProject(graph)
compileProject(graph)
finishDoc2Pass(graph.config.projectName)
proc commandCompileToC(graph: ModuleGraph) =
let conf = graph.config
extccomp.initVars(conf)
semanticPasses(graph)
if conf.symbolFiles == disabledSf:
registerPass(graph, cgenPass)
if {optRun, optForceFullMake} * conf.globalOptions == {optRun} or isDefined(conf, "nimBetterRun"):
if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile):
# nothing changed
@@ -129,11 +127,7 @@ proc commandCompileToC(graph: ModuleGraph) =
if not extccomp.ccHasSaneOverflow(conf):
conf.symbols.defineSymbol("nimEmulateOverflowChecks")
if conf.symbolFiles == disabledSf:
setPipeLinePass(graph, CgenPass)
else:
setPipeLinePass(graph, SemPass)
compilePipelineProject(graph)
compileProject(graph)
if graph.config.errorCounter > 0:
return # issue #9933
if conf.symbolFiles == disabledSf:
@@ -166,27 +160,33 @@ proc commandCompileToJS(graph: ModuleGraph) =
conf.exc = excCpp
setTarget(conf.target, osJS, cpuJS)
defineSymbol(conf.symbols, "ecmascript") # For backward compatibility
setPipeLinePass(graph, JSgenPass)
compilePipelineProject(graph)
semanticPasses(graph)
registerPass(graph, JSgenPass)
compileProject(graph)
if optGenScript in conf.globalOptions:
writeDepsFile(graph)
proc commandInteractive(graph: ModuleGraph) =
graph.config.setErrorMaxHighMaybe
proc interactivePasses(graph: ModuleGraph) =
initDefines(graph.config.symbols)
defineSymbol(graph.config.symbols, "nimscript")
# note: seems redundant with -d:nimHasLibFFI
when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
setPipeLinePass(graph, InterpreterPass)
compilePipelineSystemModule(graph)
registerPass(graph, verbosePass)
registerPass(graph, semPass)
registerPass(graph, evalPass)
proc commandInteractive(graph: ModuleGraph) =
graph.config.setErrorMaxHighMaybe
interactivePasses(graph)
compileSystemModule(graph)
if graph.config.commandArgs.len > 0:
discard graph.compilePipelineModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
discard graph.compileModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
else:
var m = graph.makeStdinModule()
incl(m.flags, sfMainModule)
var idgen = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0)
let s = llStreamOpenStdIn(onPrompt = proc() = flushDot(graph.config))
discard processPipelineModule(graph, m, idgen, s)
processModule(graph, m, idgen, s)
proc commandScan(cache: IdentCache, config: ConfigRef) =
var f = addFileExt(AbsoluteFile mainCommandArg(config), NimExt)
@@ -241,6 +241,8 @@ proc mainCommand*(graph: ModuleGraph) =
let conf = graph.config
let cache = graph.cache
# In "nim serve" scenario, each command must reset the registered passes
clearPasses(graph)
conf.lastCmdTime = epochTime()
conf.searchPaths.add(conf.libpath)

297
compiler/md5_old.nim Normal file
View File

@@ -0,0 +1,297 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# `std/md5` without VM and JavaScript support, to circumvent a bug with
# openarrays on Nim < 1.4.
when defined(nimHasStyleChecks):
{.push styleChecks: off.}
type
MD5State = array[0..3, uint32]
MD5Block = array[0..15, uint32]
MD5CBits = array[0..7, uint8]
MD5Digest* = array[0..15, uint8]
## MD5 checksum of a string, obtained with the `toMD5 proc <#toMD5,string>`_.
MD5Buffer = array[0..63, uint8]
MD5Context* {.final.} = object
state: MD5State
count: array[0..1, uint32]
buffer: MD5Buffer
const
padding: array[0..63, uint8] = [
0x80'u8, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
]
proc F(x, y, z: uint32): uint32 {.inline.} =
result = (x and y) or ((not x) and z)
proc G(x, y, z: uint32): uint32 {.inline.} =
result = (x and z) or (y and (not z))
proc H(x, y, z: uint32): uint32 {.inline.} =
result = x xor y xor z
proc I(x, y, z: uint32): uint32 {.inline.} =
result = y xor (x or (not z))
proc rot(x: var uint32, n: uint8) {.inline.} =
x = (x shl n) or (x shr (32'u32 - n))
proc FF(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
a = a + F(b, c, d) + x + ac
rot(a, s)
a = a + b
proc GG(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
a = a + G(b, c, d) + x + ac
rot(a, s)
a = a + b
proc HH(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
a = a + H(b, c, d) + x + ac
rot(a, s)
a = a + b
proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
a = a + I(b, c, d) + x + ac
rot(a, s)
a = a + b
proc encode(dest: var MD5Block, src: openArray[uint8]) =
var j = 0
for i in 0..high(dest):
dest[i] = uint32(ord(src[j])) or
uint32(ord(src[j+1])) shl 8 or
uint32(ord(src[j+2])) shl 16 or
uint32(ord(src[j+3])) shl 24
inc(j, 4)
proc decode(dest: var openArray[uint8], src: openArray[uint32]) =
var i = 0
for j in 0..high(src):
dest[i] = uint8(src[j] and 0xff'u32)
dest[i+1] = uint8(src[j] shr 8 and 0xff'u32)
dest[i+2] = uint8(src[j] shr 16 and 0xff'u32)
dest[i+3] = uint8(src[j] shr 24 and 0xff'u32)
inc(i, 4)
template slice(s: string | cstring, a, b): openArray[uint8] =
s.toOpenArrayByte(a, b)
template slice(s: openArray[uint8], a, b): openArray[uint8] =
s.toOpenArray(a, b)
proc transform(buffer: openArray[uint8], state: var MD5State) =
var
myBlock: MD5Block
encode(myBlock, buffer)
var a = state[0]
var b = state[1]
var c = state[2]
var d = state[3]
FF(a, b, c, d, myBlock[0], 7'u8, 0xD76AA478'u32)
FF(d, a, b, c, myBlock[1], 12'u8, 0xE8C7B756'u32)
FF(c, d, a, b, myBlock[2], 17'u8, 0x242070DB'u32)
FF(b, c, d, a, myBlock[3], 22'u8, 0xC1BDCEEE'u32)
FF(a, b, c, d, myBlock[4], 7'u8, 0xF57C0FAF'u32)
FF(d, a, b, c, myBlock[5], 12'u8, 0x4787C62A'u32)
FF(c, d, a, b, myBlock[6], 17'u8, 0xA8304613'u32)
FF(b, c, d, a, myBlock[7], 22'u8, 0xFD469501'u32)
FF(a, b, c, d, myBlock[8], 7'u8, 0x698098D8'u32)
FF(d, a, b, c, myBlock[9], 12'u8, 0x8B44F7AF'u32)
FF(c, d, a, b, myBlock[10], 17'u8, 0xFFFF5BB1'u32)
FF(b, c, d, a, myBlock[11], 22'u8, 0x895CD7BE'u32)
FF(a, b, c, d, myBlock[12], 7'u8, 0x6B901122'u32)
FF(d, a, b, c, myBlock[13], 12'u8, 0xFD987193'u32)
FF(c, d, a, b, myBlock[14], 17'u8, 0xA679438E'u32)
FF(b, c, d, a, myBlock[15], 22'u8, 0x49B40821'u32)
GG(a, b, c, d, myBlock[1], 5'u8, 0xF61E2562'u32)
GG(d, a, b, c, myBlock[6], 9'u8, 0xC040B340'u32)
GG(c, d, a, b, myBlock[11], 14'u8, 0x265E5A51'u32)
GG(b, c, d, a, myBlock[0], 20'u8, 0xE9B6C7AA'u32)
GG(a, b, c, d, myBlock[5], 5'u8, 0xD62F105D'u32)
GG(d, a, b, c, myBlock[10], 9'u8, 0x02441453'u32)
GG(c, d, a, b, myBlock[15], 14'u8, 0xD8A1E681'u32)
GG(b, c, d, a, myBlock[4], 20'u8, 0xE7D3FBC8'u32)
GG(a, b, c, d, myBlock[9], 5'u8, 0x21E1CDE6'u32)
GG(d, a, b, c, myBlock[14], 9'u8, 0xC33707D6'u32)
GG(c, d, a, b, myBlock[3], 14'u8, 0xF4D50D87'u32)
GG(b, c, d, a, myBlock[8], 20'u8, 0x455A14ED'u32)
GG(a, b, c, d, myBlock[13], 5'u8, 0xA9E3E905'u32)
GG(d, a, b, c, myBlock[2], 9'u8, 0xFCEFA3F8'u32)
GG(c, d, a, b, myBlock[7], 14'u8, 0x676F02D9'u32)
GG(b, c, d, a, myBlock[12], 20'u8, 0x8D2A4C8A'u32)
HH(a, b, c, d, myBlock[5], 4'u8, 0xFFFA3942'u32)
HH(d, a, b, c, myBlock[8], 11'u8, 0x8771F681'u32)
HH(c, d, a, b, myBlock[11], 16'u8, 0x6D9D6122'u32)
HH(b, c, d, a, myBlock[14], 23'u8, 0xFDE5380C'u32)
HH(a, b, c, d, myBlock[1], 4'u8, 0xA4BEEA44'u32)
HH(d, a, b, c, myBlock[4], 11'u8, 0x4BDECFA9'u32)
HH(c, d, a, b, myBlock[7], 16'u8, 0xF6BB4B60'u32)
HH(b, c, d, a, myBlock[10], 23'u8, 0xBEBFBC70'u32)
HH(a, b, c, d, myBlock[13], 4'u8, 0x289B7EC6'u32)
HH(d, a, b, c, myBlock[0], 11'u8, 0xEAA127FA'u32)
HH(c, d, a, b, myBlock[3], 16'u8, 0xD4EF3085'u32)
HH(b, c, d, a, myBlock[6], 23'u8, 0x04881D05'u32)
HH(a, b, c, d, myBlock[9], 4'u8, 0xD9D4D039'u32)
HH(d, a, b, c, myBlock[12], 11'u8, 0xE6DB99E5'u32)
HH(c, d, a, b, myBlock[15], 16'u8, 0x1FA27CF8'u32)
HH(b, c, d, a, myBlock[2], 23'u8, 0xC4AC5665'u32)
II(a, b, c, d, myBlock[0], 6'u8, 0xF4292244'u32)
II(d, a, b, c, myBlock[7], 10'u8, 0x432AFF97'u32)
II(c, d, a, b, myBlock[14], 15'u8, 0xAB9423A7'u32)
II(b, c, d, a, myBlock[5], 21'u8, 0xFC93A039'u32)
II(a, b, c, d, myBlock[12], 6'u8, 0x655B59C3'u32)
II(d, a, b, c, myBlock[3], 10'u8, 0x8F0CCC92'u32)
II(c, d, a, b, myBlock[10], 15'u8, 0xFFEFF47D'u32)
II(b, c, d, a, myBlock[1], 21'u8, 0x85845DD1'u32)
II(a, b, c, d, myBlock[8], 6'u8, 0x6FA87E4F'u32)
II(d, a, b, c, myBlock[15], 10'u8, 0xFE2CE6E0'u32)
II(c, d, a, b, myBlock[6], 15'u8, 0xA3014314'u32)
II(b, c, d, a, myBlock[13], 21'u8, 0x4E0811A1'u32)
II(a, b, c, d, myBlock[4], 6'u8, 0xF7537E82'u32)
II(d, a, b, c, myBlock[11], 10'u8, 0xBD3AF235'u32)
II(c, d, a, b, myBlock[2], 15'u8, 0x2AD7D2BB'u32)
II(b, c, d, a, myBlock[9], 21'u8, 0xEB86D391'u32)
state[0] = state[0] + a
state[1] = state[1] + b
state[2] = state[2] + c
state[3] = state[3] + d
proc md5Init*(c: var MD5Context) {.raises: [], tags: [], gcsafe.}
proc md5Update*(c: var MD5Context, input: openArray[uint8]) {.raises: [],
tags: [], gcsafe.}
proc md5Final*(c: var MD5Context, digest: var MD5Digest) {.raises: [], tags: [], gcsafe.}
proc md5Update*(c: var MD5Context, input: cstring, len: int) {.raises: [],
tags: [], gcsafe.} =
## Updates the `MD5Context` with the `input` data of length `len`.
##
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
## function explicitly.
md5Update(c, input.slice(0, len - 1))
proc toMD5*(s: string): MD5Digest =
## Computes the `MD5Digest` value for a string `s`.
##
## **See also:**
## * `getMD5 proc <#getMD5,string>`_ which returns a string representation
## of the `MD5Digest`
## * `$ proc <#$,MD5Digest>`_ for converting MD5Digest to string
runnableExamples:
assert $toMD5("abc") == "900150983cd24fb0d6963f7d28e17f72"
var c: MD5Context
md5Init(c)
md5Update(c, s.slice(0, s.len - 1))
md5Final(c, result)
proc `$`*(d: MD5Digest): string =
## Converts a `MD5Digest` value into its string representation.
const digits = "0123456789abcdef"
result = ""
for i in 0..15:
add(result, digits[(d[i].int shr 4) and 0xF])
add(result, digits[d[i].int and 0xF])
proc getMD5*(s: string): string =
## Computes an MD5 value of `s` and returns its string representation.
##
## **See also:**
## * `toMD5 proc <#toMD5,string>`_ which returns the `MD5Digest` of a string
runnableExamples:
assert getMD5("abc") == "900150983cd24fb0d6963f7d28e17f72"
var
c: MD5Context
d: MD5Digest
md5Init(c)
md5Update(c, s.slice(0, s.len - 1))
md5Final(c, d)
result = $d
proc `==`*(D1, D2: MD5Digest): bool =
## Checks if two `MD5Digest` values are identical.
for i in 0..15:
if D1[i] != D2[i]: return false
return true
proc clearBuffer(c: var MD5Context) {.inline.} =
zeroMem(addr(c.buffer), sizeof(MD5Buffer))
proc md5Init*(c: var MD5Context) =
## Initializes an `MD5Context`.
##
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
## function explicitly.
c.state[0] = 0x67452301'u32
c.state[1] = 0xEFCDAB89'u32
c.state[2] = 0x98BADCFE'u32
c.state[3] = 0x10325476'u32
c.count[0] = 0'u32
c.count[1] = 0'u32
clearBuffer(c)
proc writeBuffer(c: var MD5Context, index: int,
input: openArray[uint8], inputIndex, len: int) {.inline.} =
copyMem(addr(c.buffer[index]), unsafeAddr(input[inputIndex]), len)
proc md5Update*(c: var MD5Context, input: openArray[uint8]) =
## Updates the `MD5Context` with the `input` data.
##
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
## function explicitly.
var Index = int((c.count[0] shr 3) and 0x3F)
c.count[0] = c.count[0] + (uint32(input.len) shl 3)
if c.count[0] < (uint32(input.len) shl 3): c.count[1] = c.count[1] + 1'u32
c.count[1] = c.count[1] + (uint32(input.len) shr 29)
var PartLen = 64 - Index
if input.len >= PartLen:
writeBuffer(c, Index, input, 0, PartLen)
transform(c.buffer, c.state)
var i = PartLen
while i + 63 < input.len:
transform(input.slice(i, i + 63), c.state)
inc(i, 64)
if i < input.len:
writeBuffer(c, 0, input, i, input.len - i)
elif input.len > 0:
writeBuffer(c, Index, input, 0, input.len)
proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
## Finishes the `MD5Context` and stores the result in `digest`.
##
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
## function explicitly.
var
Bits: MD5CBits
PadLen: int
decode(Bits, c.count)
var Index = int((c.count[0] shr 3) and 0x3F)
if Index < 56: PadLen = 56 - Index
else: PadLen = 120 - Index
md5Update(c, padding.slice(0, PadLen - 1))
md5Update(c, Bits)
decode(digest, c.state)
clearBuffer(c)
when defined(nimHasStyleChecks):
{.pop.} #{.push styleChecks: off.}

View File

@@ -11,7 +11,7 @@
## represents a complete Nim project. Single modules can either be kept in RAM
## or stored in a rod-file.
import intsets, tables, hashes, md5
import intsets, tables, hashes, md5_old
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
import ic / [packed_ast, ic]
@@ -57,18 +57,6 @@ type
sym*: PSym
info*: TLineInfo
PipelinePass* = enum
NonePass
SemPass
JSgenPass
CgenPass
EvalPass
InterpreterPass
GenDependPass
Docgen2TexPass
Docgen2JsonPass
Docgen2Pass
ModuleGraph* {.acyclic.} = ref object
ifaces*: seq[Iface] ## indexed by int32 fileIdx
packed*: PackedModuleGraph
@@ -116,7 +104,6 @@ type
cacheCounters*: Table[string, BiggestInt] # IC: implemented
cacheTables*: Table[string, BTree[string, PNode]] # IC: implemented
passes*: seq[TPass]
pipelinePass*: PipelinePass
onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}

View File

@@ -11,8 +11,13 @@
import
ast, magicsys, msgs, options,
idents, lexer, syntaxes, modulegraphs,
lineinfos, pathutils
idents, lexer, passes, syntaxes, llstream, modulegraphs,
lineinfos, pathutils, tables, packages
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
import ic / replayer
proc resetSystemArtifacts*(g: ModuleGraph) =
magicsys.resetSysTypes(g)
@@ -20,12 +25,12 @@ proc resetSystemArtifacts*(g: ModuleGraph) =
template getModuleIdent(graph: ModuleGraph, filename: AbsoluteFile): PIdent =
getIdent(graph.cache, splitFile(filename).name)
proc partialInitModule*(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) =
proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) =
let packSym = getPackage(graph, fileIdx)
result.owner = packSym
result.position = int fileIdx
proc newModule*(graph: ModuleGraph; fileIdx: FileIndex): PSym =
proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
# We cannot call ``newSym`` here, because we have to circumvent the ID
# mechanism, which we do in order to assign each module a persistent ID.
@@ -33,21 +38,103 @@ proc newModule*(graph: ModuleGraph; fileIdx: FileIndex): PSym =
name: getModuleIdent(graph, filename),
info: newLineInfo(fileIdx, 1, 1))
if not isNimIdentifier(result.name.s):
rawMessage(graph.config, errGenerated, "invalid module name: '" & result.name.s &
"'; a module name must be a valid Nim identifier.")
rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s)
partialInitModule(result, graph, fileIdx, filename)
graph.registerModule(result)
proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym =
var flags = flags
if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule
result = graph.getModule(fileIdx)
template processModuleAux(moduleStatus) =
onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule)
var s: PLLStream
if sfMainModule in flags:
if graph.config.projectIsStdin: s = stdin.llStreamOpen
elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput)
discard processModule(graph, result, idGeneratorFromModule(result), s)
if result == nil:
var cachedModules: seq[FileIndex]
result = moduleFromRodFile(graph, fileIdx, cachedModules)
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
if result == nil:
result = newModule(graph, fileIdx)
result.flags.incl flags
registerModule(graph, result)
processModuleAux("import")
else:
if sfSystemModule in flags:
graph.systemModule = result
partialInitModule(result, graph, fileIdx, filename)
for m in cachedModules:
registerModuleById(graph, m)
replayStateChanges(graph.packed[m.int].module, graph)
replayGenericCacheInformation(graph, m.int)
elif graph.isDirty(result):
result.flags.excl sfDirty
# reset module fields:
initStrTables(graph, result)
result.ast = nil
processModuleAux("import(dirty)")
graph.markClientsDirty(fileIdx)
proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym =
# this is called by the semantic checking phase
assert graph.config != nil
result = compileModule(graph, fileIdx, {}, s)
graph.addDep(s, fileIdx)
# keep track of import relationships
if graph.config.hcrOn:
graph.importDeps.mgetOrPut(FileIndex(s.position), @[]).add(fileIdx)
#if sfSystemModule in result.flags:
# localError(result.info, errAttemptToRedefine, result.name.s)
# restore the notes for outer module:
graph.config.notes =
if graph.config.belongsToProjectPackage(s) or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
else: graph.config.foreignPackageNotes
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
graph.addDep(s, fileIdx)
graph.addIncludeDep(s.position.FileIndex, fileIdx)
proc connectCallbacks*(graph: ModuleGraph) =
graph.includeFileCallback = includeModule
graph.importModuleCallback = importModule
proc compileSystemModule*(graph: ModuleGraph) =
if graph.systemModule == nil:
connectCallbacks(graph)
graph.config.m.systemFileIdx = fileInfoIdx(graph.config,
graph.config.libpath / RelativeFile"system.nim")
discard graph.compileModule(graph.config.m.systemFileIdx, {sfSystemModule})
proc wantMainModule*(conf: ConfigRef) =
if conf.projectFull.isEmpty:
fatal(conf, gCmdLineInfo, "command expects a filename")
conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt))
proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) =
connectCallbacks(graph)
let conf = graph.config
wantMainModule(conf)
configComplete(graph)
let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim")
let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx
conf.projectMainIdx2 = projectFile
let packSym = getPackage(graph, projectFile)
graph.config.mainPackageId = packSym.getPackageId
graph.importStack.add projectFile
if projectFile == systemFileIdx:
discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule})
else:
graph.compileSystemModule()
discard graph.compileModule(projectFile, {sfMainModule})
proc makeModule*(graph: ModuleGraph; filename: AbsoluteFile): PSym =
result = graph.newModule(fileInfoIdx(graph.config, filename))
registerModule(graph, result)

View File

@@ -128,13 +128,6 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
var dummy: bool
result = fileInfoIdx(conf, filename, dummy)
proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile; isKnownFile: var bool): FileIndex =
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), isKnownFile)
proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex =
var dummy: bool
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy)
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
result.fileIndex = fileInfoIdx
if line < int high(uint16):
@@ -541,11 +534,10 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
ignoreMsg = not conf.hasWarn(msg)
if not ignoreMsg and msg in conf.warningAsErrors:
title = ErrorTitle
color = ErrorColor
else:
title = WarningTitle
color = WarningColor
if not ignoreMsg: writeContext(conf, info)
color = WarningColor
inc(conf.warnCounter)
of hintMin..hintMax:
sev = Severity.Hint

View File

@@ -31,10 +31,6 @@ define:useStdoutAsStdmsg
warning[ObservableStores]:off
@end
@if nimHasWarnCastSizes:
warning[CastSizes]:on
@end
@if nimHasWarningAsError:
warningAsError[GcUnsafe2]:on
@end
@@ -42,7 +38,3 @@ define:useStdoutAsStdmsg
@if nimHasWarnUnnamedBreak:
warningAserror[UnnamedBreak]:on
@end
@if nimHasWarnBareExcept:
warningAserror[BareExcept]:on
@end

View File

@@ -41,15 +41,6 @@ when defined(profiler) or defined(memProfiler):
{.hint: "Profiling support is turned on!".}
import nimprof
proc nimbleLockExists(config: ConfigRef): bool =
const nimbleLock = "nimble.lock"
let pd = if not config.projectPath.isEmpty: config.projectPath else: AbsoluteDir(getCurrentDir())
if optSkipParentConfigFiles notin config.globalOptions:
for dir in parentDirs(pd.string, fromRoot=true, inclusive=false):
if fileExists(dir / nimbleLock):
return true
return fileExists(pd.string / nimbleLock)
proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
var p = parseopt.initOptParser(cmd)
var argsCount = 0
@@ -83,11 +74,6 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
config.arguments.len > 0 and config.cmd notin {cmdTcc, cmdNimscript, cmdCrun}:
rawMessage(config, errGenerated, errArgsNeedRunOption)
if config.nimbleLockExists:
# disable nimble path if nimble.lock is present.
# see https://github.com/nim-lang/nimble/issues/1004
disableNimblePath(config)
proc getNimRunExe(conf: ConfigRef): string =
# xxx consider defining `conf.getConfigVar("nimrun.exe")` to allow users to
# customize the binary to run the command with, e.g. for custom `nodejs` or `wine`.

View File

@@ -9,16 +9,10 @@
## exposes the Nim VM to clients.
import
ast, modules, condsyms,
options, llstream, lineinfos, vm,
ast, astalgo, modules, passes, condsyms,
options, sem, llstream, lineinfos, vm,
vmdef, modulegraphs, idents, os, pathutils,
scriptconfig, std/compilesettings
import pipelines
when defined(nimPreviewSlimSystem):
import std/[assertions, syncio]
passaux, scriptconfig, std/compilesettings
type
Interpreter* = ref object ## Use Nim as an interpreter with this object
@@ -82,7 +76,7 @@ proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) =
let s = if scriptStream != nil: scriptStream
else: llStreamOpen(findFile(i.graph.config, i.scriptName), fmRead)
discard processPipelineModule(i.graph, i.mainModule, i.idgen, s)
processModule(i.graph, i.mainModule, i.idgen, s)
proc findNimStdLib*(): string =
## Tries to find a path to a valid "system.nim" file.
@@ -115,10 +109,12 @@ proc createInterpreter*(scriptName: string;
var conf = newConfigRef()
var cache = newIdentCache()
var graph = newModuleGraph(cache, conf)
connectPipelineCallbacks(graph)
connectCallbacks(graph)
initDefines(conf.symbols)
for define in defines:
defineSymbol(conf.symbols, define[0], define[1])
registerPass(graph, semPass)
registerPass(graph, evalPass)
for p in searchPaths:
conf.searchPaths.add(AbsoluteDir p)
@@ -133,8 +129,7 @@ proc createInterpreter*(scriptName: string;
if registerOps:
vm.registerAdditionalOps() # Required to register parts of stdlib modules
graph.vm = vm
setPipeLinePass(graph, EvalPass)
graph.compilePipelineSystemModule()
graph.compileSystemModule()
result = Interpreter(mainModule: m, graph: graph, scriptName: scriptName, idgen: idgen)
proc destroyInterpreter*(i: Interpreter) =
@@ -164,11 +159,13 @@ proc runRepl*(r: TLLRepl;
defineSymbol(conf.symbols, "nimscript")
if supportNimscript: defineSymbol(conf.symbols, "nimconfig")
when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
registerPass(graph, verbosePass)
registerPass(graph, semPass)
registerPass(graph, evalPass)
var m = graph.makeStdinModule()
incl(m.flags, sfMainModule)
var idgen = idGeneratorFromModule(m)
if supportNimscript: graph.vm = setupVM(m, cache, "stdin", graph, idgen)
setPipeLinePass(graph, InterpreterPass)
graph.compilePipelineSystemModule()
discard processPipelineModule(graph, m, idgen, llStreamOpenStdIn(r))
graph.compileSystemModule()
processModule(graph, m, idgen, llStreamOpenStdIn(r))

View File

@@ -7,4 +7,4 @@ proc findNodeJs*(): string {.inline.} =
result = findExe("node")
if result.len == 0:
echo "Please install NodeJS first, see https://nodejs.org/en/download"
raise newException(IOError, "NodeJS not found in PATH")
raise newException(IOError, "NodeJS not found in PATH: " & result)

View File

@@ -16,8 +16,6 @@ import
from trees import exprStructuralEquivalent
import std/strutils
const
nfMarkForDeletion = nfNone # faster than a lookup table
@@ -112,17 +110,16 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) =
var reverse = false
if n[0].kind == nkSym:
let s = n[0].sym
let name = s.name.s.normalize
if s.magic == mWasMoved or name == "=wasmoved":
if s.magic == mWasMoved:
b.wasMovedLocs.add n
special = true
elif name == "=destroy":
elif s.name.s == "=destroy":
if c.inFinally > 0 and (b.hasReturn or b.hasBreak):
discard "cannot optimize away the destructor"
else:
c.wasMovedDestroyPair b, n
special = true
elif name == "=sink":
elif s.name.s == "=sink":
reverse = true
if not special:

View File

@@ -24,7 +24,7 @@ const
useEffectSystem* = true
useWriteTracking* = false
hasFFI* = defined(nimHasLibFFI)
copyrightYear* = "2023"
copyrightYear* = "2022"
nimEnableCovariance* = defined(nimEnableCovariance)
@@ -78,8 +78,6 @@ type # please make sure we have under 32 options
optThreadAnalysis, # thread analysis pass
optTlsEmulation, # thread var emulation turned on
optGenIndex # generate index file for documentation;
optGenIndexOnly # generate only index file for documentation
optNoImportdoc # disable loading external documentation files
optEmbedOrigSrc # embed the original source in the generated code
# also: generate header file
optIdeDebug # idetools: debug mode
@@ -108,7 +106,6 @@ type # please make sure we have under 32 options
optSourcemap
optProfileVM # enable VM profiler
optEnableDeepCopy # ORC specific: enable 'deepcopy' for all types.
optShowNonExportedFields # for documentation: show fields that are not exported
TGlobalOptions* = set[TGlobalOption]
@@ -196,7 +193,7 @@ type
IdeCmd* = enum
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod,
ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols,
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand
ideRecompile, ideChanged, ideType, ideDeclaration
Feature* = enum ## experimental features; DO NOT RENAME THESE!
dotOperators,
@@ -234,7 +231,6 @@ type
## are not anymore.
laxEffects
## Lax effects system prior to Nim 2.0.
verboseTypeMismatch
SymbolFilesOption* = enum
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
@@ -279,9 +275,6 @@ type
scope*, localUsages*, globalUsages*: int # more usages is better
tokenLen*: int
version*: int
endLine*: uint16
endCol*: int
Suggestions* = seq[Suggest]
ProfileInfo* = object
@@ -412,11 +405,6 @@ type
nimMainPrefix*: string
vmProfileData*: ProfileData
expandProgress*: bool
expandLevels*: int
expandNodeResult*: string
expandPosition*: TLineInfo
proc parseNimVersion*(a: string): NimVer =
# could be moved somewhere reusable
if a.len > 0:
@@ -621,7 +609,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
osQnx, osAtari, osAix,
osHaiku, osVxWorks, osSolaris, osNetbsd,
osFreebsd, osOpenbsd, osDragonfly, osMacosx, osIos,
osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos, osZephyr, osNuttX}
osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos, osZephyr}
of "linux":
result = conf.target.targetOS in {osLinux, osAndroid}
of "bsd":
@@ -643,8 +631,6 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
result = conf.target.targetOS == osFreeRTOS
of "zephyr":
result = conf.target.targetOS == osZephyr
of "nuttx":
result = conf.target.targetOS == osNuttX
of "littleendian": result = CPU[conf.target.targetCPU].endian == littleEndian
of "bigendian": result = CPU[conf.target.targetCPU].endian == bigEndian
of "cpu8": result = CPU[conf.target.targetCPU].bit == 8
@@ -719,24 +705,22 @@ proc getPrefixDir*(conf: ConfigRef): AbsoluteDir =
## clone or using installed nim, so that these exist: `result/doc/advopt.txt`
## and `result/lib/system.nim`
if not conf.prefixDir.isEmpty: result = conf.prefixDir
else:
let binParent = AbsoluteDir splitPath(getAppDir()).head
when defined(posix):
if binParent == AbsoluteDir"/usr":
result = AbsoluteDir"/usr/lib/nim"
elif binParent == AbsoluteDir"/usr/local":
result = AbsoluteDir"/usr/local/lib/nim"
else:
result = binParent
else:
result = binParent
else: result = AbsoluteDir splitPath(getAppDir()).head
proc setDefaultLibpath*(conf: ConfigRef) =
# set default value (can be overwritten):
if conf.libpath.isEmpty:
# choose default libpath:
var prefix = getPrefixDir(conf)
conf.libpath = prefix / RelativeDir"lib"
when defined(posix):
if prefix == AbsoluteDir"/usr":
conf.libpath = AbsoluteDir"/usr/lib/nim"
elif prefix == AbsoluteDir"/usr/local":
conf.libpath = AbsoluteDir"/usr/local/lib/nim"
else:
conf.libpath = prefix / RelativeDir"lib"
else:
conf.libpath = prefix / RelativeDir"lib"
# Special rule to support other tools (nimble) which import the compiler
# modules and make use of them.
@@ -1009,12 +993,6 @@ proc isDynlibOverride*(conf: ConfigRef; lib: string): bool =
result = optDynlibOverrideAll in conf.globalOptions or
conf.dllOverrides.hasKey(lib.canonDynlibName)
proc showNonExportedFields*(conf: ConfigRef) =
incl(conf.globalOptions, optShowNonExportedFields)
proc expandDone*(conf: ConfigRef): bool =
result = conf.ideCmd == ideExpand and conf.expandLevels == 0 and conf.expandProgress
proc parseIdeCmd*(s: string): IdeCmd =
case s:
of "sug": ideSug
@@ -1054,7 +1032,6 @@ proc `$`*(c: IdeCmd): string =
of ideProject: "project"
of ideGlobalSymbols: "globalSymbols"
of ideDeclaration: "declaration"
of ideExpand: "expand"
of ideRecompile: "recompile"
of ideChanged: "changed"
of ideType: "type"

View File

@@ -42,7 +42,7 @@ when isMainModule or defined(nimTestGrammar):
proc checkSameGrammar*() =
doAssert sameFileContent(newGrammarText, "doc/grammar.txt"),
"execute 'nim r compiler/parser.nim' to keep grammar.txt up-to-date"
"execute 'nim r compiler.nim' to keep grammar.txt up-to-date"
else:
writeGrammarFile("doc/grammar.txt")
import ".." / tools / grammar_nanny
@@ -354,12 +354,6 @@ proc colcom(p: var Parser, n: PNode) =
const tkBuiltInMagics = {tkType, tkStatic, tkAddr}
template setEndInfo() =
when defined(nimsuggest):
result.endInfo = TLineInfo(fileIndex: p.lex.fileIdx,
line: p.lex.previousTokenEnd.line,
col: p.lex.previousTokenEnd.col)
proc parseSymbol(p: var Parser, mode = smNormal): PNode =
#| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
#| | IDENT | KEYW
@@ -412,7 +406,6 @@ proc parseSymbol(p: var Parser, mode = smNormal): PNode =
# if it is a keyword:
#if not isKeyword(p.tok.tokType): getTok(p)
result = p.emptyNode
setEndInfo()
proc equals(p: var Parser, a: PNode): PNode =
if p.tok.tokType == tkEquals:
@@ -584,7 +577,6 @@ proc parseCast(p: var Parser): PNode =
result.add(exprColonEqExpr(p))
optPar(p)
eat(p, tkParRi)
setEndInfo()
proc setBaseFlags(n: PNode, base: NumericalBase) =
case base
@@ -607,7 +599,6 @@ proc parseGStrLit(p: var Parser, a: PNode): PNode =
getTok(p)
else:
result = a
setEndInfo()
proc complexOrSimpleStmt(p: var Parser): PNode
proc simpleExpr(p: var Parser, mode = pmNormal): PNode
@@ -712,7 +703,6 @@ proc parsePar(p: var Parser): PNode =
skipComment(p, a)
optPar(p)
eat(p, tkParRi)
setEndInfo()
proc identOrLiteral(p: var Parser, mode: PrimaryMode): PNode =
#| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
@@ -951,7 +941,6 @@ proc parseOperators(p: var Parser, headNode: PNode,
a.add(b)
result = a
opPrec = getPrecedence(p.tok)
setEndInfo()
proc simpleExprAux(p: var Parser, limit: int, mode: PrimaryMode): PNode =
var mode = mode
@@ -1001,7 +990,6 @@ proc parsePragma(p: var Parser): PNode =
when defined(nimpretty):
dec p.em.doIndentMore
dec p.em.keepIndents
setEndInfo()
proc identVis(p: var Parser; allowDot=false): PNode =
#| identVis = symbol OPR? # postfix position
@@ -1070,7 +1058,6 @@ proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode =
result.add(parseExpr(p))
else:
result.add(newNodeP(nkEmpty, p))
setEndInfo()
proc parseTuple(p: var Parser, indentAllowed = false): PNode =
#| tupleTypeBracket = '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
@@ -1115,7 +1102,6 @@ proc parseTuple(p: var Parser, indentAllowed = false): PNode =
parMessage(p, errGenerated, "the syntax for tuple types is 'tuple[...]', not 'tuple(...)'")
else:
result = newNodeP(nkTupleClassTy, p)
setEndInfo()
proc parseParamList(p: var Parser, retColon = true): PNode =
#| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
@@ -1164,7 +1150,6 @@ proc parseParamList(p: var Parser, retColon = true): PNode =
when defined(nimpretty):
dec p.em.doIndentMore
dec p.em.keepIndents
setEndInfo()
proc optPragmas(p: var Parser): PNode =
if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)):
@@ -1185,7 +1170,6 @@ proc parseDoBlock(p: var Parser; info: TLineInfo): PNode =
result = newProcNode(nkDo, info,
body = result, params = params, name = p.emptyNode, pattern = p.emptyNode,
genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode)
setEndInfo()
proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode =
#| routineExpr = ('proc' | 'func' | 'iterator') paramListColon pragma? ('=' COMMENT? stmt)?
@@ -1208,7 +1192,6 @@ proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode =
if kind == nkFuncDef:
parMessage(p, "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead")
result.add(pragmas)
setEndInfo()
proc isExprStart(p: Parser): bool =
case p.tok.tokType
@@ -1228,7 +1211,6 @@ proc parseSymbolList(p: var Parser, result: PNode) =
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, s)
setEndInfo()
proc parseTypeDescKAux(p: var Parser, kind: TNodeKind,
mode: PrimaryMode): PNode =
@@ -1257,7 +1239,6 @@ proc parseTypeDescKAux(p: var Parser, kind: TNodeKind,
parseSymbolList(p, list)
if mode == pmTypeDef and not isTypedef:
result = parseOperators(p, result, -1, mode)
setEndInfo()
proc parseVarTuple(p: var Parser): PNode
@@ -1283,7 +1264,6 @@ proc parseFor(p: var Parser): PNode =
result.add(parseExpr(p))
colcom(p, result)
result.add(parseStmt(p))
setEndInfo()
template nimprettyDontTouch(body) =
when defined(nimpretty):
@@ -1322,7 +1302,6 @@ proc parseExpr(p: var Parser): PNode =
nimprettyDontTouch:
result = parseTry(p, isExpr=true)
else: result = simpleExpr(p)
setEndInfo()
proc parseEnum(p: var Parser): PNode
proc parseObject(p: var Parser): PNode
@@ -1432,7 +1411,6 @@ proc parseTypeDesc(p: var Parser, fullExpr = false): PNode =
else:
result = simpleExpr(p, pmTypeDesc)
result = binaryNot(p, result)
setEndInfo()
proc parseTypeDefValue(p: var Parser): PNode =
#| typeDefValue = ((tupleDecl | enumDecl | objectDecl | conceptDecl |
@@ -1463,7 +1441,6 @@ proc parseTypeDefValue(p: var Parser): PNode =
result.add(commandParam(p, isFirstParam, pmTypeDef))
result = postExprBlocks(p, result)
result = binaryNot(p, result)
setEndInfo()
proc makeCall(n: PNode): PNode =
## Creates a call if the given node isn't already a call.
@@ -1496,7 +1473,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
result = makeCall(result)
getTok(p)
skipComment(p, result)
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept, tkFinally}:
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
var stmtList = newNodeP(nkStmtList, p)
stmtList.add parseStmt(p)
# to keep backwards compatibility (see tests/vm/tstringnil)
@@ -1584,7 +1561,6 @@ proc parseExprStmt(p: var Parser): PNode =
else:
result = a
result = postExprBlocks(p, result)
setEndInfo()
proc parseModuleName(p: var Parser, kind: TNodeKind): PNode =
result = parseExpr(p)
@@ -1596,7 +1572,6 @@ proc parseModuleName(p: var Parser, kind: TNodeKind): PNode =
getTok(p)
result.add(a)
result.add(parseExpr(p))
setEndInfo()
proc parseImport(p: var Parser, kind: TNodeKind): PNode =
#| importStmt = 'import' optInd expr
@@ -1625,7 +1600,6 @@ proc parseImport(p: var Parser, kind: TNodeKind): PNode =
getTok(p)
optInd(p, a)
#expectNl(p)
setEndInfo()
proc parseIncludeStmt(p: var Parser): PNode =
#| includeStmt = 'include' optInd expr ^+ comma
@@ -1642,7 +1616,6 @@ proc parseIncludeStmt(p: var Parser): PNode =
getTok(p)
optInd(p, a)
#expectNl(p)
setEndInfo()
proc parseFromStmt(p: var Parser): PNode =
#| fromStmt = 'from' expr 'import' optInd expr (comma expr)*
@@ -1663,7 +1636,6 @@ proc parseFromStmt(p: var Parser): PNode =
getTok(p)
optInd(p, a)
#expectNl(p)
setEndInfo()
proc parseReturnOrRaise(p: var Parser, kind: TNodeKind): PNode =
#| returnStmt = 'return' optInd expr?
@@ -1685,7 +1657,6 @@ proc parseReturnOrRaise(p: var Parser, kind: TNodeKind): PNode =
var e = parseExpr(p)
e = postExprBlocks(p, e)
result.add(e)
setEndInfo()
proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode =
#| condStmt = expr colcom stmt COMMENT?
@@ -1710,7 +1681,6 @@ proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode =
colcom(p, branch)
branch.add(parseStmt(p))
result.add(branch)
setEndInfo()
proc parseIfOrWhenExpr(p: var Parser, kind: TNodeKind): PNode =
#| condExpr = expr colcom expr optInd
@@ -1735,7 +1705,6 @@ proc parseIfOrWhenExpr(p: var Parser, kind: TNodeKind): PNode =
colcom(p, branch)
branch.add(parseStmt(p))
result.add(branch)
setEndInfo()
proc parseWhile(p: var Parser): PNode =
#| whileStmt = 'while' expr colcom stmt
@@ -1745,7 +1714,6 @@ proc parseWhile(p: var Parser): PNode =
result.add(parseExpr(p))
colcom(p, result)
result.add(parseStmt(p))
setEndInfo()
proc parseCase(p: var Parser): PNode =
#| ofBranch = 'of' exprList colcom stmt
@@ -1793,7 +1761,6 @@ proc parseCase(p: var Parser): PNode =
if wasIndented:
p.currInd = oldInd
setEndInfo()
proc parseTry(p: var Parser; isExpr: bool): PNode =
#| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
@@ -1803,13 +1770,11 @@ proc parseTry(p: var Parser; isExpr: bool): PNode =
#| (optInd 'except' optionalExprList colcom stmt)*
#| (optInd 'finally' colcom stmt)?
result = newNodeP(nkTryStmt, p)
let parentIndent = p.currInd # isExpr
getTok(p)
colcom(p, result)
result.add(parseStmt(p))
var b: PNode = nil
while sameOrNoInd(p) or (isExpr and parentIndent <= p.tok.indent):
while sameOrNoInd(p) or isExpr:
case p.tok.tokType
of tkExcept:
b = newNodeP(nkExceptBranch, p)
@@ -1822,14 +1787,12 @@ proc parseTry(p: var Parser; isExpr: bool): PNode =
b.add(parseStmt(p))
result.add(b)
if b == nil: parMessage(p, "expected 'except'")
setEndInfo()
proc parseExceptBlock(p: var Parser, kind: TNodeKind): PNode =
result = newNodeP(kind, p)
getTok(p)
colcom(p, result)
result.add(parseStmt(p))
setEndInfo()
proc parseBlock(p: var Parser): PNode =
#| blockStmt = 'block' symbol? colcom stmt
@@ -1840,7 +1803,6 @@ proc parseBlock(p: var Parser): PNode =
else: result.add(parseSymbol(p))
colcom(p, result)
result.add(parseStmt(p))
setEndInfo()
proc parseStaticOrDefer(p: var Parser; k: TNodeKind): PNode =
#| staticStmt = 'static' colcom stmt
@@ -1849,7 +1811,6 @@ proc parseStaticOrDefer(p: var Parser; k: TNodeKind): PNode =
getTok(p)
colcom(p, result)
result.add(parseStmt(p))
setEndInfo()
proc parseAsm(p: var Parser): PNode =
#| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
@@ -1866,7 +1827,6 @@ proc parseAsm(p: var Parser): PNode =
result.add(p.emptyNode)
return
getTok(p)
setEndInfo()
proc parseGenericParam(p: var Parser): PNode =
#| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
@@ -1902,7 +1862,6 @@ proc parseGenericParam(p: var Parser): PNode =
result.add(parseExpr(p))
else:
result.add(p.emptyNode)
setEndInfo()
proc parseGenericParamList(p: var Parser): PNode =
#| genericParamList = '[' optInd
@@ -1921,14 +1880,12 @@ proc parseGenericParamList(p: var Parser): PNode =
skipComment(p, a)
optPar(p)
eat(p, tkBracketRi)
setEndInfo()
proc parsePattern(p: var Parser): PNode =
#| pattern = '{' stmt '}'
eat(p, tkCurlyLe)
result = parseStmt(p)
eat(p, tkCurlyRi)
setEndInfo()
proc parseRoutine(p: var Parser, kind: TNodeKind): PNode =
#| indAndComment = (IND{>} COMMENT)? | COMMENT?
@@ -1973,7 +1930,6 @@ proc parseRoutine(p: var Parser, kind: TNodeKind): PNode =
#else:
# assert false, p.lex.config$body.info # avoids hard to track bugs, fail early.
# Yeah, that worked so well. There IS a bug in this logic, now what?
setEndInfo()
proc newCommentStmt(p: var Parser): PNode =
#| commentStmt = COMMENT
@@ -2009,7 +1965,6 @@ proc parseSection(p: var Parser, kind: TNodeKind,
result.add(defparser(p))
else:
parMessage(p, errIdentifierExpected, p.tok)
setEndInfo()
proc parseEnum(p: var Parser): PNode =
#| enumDecl = 'enum' optInd (symbol pragma? optInd ('=' optInd expr COMMENT?)? comma?)+
@@ -2056,7 +2011,6 @@ proc parseEnum(p: var Parser): PNode =
break
if result.len <= 1:
parMessage(p, errIdentifierExpected, p.tok)
setEndInfo()
proc parseObjectPart(p: var Parser): PNode
proc parseObjectWhen(p: var Parser): PNode =
@@ -2082,7 +2036,6 @@ proc parseObjectWhen(p: var Parser): PNode =
branch.add(parseObjectPart(p))
flexComment(p, branch)
result.add(branch)
setEndInfo()
proc parseObjectCase(p: var Parser): PNode =
#| objectBranch = 'of' exprList colcom objectPart
@@ -2124,7 +2077,6 @@ proc parseObjectCase(p: var Parser): PNode =
if b.kind == nkElse: break
if wasIndented:
p.currInd = oldInd
setEndInfo()
proc parseObjectPart(p: var Parser): PNode =
#| objectPart = IND{>} objectPart^+IND{=} DED
@@ -2157,7 +2109,6 @@ proc parseObjectPart(p: var Parser): PNode =
result = p.emptyNode
else:
result = p.emptyNode
setEndInfo()
proc parseObject(p: var Parser): PNode =
#| objectDecl = 'object' ('of' typeDesc)? COMMENT? objectPart
@@ -2178,7 +2129,6 @@ proc parseObject(p: var Parser): PNode =
result.add(p.emptyNode)
else:
result.add(parseObjectPart(p))
setEndInfo()
proc parseTypeClassParam(p: var Parser): PNode =
let modifier =
@@ -2196,7 +2146,6 @@ proc parseTypeClassParam(p: var Parser): PNode =
result.add(p.parseSymbol)
else:
result = p.parseSymbol
setEndInfo()
proc parseTypeClass(p: var Parser): PNode =
#| conceptParam = ('var' | 'out')? symbol
@@ -2240,7 +2189,6 @@ proc parseTypeClass(p: var Parser): PNode =
result.add(p.emptyNode)
else:
result.add(parseStmt(p))
setEndInfo()
proc parseTypeDef(p: var Parser): PNode =
#|
@@ -2274,7 +2222,6 @@ proc parseTypeDef(p: var Parser): PNode =
else:
result.add(p.emptyNode)
indAndComment(p, result) # special extension!
setEndInfo()
proc parseVarTuple(p: var Parser): PNode =
#| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
@@ -2291,7 +2238,6 @@ proc parseVarTuple(p: var Parser): PNode =
result.add(p.emptyNode) # no type desc
optPar(p)
eat(p, tkParRi)
setEndInfo()
proc parseVariable(p: var Parser): PNode =
#| colonBody = colcom stmt postExprBlocks?
@@ -2304,7 +2250,6 @@ proc parseVariable(p: var Parser): PNode =
else: result = parseIdentColonEquals(p, {withPragma, withDot})
result[^1] = postExprBlocks(p, result[^1])
indAndComment(p, result)
setEndInfo()
proc parseConstant(p: var Parser): PNode =
#| constant = (varTuple / identWithPragma) (colon typeDesc)? '=' optInd expr indAndComment
@@ -2324,7 +2269,6 @@ proc parseConstant(p: var Parser): PNode =
result.add(parseExpr(p))
result[^1] = postExprBlocks(p, result[^1])
indAndComment(p, result)
setEndInfo()
proc parseBind(p: var Parser, k: TNodeKind): PNode =
#| bindStmt = 'bind' optInd qualifiedIdent ^+ comma
@@ -2340,7 +2284,6 @@ proc parseBind(p: var Parser, k: TNodeKind): PNode =
getTok(p)
optInd(p, a)
#expectNl(p)
setEndInfo()
proc parseStmtPragma(p: var Parser): PNode =
#| pragmaStmt = pragma (':' COMMENT? stmt)?
@@ -2352,7 +2295,6 @@ proc parseStmtPragma(p: var Parser): PNode =
skipComment(p, result)
result.add a
result.add parseStmt(p)
setEndInfo()
proc simpleStmt(p: var Parser): PNode =
#| simpleStmt = ((returnStmt | raiseStmt | yieldStmt | discardStmt | breakStmt
@@ -2495,7 +2437,6 @@ proc parseStmt(p: var Parser): PNode =
if p.tok.tokType != tkSemiColon: break
getTok(p)
if err and p.tok.tokType == tkEof: break
setEndInfo()
proc parseAll(p: var Parser): PNode =
## Parses the rest of the input stream held by the parser into a PNode.
@@ -2511,7 +2452,6 @@ proc parseAll(p: var Parser): PNode =
getTok(p)
if p.tok.indent != 0:
parMessage(p, errInvalidIndentation)
setEndInfo()
proc checkFirstLineIndentation*(p: var Parser) =
if p.tok.indent != 0 and p.tok.strongSpaceA:
@@ -2545,7 +2485,6 @@ proc parseTopLevelStmt(p: var Parser): PNode =
result = complexOrSimpleStmt(p)
if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
break
setEndInfo()
proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
filename: string = ""; line: int = 0;
@@ -2557,10 +2496,9 @@ proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
var stream = llStreamOpen(s)
stream.lineOffset = line
var p: Parser
p.lex.errorHandler = errorHandler
openParser(p, AbsoluteFile filename, stream, cache, config)
var parser: Parser
parser.lex.errorHandler = errorHandler
openParser(parser, AbsoluteFile filename, stream, cache, config)
result = p.parseAll
closeParser(p)
setEndInfo()
result = parser.parseAll
closeParser(parser)

View File

@@ -14,22 +14,13 @@ import
options, ast, llstream, msgs,
idents,
syntaxes, modulegraphs, reorder,
lineinfos,
pipelineutils,
modules, pathutils, packages,
sem, semdata
import ic/replayer
export skipCodegen, resolveMod, prepareConfigNotes
lineinfos, pathutils, packages
when defined(nimsuggest):
import std/sha1
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
import std/tables
import std/syncio
type
TPassData* = tuple[input: PNode, closeOutput: PNode]
@@ -47,6 +38,12 @@ proc makePass*(open: TPassOpen = nil,
result.process = process
result.isFrontend = isFrontend
proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} =
# can be used by codegen passes to determine whether they should do
# something with `n`. Currently, this ignores `n` and uses the global
# error count instead.
result = config.errorCounter > 0
const
maxPasses = 10
@@ -83,6 +80,13 @@ proc processTopLevelStmt(graph: ModuleGraph, n: PNode, a: var TPassContextArray)
if isNil(m): return false
result = true
proc resolveMod(conf: ConfigRef; module, relativeTo: string): FileIndex =
let fullPath = findModule(conf, module, relativeTo)
if fullPath.isEmpty:
result = InvalidFileIdx
else:
result = fileInfoIdx(conf, fullPath)
proc processImplicits(graph: ModuleGraph; implicits: seq[string], nodeKind: TNodeKind,
a: var TPassContextArray; m: PSym) =
# XXX fixme this should actually be relative to the config file!
@@ -96,6 +100,23 @@ proc processImplicits(graph: ModuleGraph; implicits: seq[string], nodeKind: TNod
importStmt.add str
if not processTopLevelStmt(graph, importStmt, a): break
const
imperativeCode = {low(TNodeKind)..high(TNodeKind)} - {nkTemplateDef, nkProcDef, nkMethodDef,
nkMacroDef, nkConverterDef, nkIteratorDef, nkFuncDef, nkPragma,
nkExportStmt, nkExportExceptStmt, nkFromStmt, nkImportStmt, nkImportExceptStmt}
proc prepareConfigNotes(graph: ModuleGraph; module: PSym) =
# don't be verbose unless the module belongs to the main package:
if graph.config.belongsToProjectPackage(module):
graph.config.notes = graph.config.mainPackageNotes
else:
if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes
graph.config.notes = graph.config.foreignPackageNotes
proc moduleHasChanged*(graph: ModuleGraph; module: PSym): bool {.inline.} =
result = true
#module.id >= 0 or isDefined(graph.config, "nimBackendAssumesChange")
proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
stream: PLLStream): bool {.discardable.} =
if graph.stopCompile(): return true
@@ -122,7 +143,7 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
while true:
openParser(p, fileIdx, s, graph.cache, graph.config)
if (not belongsToStdlib(graph, module)) or module.name.s == "distros":
if not belongsToStdlib(graph, module) or (belongsToStdlib(graph, module) and module.name.s == "distros"):
# XXX what about caching? no processing then? what if I change the
# modules to include between compilation runs? we'd need to track that
# in ROD files. I think we should enable this feature only
@@ -132,22 +153,43 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
processImplicits graph, graph.config.implicitIncludes, nkIncludeStmt, a, module
checkFirstLineIndentation(p)
block processCode:
if graph.stopCompile(): break processCode
while true:
if graph.stopCompile(): break
var n = parseTopLevelStmt(p)
if n.kind == nkEmpty: break processCode
# read everything, no streaming possible
var sl = newNodeI(nkStmtList, n.info)
sl.add n
while true:
var n = parseTopLevelStmt(p)
if n.kind == nkEmpty: break
if n.kind == nkEmpty: break
if (sfSystemModule notin module.flags and
({sfNoForward, sfReorder} * module.flags != {} or
codeReordering in graph.config.features)):
# read everything, no streaming possible
var sl = newNodeI(nkStmtList, n.info)
sl.add n
if sfReorder in module.flags or codeReordering in graph.config.features:
sl = reorder(graph, sl, module)
discard processTopLevelStmt(graph, sl, a)
while true:
var n = parseTopLevelStmt(p)
if n.kind == nkEmpty: break
sl.add n
if sfReorder in module.flags or codeReordering in graph.config.features:
sl = reorder(graph, sl, module)
discard processTopLevelStmt(graph, sl, a)
break
elif n.kind in imperativeCode:
# read everything until the next proc declaration etc.
var sl = newNodeI(nkStmtList, n.info)
sl.add n
var rest: PNode = nil
while true:
var n = parseTopLevelStmt(p)
if n.kind == nkEmpty or n.kind notin imperativeCode:
rest = n
break
sl.add n
#echo "-----\n", sl
if not processTopLevelStmt(graph, sl, a): break
if rest != nil:
#echo "-----\n", rest
if not processTopLevelStmt(graph, rest, a): break
else:
#echo "----- single\n", n
if not processTopLevelStmt(graph, n, a): break
closeParser(p)
if s.kind != llsStdIn: break
closePasses(graph, a)
@@ -157,99 +199,3 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
# They are responsible for closing the rod files. See `cbackend.nim`.
closeRodFile(graph, module)
result = true
proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym =
var flags = flags
if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule
result = graph.getModule(fileIdx)
template processModuleAux(moduleStatus) =
onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule)
var s: PLLStream
if sfMainModule in flags:
if graph.config.projectIsStdin: s = stdin.llStreamOpen
elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput)
discard processModule(graph, result, idGeneratorFromModule(result), s)
if result == nil:
var cachedModules: seq[FileIndex]
result = moduleFromRodFile(graph, fileIdx, cachedModules)
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
if result == nil:
result = newModule(graph, fileIdx)
result.flags.incl flags
registerModule(graph, result)
processModuleAux("import")
else:
if sfSystemModule in flags:
graph.systemModule = result
partialInitModule(result, graph, fileIdx, filename)
for m in cachedModules:
registerModuleById(graph, m)
replayStateChanges(graph.packed[m.int].module, graph)
replayGenericCacheInformation(graph, m.int)
elif graph.isDirty(result):
result.flags.excl sfDirty
# reset module fields:
initStrTables(graph, result)
result.ast = nil
processModuleAux("import(dirty)")
graph.markClientsDirty(fileIdx)
proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym =
# this is called by the semantic checking phase
assert graph.config != nil
result = compileModule(graph, fileIdx, {}, s)
graph.addDep(s, fileIdx)
# keep track of import relationships
if graph.config.hcrOn:
graph.importDeps.mgetOrPut(FileIndex(s.position), @[]).add(fileIdx)
#if sfSystemModule in result.flags:
# localError(result.info, errAttemptToRedefine, result.name.s)
# restore the notes for outer module:
graph.config.notes =
if graph.config.belongsToProjectPackage(s) or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
else: graph.config.foreignPackageNotes
proc connectCallbacks*(graph: ModuleGraph) =
graph.includeFileCallback = modules.includeModule
graph.importModuleCallback = importModule
proc compileSystemModule*(graph: ModuleGraph) =
if graph.systemModule == nil:
connectCallbacks(graph)
graph.config.m.systemFileIdx = fileInfoIdx(graph.config,
graph.config.libpath / RelativeFile"system.nim")
discard graph.compileModule(graph.config.m.systemFileIdx, {sfSystemModule})
proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) =
connectCallbacks(graph)
let conf = graph.config
wantMainModule(conf)
configComplete(graph)
let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim")
let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx
conf.projectMainIdx2 = projectFile
let packSym = getPackage(graph, projectFile)
graph.config.mainPackageId = packSym.getPackageId
graph.importStack.add projectFile
if projectFile == systemFileIdx:
discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule})
else:
graph.compileSystemModule()
discard graph.compileModule(projectFile, {sfMainModule})
proc mySemOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
result = preparePContext(graph, module, idgen)
proc mySemClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
var c = PContext(context)
closePContext(graph, c, n)
proc mySemProcess(context: PPassContext, n: PNode): PNode =
result = semWithPContext(PContext(context), n)
const semPass* = makePass(mySemOpen, mySemProcess, mySemClose,
isFrontend = true)

View File

@@ -10,7 +10,7 @@
## Path handling utilities for Nim. Strictly typed code in order
## to avoid the never ending time sink in getting path handling right.
import os, pathnorm, strutils
import os, pathnorm
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
@@ -102,52 +102,3 @@ when true:
proc addFileExt*(x: RelativeFile; ext: string): RelativeFile {.borrow.}
proc writeFile*(x: AbsoluteFile; content: string) {.borrow.}
proc skipHomeDir(x: string): int =
when defined(windows):
if x.continuesWith("Users/", len("C:/")):
result = 3
else:
result = 0
else:
if x.startsWith("/home/") or x.startsWith("/Users/"):
result = 3
elif x.startsWith("/mnt/") and x.continuesWith("/Users/", len("/mnt/c")):
result = 5
else:
result = 0
proc relevantPart(s: string; afterSlashX: int): string =
result = newStringOfCap(s.len - 8)
var slashes = afterSlashX
for i in 0..<s.len:
if slashes == 0:
result.add s[i]
elif s[i] == '/':
dec slashes
template canonSlashes(x: string): string =
when defined(windows):
x.replace('\\', '/')
else:
x
proc customPathImpl(x: string): string =
# Idea: Encode a "protocol" via "//protocol/path" which is not ambiguous
# as path canonicalization would have removed the double slashes.
# /mnt/X/Users/Y
# X:\\Users\Y
# /home/Y
# -->
# //user/
if not isAbsolute(x):
result = customPathImpl(canonSlashes(getCurrentDir() / x))
else:
let slashes = skipHomeDir(x)
if slashes > 0:
result = "//user/" & relevantPart(x, slashes)
else:
result = x
proc customPath*(x: string): string =
customPathImpl canonSlashes x

View File

@@ -1,284 +0,0 @@
import sem, cgen, modulegraphs, ast, llstream, parser, msgs,
lineinfos, reorder, options, semdata, cgendata, modules, pathutils,
packages, syntaxes, depends, vm, pragmas, idents, lookups
import pipelineutils
when not defined(leanCompiler):
import jsgen, docgen2
import std/[syncio, objectdollar, assertions, tables, strutils]
import renderer
import ic/replayer
proc setPipeLinePass*(graph: ModuleGraph; pass: PipelinePass) =
graph.pipelinePass = pass
proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext): PNode =
case graph.pipelinePass
of CgenPass:
result = semNode
if bModule != nil:
genTopLevelStmt(BModule(bModule), result)
of JSgenPass:
when not defined(leanCompiler):
result = processJSCodeGen(bModule, semNode)
of GenDependPass:
result = addDotDependency(bModule, semNode)
of SemPass:
result = graph.emptyNode
of Docgen2Pass, Docgen2TexPass:
when not defined(leanCompiler):
result = processNode(bModule, semNode)
of Docgen2JsonPass:
when not defined(leanCompiler):
result = processNodeJson(bModule, semNode)
of EvalPass, InterpreterPass:
result = interpreterCode(bModule, semNode)
of NonePass:
doAssert false, "use setPipeLinePass to set a proper PipelinePass"
proc processImplicitImports(graph: ModuleGraph; implicits: seq[string], nodeKind: TNodeKind,
m: PSym, ctx: PContext, bModule: PPassContext, idgen: IdGenerator,
) =
# XXX fixme this should actually be relative to the config file!
let relativeTo = toFullPath(graph.config, m.info)
for module in items(implicits):
# implicit imports should not lead to a module importing itself
if m.position != resolveMod(graph.config, module, relativeTo).int32:
var importStmt = newNodeI(nodeKind, m.info)
var str = newStrNode(nkStrLit, module)
str.info = m.info
importStmt.add str
message(graph.config, importStmt.info, hintProcessingStmt, $idgen[])
let semNode = semWithPContext(ctx, importStmt)
if semNode == nil or processPipeline(graph, semNode, bModule) == nil:
break
proc prePass(c: PContext; n: PNode) =
for son in n:
if son.kind == nkPragma:
for s in son:
var key = if s.kind in nkPragmaCallKinds and s.len > 1: s[0] else: s
if key.kind in {nkBracketExpr, nkCast} or key.kind notin nkIdentKinds:
continue
let ident = whichKeyword(considerQuotedIdent(c, key))
case ident
of wReorder:
pragmaNoForward(c, s, flag = sfReorder)
of wExperimental:
if isTopLevel(c) and s.kind in nkPragmaCallKinds and s.len == 2:
let name = c.semConstExpr(c, s[1])
case name.kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
try:
let feature = parseEnum[Feature](name.strVal)
if feature == codeReordering:
c.features.incl feature
c.module.flags.incl sfReorder
except ValueError:
discard
else:
discard
else:
discard
proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
stream: PLLStream): bool =
if graph.stopCompile(): return true
var
p: Parser
s: PLLStream
fileIdx = module.fileIdx
prepareConfigNotes(graph, module)
let ctx = preparePContext(graph, module, idgen)
let bModule: PPassContext =
case graph.pipelinePass
of CgenPass:
setupCgen(graph, module, idgen)
of JSgenPass:
when not defined(leanCompiler):
setupJSgen(graph, module, idgen)
else:
nil
of EvalPass, InterpreterPass:
setupEvalGen(graph, module, idgen)
of GenDependPass:
setupDependPass(graph, module, idgen)
of Docgen2Pass:
when not defined(leanCompiler):
openHtml(graph, module, idgen)
else:
nil
of Docgen2TexPass:
when not defined(leanCompiler):
openTex(graph, module, idgen)
else:
nil
of Docgen2JsonPass:
when not defined(leanCompiler):
openJson(graph, module, idgen)
else:
nil
of SemPass:
nil
of NonePass:
doAssert false, "use setPipeLinePass to set a proper PipelinePass"
nil
if stream == nil:
let filename = toFullPathConsiderDirty(graph.config, fileIdx)
s = llStreamOpen(filename, fmRead)
if s == nil:
rawMessage(graph.config, errCannotOpenFile, filename.string)
return false
else:
s = stream
while true:
syntaxes.openParser(p, fileIdx, s, graph.cache, graph.config)
if not belongsToStdlib(graph, module) or (belongsToStdlib(graph, module) and module.name.s == "distros"):
# XXX what about caching? no processing then? what if I change the
# modules to include between compilation runs? we'd need to track that
# in ROD files. I think we should enable this feature only
# for the interactive mode.
if module.name.s != "nimscriptapi":
processImplicitImports graph, graph.config.implicitImports, nkImportStmt, module, ctx, bModule, idgen
processImplicitImports graph, graph.config.implicitIncludes, nkIncludeStmt, module, ctx, bModule, idgen
checkFirstLineIndentation(p)
block processCode:
if graph.stopCompile(): break processCode
var n = parseTopLevelStmt(p)
if n.kind == nkEmpty: break processCode
# read everything, no streaming possible
var sl = newNodeI(nkStmtList, n.info)
sl.add n
while true:
var n = parseTopLevelStmt(p)
if n.kind == nkEmpty: break
sl.add n
prePass(ctx, sl)
if sfReorder in module.flags or codeReordering in graph.config.features:
sl = reorder(graph, sl, module)
if graph.pipelinePass != EvalPass:
message(graph.config, sl.info, hintProcessingStmt, $idgen[])
var semNode = semWithPContext(ctx, sl)
discard processPipeline(graph, semNode, bModule)
closeParser(p)
if s.kind != llsStdIn: break
let finalNode = closePContext(graph, ctx, nil)
case graph.pipelinePass
of CgenPass:
if bModule != nil:
finalCodegenActions(graph, BModule(bModule), finalNode)
of JSgenPass:
when not defined(leanCompiler):
discard finalJSCodeGen(graph, bModule, finalNode)
of EvalPass, InterpreterPass:
discard interpreterCode(bModule, finalNode)
of SemPass, GenDependPass:
discard
of Docgen2Pass, Docgen2TexPass:
when not defined(leanCompiler):
discard closeDoc(graph, bModule, finalNode)
of Docgen2JsonPass:
when not defined(leanCompiler):
discard closeJson(graph, bModule, finalNode)
of NonePass:
doAssert false, "use setPipeLinePass to set a proper PipelinePass"
if graph.config.backend notin {backendC, backendCpp, backendObjc}:
# We only write rod files here if no C-like backend is active.
# The C-like backends have been patched to support the IC mechanism.
# They are responsible for closing the rod files. See `cbackend.nim`.
closeRodFile(graph, module)
result = true
proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym =
var flags = flags
if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule
result = graph.getModule(fileIdx)
template processModuleAux(moduleStatus) =
onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule)
var s: PLLStream
if sfMainModule in flags:
if graph.config.projectIsStdin: s = stdin.llStreamOpen
elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput)
discard processPipelineModule(graph, result, idGeneratorFromModule(result), s)
if result == nil:
var cachedModules: seq[FileIndex]
result = moduleFromRodFile(graph, fileIdx, cachedModules)
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
if result == nil:
result = newModule(graph, fileIdx)
result.flags.incl flags
registerModule(graph, result)
processModuleAux("import")
else:
if sfSystemModule in flags:
graph.systemModule = result
partialInitModule(result, graph, fileIdx, filename)
for m in cachedModules:
registerModuleById(graph, m)
replayStateChanges(graph.packed[m.int].module, graph)
replayGenericCacheInformation(graph, m.int)
elif graph.isDirty(result):
result.flags.excl sfDirty
# reset module fields:
initStrTables(graph, result)
result.ast = nil
processModuleAux("import(dirty)")
graph.markClientsDirty(fileIdx)
proc importPipelineModule(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym =
# this is called by the semantic checking phase
assert graph.config != nil
result = compilePipelineModule(graph, fileIdx, {}, s)
graph.addDep(s, fileIdx)
# keep track of import relationships
if graph.config.hcrOn:
graph.importDeps.mgetOrPut(FileIndex(s.position), @[]).add(fileIdx)
#if sfSystemModule in result.flags:
# localError(result.info, errAttemptToRedefine, result.name.s)
# restore the notes for outer module:
graph.config.notes =
if graph.config.belongsToProjectPackage(s) or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
else: graph.config.foreignPackageNotes
proc connectPipelineCallbacks*(graph: ModuleGraph) =
graph.includeFileCallback = modules.includeModule
graph.importModuleCallback = importPipelineModule
proc compilePipelineSystemModule*(graph: ModuleGraph) =
if graph.systemModule == nil:
connectPipelineCallbacks(graph)
graph.config.m.systemFileIdx = fileInfoIdx(graph.config,
graph.config.libpath / RelativeFile"system.nim")
discard graph.compilePipelineModule(graph.config.m.systemFileIdx, {sfSystemModule})
proc compilePipelineProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) =
connectPipelineCallbacks(graph)
let conf = graph.config
wantMainModule(conf)
configComplete(graph)
let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim")
let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx
conf.projectMainIdx2 = projectFile
let packSym = getPackage(graph, projectFile)
graph.config.mainPackageId = packSym.getPackageId
graph.importStack.add projectFile
if projectFile == systemFileIdx:
discard graph.compilePipelineModule(projectFile, {sfMainModule, sfSystemModule})
else:
graph.compilePipelineSystemModule()
discard graph.compilePipelineModule(projectFile, {sfMainModule})

View File

@@ -1,26 +0,0 @@
import ast, options, lineinfos, pathutils, msgs, modulegraphs, packages
proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} =
# can be used by codegen passes to determine whether they should do
# something with `n`. Currently, this ignores `n` and uses the global
# error count instead.
result = config.errorCounter > 0
proc resolveMod*(conf: ConfigRef; module, relativeTo: string): FileIndex =
let fullPath = findModule(conf, module, relativeTo)
if fullPath.isEmpty:
result = InvalidFileIdx
else:
result = fileInfoIdx(conf, fullPath)
proc prepareConfigNotes*(graph: ModuleGraph; module: PSym) =
# don't be verbose unless the module belongs to the main package:
if graph.config.belongsToProjectPackage(module):
graph.config.notes = graph.config.mainPackageNotes
else:
if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes
graph.config.notes = graph.config.foreignPackageNotes
proc moduleHasChanged*(graph: ModuleGraph; module: PSym): bool {.inline.} =
result = true
#module.id >= 0 or isDefined(graph.config, "nimBackendAssumesChange")

View File

@@ -26,8 +26,7 @@ type
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osCrossos, osAix, osPalmos, osQnx,
osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osZephyr,
osNuttX, osAny
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osZephyr, osAny
type
TInfoOSProp* = enum
@@ -194,10 +193,6 @@ const
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
props: {ospPosix}),
(name: "NuttX", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
props: {ospPosix}),
(name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",

View File

@@ -270,7 +270,7 @@ proc onOff(c: PContext, n: PNode, op: TOptions, resOptions: var TOptions) =
if isTurnedOn(c, n): resOptions.incl op
else: resOptions.excl op
proc pragmaNoForward*(c: PContext, n: PNode; flag=sfNoForward) =
proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
if isTurnedOn(c, n):
incl(c.module.flags, flag)
c.features.incl codeReordering
@@ -364,7 +364,7 @@ proc processNote(c: PContext, n: PNode) =
else: invalidPragma(c, n)
else: invalidPragma(c, n)
proc pragmaToOptions*(w: TSpecialWord): TOptions {.inline.} =
proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} =
case w
of wChecks: ChecksOptions
of wObjChecks: {optObjCheck}
@@ -513,11 +513,8 @@ proc processCompile(c: PContext, n: PNode) =
var cf = Cfile(nimname: splitFile(src).name,
cname: src, obj: dest, flags: {CfileFlag.External},
customArgs: customArgs)
if not fileExists(src):
localError(c.config, n.info, "cannot find: " & src.string)
else:
extccomp.addExternalFileToCompile(c.config, cf)
recordPragma(c, it, "compile", src.string, dest.string, customArgs)
extccomp.addExternalFileToCompile(c.config, cf)
recordPragma(c, it, "compile", src.string, dest.string, customArgs)
proc getStrLit(c: PContext, n: PNode; i: int): string =
n[i] = c.semConstExpr(c, n[i])
@@ -929,8 +926,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wThreadVar:
noVal(c, it)
incl(sym.flags, {sfThread, sfGlobal})
of wDeadCodeElimUnused:
warningDeprecated(c.config, n.info, "'{.deadcodeelim: on.}' is deprecated, now a noop") # deprecated, dead code elim always on
of wDeadCodeElimUnused: discard # deprecated, dead code elim always on
of wNoForward: pragmaNoForward(c, it)
of wReorder: pragmaNoForward(c, it, flag = sfReorder)
of wMagic: processMagic(c, it, sym)

View File

@@ -9,9 +9,10 @@
# This module implements the renderer of the standard Nim representation.
# 'import renderer' is so useful for debugging
# that Nim shouldn't produce a warning for that:
{.used.}
when defined(nimHasUsed):
# 'import renderer' is so useful for debugging
# that Nim shouldn't produce a warning for that:
{.used.}
import
lexer, options, idents, strutils, ast, msgs, lineinfos
@@ -23,8 +24,7 @@ type
TRenderFlag* = enum
renderNone, renderNoBody, renderNoComments, renderDocComments,
renderNoPragmas, renderIds, renderNoProcDefs, renderSyms, renderRunnableExamples,
renderIr, renderNonExportedFields, renderExpandUsing
renderIr, renderExpandUsing
TRenderFlags* = set[TRenderFlag]
TRenderTok* = object
kind*: TokType
@@ -619,9 +619,7 @@ proc isHideable(config: ConfigRef, n: PNode): bool =
# xxx compare `ident` directly with `getIdent(cache, wRaises)`, but
# this requires a `cache`.
case n.kind
of nkExprColonExpr:
result = n[0].kind == nkIdent and
n[0].ident.s.nimIdentNormalize in ["raises", "tags", "extern", "deprecated", "forbids", "stacktrace"]
of nkExprColonExpr: result = n[0].kind == nkIdent and n[0].ident.s in ["raises", "tags", "extern", "deprecated", "forbids"]
of nkIdent: result = n.ident.s in ["gcsafe", "deprecated"]
else: result = false
@@ -653,7 +651,7 @@ proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
inHideable = false
proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
theEnd: int = -1) =
theEnd: int = - 1) =
var ind: int
if rfInConstExpr in c.flags:
ind = g.indent + IndentWidth
@@ -1482,11 +1480,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
of nkRecList:
indentNL(g)
for i in 0..<n.len:
if n[i].kind == nkIdentDefs and n[i][0].kind == nkPostfix or
renderNonExportedFields in g.flags:
optNL(g)
gsub(g, n[i], c)
gcoms(g)
optNL(g)
gsub(g, n[i], c)
gcoms(g)
dedent(g)
putNL(g)
of nkOfInherit:

View File

@@ -106,7 +106,6 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev
if a.kind == nkExprColonExpr and a[0].kind == nkIdent and a[0].ident.s == "pragma":
# user defined pragma
decl(a[1])
for i in 1..<n.safeLen: deps(n[i])
else:
for i in 0..<n.safeLen: deps(n[i])
of nkMixinStmt, nkBindStmt: discard

View File

@@ -11,10 +11,10 @@
## language.
import
ast, modules, idents, condsyms,
options, llstream, vm, vmdef, commands,
ast, modules, idents, passes, condsyms,
options, sem, llstream, vm, vmdef, commands,
os, times, osproc, wordrecg, strtabs, modulegraphs,
pathutils, pipelines
pathutils
when defined(nimPreviewSlimSystem):
import std/syncio
@@ -197,11 +197,13 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
conf.symbolFiles = disabledSf
let graph = newModuleGraph(cache, conf)
connectPipelineCallbacks(graph)
connectCallbacks(graph)
if freshDefines: initDefines(conf.symbols)
defineSymbol(conf.symbols, "nimscript")
defineSymbol(conf.symbols, "nimconfig")
registerPass(graph, semPass)
registerPass(graph, evalPass)
conf.searchPaths.add(conf.libpath)
@@ -216,9 +218,8 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
var vm = setupVM(m, cache, scriptName.string, graph, idgen)
graph.vm = vm
graph.setPipeLinePass(EvalPass)
graph.compilePipelineSystemModule()
discard graph.processPipelineModule(m, vm.idgen, stream)
graph.compileSystemModule()
discard graph.processModule(m, vm.idgen, stream)
# watch out, "newruntime" can be set within NimScript itself and then we need
# to remember this:

View File

@@ -13,7 +13,7 @@ import
ast, strutils, options, astalgo, trees,
wordrecg, ropes, msgs, idents, renderer, types, platform, math,
magicsys, nversion, nimsets, semfold, modulepaths, importer,
procfind, lookups, pragmas, semdata, semtypinst, sigmatch,
procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch,
intsets, transf, vmdef, vm, aliases, cgmeth, lambdalifting,
evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
lowerings, plugins/active, lineinfos, strtabs, int128,
@@ -405,6 +405,9 @@ proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags; expectedTyp
evaluated = evalAtCompileTime(c, result)
if evaluated != nil: return evaluated
when not defined(nimHasSinkInference):
{.pragma: nosinks.}
include hlo, seminst, semcall
proc resetSemFlag(n: PNode) =
@@ -550,17 +553,18 @@ proc pickCaseBranchIndex(caseExpr, matched: PNode): int =
if endsWithElse:
return caseExpr.len - 1
proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode]
proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode
proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, id: var IntSet): seq[PNode]
proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, id: var IntSet): PNode
proc defaultNodeField(c: PContext, a: PNode): PNode
proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode
const defaultFieldsSkipTypes = {tyGenericInst, tyAlias, tySink}
proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): seq[PNode] =
proc defaultFieldsForTuple(c: PContext, recNode: PNode, id: var IntSet, hasDefault: var bool): seq[PNode] =
case recNode.kind
of nkRecList:
for field in recNode:
result.add defaultFieldsForTuple(c, field, hasDefault)
result.add defaultFieldsForTuple(c, field, id, hasDefault)
of nkSym:
let field = recNode.sym
let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes)
@@ -569,10 +573,10 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s
result.add newTree(nkExprColonExpr, recNode, field.ast)
else:
if recType.kind in {tyObject, tyArray, tyTuple}:
let asgnExpr = defaultNodeField(c, recNode, recNode.typ)
let asgnExpr = defaultNodeField(c, recNode, recNode.typ, id)
if asgnExpr != nil:
hasDefault = true
asgnExpr.flags.incl nfSkipFieldChecking
asgnExpr.flags.incl nfUseDefaultField
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
return
@@ -582,17 +586,17 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s
newSymNode(getSysMagic(c.graph, recNode.info, "zeroDefault", mZeroDefault)),
newNodeIT(nkType, recNode.info, asgnType)
)
asgnExpr.flags.incl nfSkipFieldChecking
asgnExpr.flags.incl nfUseDefaultField
asgnExpr.typ = recType
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
else:
doAssert false
proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] =
proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, id: var IntSet): seq[PNode] =
case recNode.kind
of nkRecList:
for field in recNode:
result.add defaultFieldsForTheUninitialized(c, field)
result.add defaultFieldsForTheUninitialized(c, field, id)
of nkRecCase:
let discriminator = recNode[0]
var selectedBranch: int
@@ -604,34 +608,36 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] =
defaultValue = newIntNode(nkIntLit#[c.graph]#, 0)
defaultValue.typ = discriminator.typ
selectedBranch = recNode.pickCaseBranchIndex defaultValue
defaultValue.flags.incl nfSkipFieldChecking
defaultValue.flags.incl nfUseDefaultField
result.add newTree(nkExprColonExpr, discriminator, defaultValue)
result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1])
result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1], id)
of nkSym:
let field = recNode.sym
let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes)
if field.ast != nil: #Try to use default value
result.add newTree(nkExprColonExpr, recNode, field.ast)
elif recType.kind in {tyObject, tyArray, tyTuple}:
let asgnExpr = defaultNodeField(c, recNode, recType)
let asgnExpr = defaultNodeField(c, recNode, recType, id)
if asgnExpr != nil:
asgnExpr.typ = recType
asgnExpr.flags.incl nfSkipFieldChecking
asgnExpr.flags.incl nfUseDefaultField
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
else:
doAssert false
proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode =
proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, id: var IntSet): PNode =
let aTypSkip = aTyp.skipTypes(defaultFieldsSkipTypes)
if aTypSkip.kind == tyObject:
let child = defaultFieldsForTheUninitialized(c, aTypSkip.n)
if id.containsOrIncl(aTypSkip.id):
return
let child = defaultFieldsForTheUninitialized(c, aTypSkip.n, id)
if child.len > 0:
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTypSkip))
asgnExpr.typ = aTypSkip
asgnExpr.sons.add child
result = semExpr(c, asgnExpr)
elif aTypSkip.kind == tyArray:
let child = defaultNodeField(c, a, aTypSkip[1])
let child = defaultNodeField(c, a, aTypSkip[1], id)
if child != nil:
let node = newNode(nkIntLit)
@@ -644,15 +650,20 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode =
elif aTypSkip.kind == tyTuple:
var hasDefault = false
if aTypSkip.n != nil:
let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault)
let children = defaultFieldsForTuple(c, aTypSkip.n, id, hasDefault)
if hasDefault and children.len > 0:
result = newNodeI(nkTupleConstr, a.info)
result.typ = aTyp
result.sons.add children
result = semExpr(c, result)
proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode =
var s = initIntSet()
defaultNodeField(c, a, aTyp, s)
proc defaultNodeField(c: PContext, a: PNode): PNode =
result = defaultNodeField(c, a, a.typ)
var s = initIntSet()
result = defaultNodeField(c, a, a.typ, s)
include semtempl, semgnrc, semstmts, semexprs
@@ -666,46 +677,41 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
n.add prc.ast
c.lastGenericIdx = c.generics.len
proc preparePContext*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PContext =
result = newContext(graph, module)
result.idgen = idgen
result.enforceVoidContext = newType(tyTyped, nextTypeId(idgen), nil)
result.voidType = newType(tyVoid, nextTypeId(idgen), nil)
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)
c.voidType = newType(tyVoid, nextTypeId(idgen), nil)
if result.p != nil: internalError(graph.config, module.info, "sem.preparePContext")
result.semConstExpr = semConstExpr
result.semExpr = semExpr
result.semTryExpr = tryExpr
result.semTryConstExpr = tryConstExpr
result.computeRequiresInit = computeRequiresInit
result.semOperand = semOperand
result.semConstBoolExpr = semConstBoolExpr
result.semOverloadedCall = semOverloadedCall
result.semInferredLambda = semInferredLambda
result.semGenerateInstance = generateInstance
result.semTypeNode = semTypeNode
result.instTypeBoundOp = sigmatch.instTypeBoundOp
result.hasUnresolvedArgs = hasUnresolvedArgs
result.templInstCounter = new int
if c.p != nil: internalError(graph.config, module.info, "sem.myOpen")
c.semConstExpr = semConstExpr
c.semExpr = semExpr
c.semTryExpr = tryExpr
c.semTryConstExpr = tryConstExpr
c.computeRequiresInit = computeRequiresInit
c.semOperand = semOperand
c.semConstBoolExpr = semConstBoolExpr
c.semOverloadedCall = semOverloadedCall
c.semInferredLambda = semInferredLambda
c.semGenerateInstance = generateInstance
c.semTypeNode = semTypeNode
c.instTypeBoundOp = sigmatch.instTypeBoundOp
c.hasUnresolvedArgs = hasUnresolvedArgs
c.templInstCounter = new int
pushProcCon(result, module)
pushOwner(result, result.module)
pushProcCon(c, module)
pushOwner(c, c.module)
result.moduleScope = openScope(result)
result.moduleScope.addSym(module) # a module knows itself
c.moduleScope = openScope(c)
c.moduleScope.addSym(module) # a module knows itself
if sfSystemModule in module.flags:
graph.systemModule = module
result.topLevelScope = openScope(result)
c.topLevelScope = openScope(c)
result = c
proc isImportSystemStmt(g: ModuleGraph; n: PNode): bool =
if g.systemModule == nil: return false
var n = n
if n.kind == nkStmtList:
for i in 0..<n.len-1:
if n[i].kind notin {nkCommentStmt, nkEmpty}:
n = n[i]
break
case n.kind
of nkImportStmt:
for x in n:
@@ -770,7 +776,8 @@ proc recoverContext(c: PContext) =
while getCurrOwner(c).kind != skModule: popOwner(c)
while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next
proc semWithPContext*(c: PContext, n: PNode): PNode =
proc myProcess(context: PPassContext, n: PNode): PNode {.nosinks.} =
var c = PContext(context)
# no need for an expensive 'try' if we stop after the first error anyway:
if c.config.errorMax <= 1:
result = semStmtAndGenerateGenerics(c, n)
@@ -791,13 +798,13 @@ proc semWithPContext*(c: PContext, n: PNode): PNode =
#if c.config.cmd == cmdIdeTools: findSuggest(c, n)
storeRodNode(c, result)
proc reportUnusedModules(c: PContext) =
for i in 0..high(c.unusedImports):
if sfUsed notin c.unusedImports[i][0].flags:
message(c.config, c.unusedImports[i][1], warnUnusedImportX, c.unusedImports[i][0].name.s)
proc closePContext*(graph: ModuleGraph; c: PContext, n: PNode): PNode =
proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
var c = PContext(context)
if c.config.cmd == cmdIdeTools and not c.suggestionsMade:
suggestSentinel(c)
closeScope(c) # close module's scope
@@ -812,3 +819,6 @@ proc closePContext*(graph: ModuleGraph; c: PContext, n: PNode): PNode =
popOwner(c)
popProcCon(c)
sealRodFile(c)
const semPass* = makePass(myOpen, myProcess, myClose,
isFrontend = true)

View File

@@ -10,8 +10,7 @@
## This module implements semantic checking for calls.
# included from sem.nim
from std/algorithm import sort
from algorithm import sort
proc sameMethodDispatcher(a, b: PSym): bool =
result = false
@@ -43,7 +42,6 @@ proc initCandidateSymbols(c: PContext, headSymbol: PNode,
best, alt: var TCandidate,
o: var TOverloadIter,
diagnostics: bool): seq[tuple[s: PSym, scope: int]] =
## puts all overloads into a seq and prepares best+alt
result = @[]
var symx = initOverloadIter(o, c, headSymbol)
while symx != nil:
@@ -65,35 +63,36 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
errors: var CandidateErrors,
diagnosticsFlag: bool,
errorsEnabled: bool, flags: TExprFlags) =
# `matches` may find new symbols, so keep track of count
var symCount = c.currentScope.symbols.counter
var o: TOverloadIter
# https://github.com/nim-lang/Nim/issues/21272
# prevent mutation during iteration by storing them in a seq
# luckily `initCandidateSymbols` does just that
var syms = initCandidateSymbols(c, headSymbol, initialBinding, filter,
best, alt, o, diagnosticsFlag)
if len(syms) == 0:
return
# current overload being considered
var sym = syms[0].s
var scope = syms[0].scope
# starts at 1 because 0 is already done with setup, only needs checking
var nextSymIndex = 1
var z: TCandidate # current candidate
while true:
var sym = initOverloadIter(o, c, headSymbol)
var scope = o.lastOverloadScope
# Thanks to the lazy semchecking for operands, we need to check whether
# 'initCandidate' modifies the symbol table (via semExpr).
# This can occur in cases like 'init(a, 1, (var b = new(Type2); b))'
let counterInitial = c.currentScope.symbols.counter
var syms: seq[tuple[s: PSym, scope: int]]
var noSyms = true
var nextSymIndex = 0
while sym != nil:
if sym.kind in filter:
# Initialise 'best' and 'alt' with the first available symbol
initCandidate(c, best, sym, initialBinding, scope, diagnosticsFlag)
initCandidate(c, alt, sym, initialBinding, scope, diagnosticsFlag)
best.state = csNoMatch
break
else:
sym = nextOverloadIter(o, c, headSymbol)
scope = o.lastOverloadScope
var z: TCandidate
while sym != nil:
if sym.kind notin filter:
sym = nextOverloadIter(o, c, headSymbol)
scope = o.lastOverloadScope
continue
determineType(c, sym)
initCandidate(c, z, sym, initialBinding, scope, diagnosticsFlag)
# this is kinda backwards as without a check here the described
# problems in recalc would not happen, but instead it 100%
# does check forever in some cases
if c.currentScope.symbols.counter == symCount:
# may introduce new symbols with caveats described in recalc branch
if c.currentScope.symbols.counter == counterInitial or syms.len != 0:
matches(c, n, orig, z)
if z.state == csMatch:
# little hack so that iterators are preferred over everything else:
if sym.kind == skIterator:
@@ -113,36 +112,22 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
firstMismatch: z.firstMismatch,
diagnostics: z.diagnostics))
else:
# this branch feels like a ticking timebomb
# one of two bad things could happen
# 1) new symbols are discovered but the loop ends before we recalc
# 2) new symbols are discovered and resemmed forever
# not 100% sure if these are possible though as they would rely
# on somehow introducing a new overload during overload resolution
# Symbol table has been modified. Restart and pre-calculate all syms
# before any further candidate init and compare. SLOW, but rare case.
syms = initCandidateSymbols(c, headSymbol, initialBinding, filter,
best, alt, o, diagnosticsFlag)
# reset counter because syms may be in a new order
symCount = c.currentScope.symbols.counter
nextSymIndex = 0
# just in case, should be impossible though
if syms.len == 0:
break
if nextSymIndex > high(syms):
# we have reached the end
noSyms = false
if noSyms:
sym = nextOverloadIter(o, c, headSymbol)
scope = o.lastOverloadScope
elif nextSymIndex < syms.len:
# rare case: retrieve the next pre-calculated symbol
sym = syms[nextSymIndex].s
scope = syms[nextSymIndex].scope
nextSymIndex += 1
else:
break
# advance to next sym
sym = syms[nextSymIndex].s
scope = syms[nextSymIndex].scope
inc(nextSymIndex)
proc effectProblem(f, a: PType; result: var string; c: PContext) =
if f.kind == tyProc and a.kind == tyProc:
if tfThread in f.flags and tfThread notin a.flags:
@@ -207,7 +192,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
# argument in order to remove plenty of candidates. This is
# comparable to what C# does and C# is doing fine.
var filterOnlyFirst = false
if optShowAllMismatches notin c.config.globalOptions and verboseTypeMismatch in c.config.legacyFeatures:
if optShowAllMismatches notin c.config.globalOptions:
for err in errors:
if err.firstMismatch.arg > 1:
filterOnlyFirst = true
@@ -223,10 +208,6 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
if filterOnlyFirst and err.firstMismatch.arg == 1:
inc skipped
continue
if verboseTypeMismatch notin c.config.legacyFeatures:
candidates.add "[" & $err.firstMismatch.arg & "] "
if err.sym.kind in routineKinds and err.sym.ast != nil:
candidates.add(renderTree(err.sym.ast,
{renderNoBody, renderNoComments, renderNoPragmas}))
@@ -236,7 +217,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
candidates.add("\n")
let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil
let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: ""
if n.len > 1 and verboseTypeMismatch in c.config.legacyFeatures:
if n.len > 1:
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
case err.firstMismatch.kind
@@ -293,28 +274,11 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
const
errTypeMismatch = "type mismatch: got <"
errButExpected = "but expected one of:"
errExpectedPosition = "Expected one of (first mismatch at position [#]):"
errUndeclaredField = "undeclared field: '$1'"
errUndeclaredRoutine = "attempting to call undeclared routine: '$1'"
errBadRoutine = "attempting to call routine: '$1'$2"
errAmbiguousCallXYZ = "ambiguous call; both $1 and $2 match for: $3"
proc describeParamList(c: PContext, n: PNode, startIdx = 1; prefer = preferName): string =
result = "Expression: " & $n
for i in startIdx..<n.len:
result.add "\n [" & $i & "] " & renderTree(n[i]) & ": "
result.add describeArg(c, n, i, startIdx, prefer)
result.add "\n"
template legacynotFoundError(c: PContext, n: PNode, errors: CandidateErrors) =
let (prefer, candidates) = presentFailedCandidates(c, n, errors)
var result = errTypeMismatch
result.add(describeArgs(c, n, 1, prefer))
result.add('>')
if candidates != "":
result.add("\n" & errButExpected & "\n" & candidates)
localError(c.config, n.info, result & "\nexpression: " & $n)
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
# Gives a detailed error message; this is separated from semOverloadedCall,
# as semOverloadedCall is already pretty slow (and we need this information
@@ -338,19 +302,17 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
if n[0].kind in nkIdentKinds:
let ident = considerQuotedIdent(c, n[0], n).s
localError(c.config, n.info, errUndeclaredRoutine % ident)
else:
else:
localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree)
return
if verboseTypeMismatch in c.config.legacyFeatures:
legacynotFoundError(c, n, errors)
else:
let (prefer, candidates) = presentFailedCandidates(c, n, errors)
var result = "type mismatch\n"
result.add describeParamList(c, n, 1, prefer)
if candidates != "":
result.add("\n" & errExpectedPosition & "\n" & candidates)
localError(c.config, n.info, result)
let (prefer, candidates) = presentFailedCandidates(c, n, errors)
var result = errTypeMismatch
result.add(describeArgs(c, n, 1, prefer))
result.add('>')
if candidates != "":
result.add("\n" & errButExpected & "\n" & candidates)
localError(c.config, n.info, result & "\nexpression: " & $n)
proc bracketNotFoundError(c: PContext; n: PNode) =
var errors: CandidateErrors = @[]
@@ -615,7 +577,7 @@ proc tryDeref(n: PNode): PNode =
result.add n
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
filter: TSymKinds, flags: TExprFlags): PNode =
filter: TSymKinds, flags: TExprFlags): PNode {.nosinks.} =
var errors: CandidateErrors = @[] # if efExplain in flags: @[] else: nil
var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags)
if r.state == csMatch:
@@ -630,7 +592,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
if efExplain notin flags:
# repeat the overload resolution,
# this time enabling all the diagnostic output (this should fail again)
result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
discard semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
elif efNoUndeclared notin flags:
notFoundError(c, n, errors)

View File

@@ -75,7 +75,6 @@ type
# overload resolution.
efNoDiagnostics,
efTypeAllowed # typeAllowed will be called after
efWantNoDefaults
TExprFlags* = set[TExprFlag]

View File

@@ -302,7 +302,7 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
result = newNodeI(nkConv, n.info)
var targetType = semTypeNode(c, n[0], nil)
case targetType.skipTypes({tyDistinct}).kind
case targetType.kind
of tyTypeDesc:
internalAssert c.config, targetType.len > 0
if targetType.base.kind == tyNone:
@@ -319,8 +319,6 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
return evaluated
else:
targetType = targetType.base
of tyAnything, tyUntyped, tyTyped:
localError(c.config, n.info, "illegal type conversion to '$1'" % typeToString(targetType))
else: discard
maybeLiftType(targetType, c, n[0].info)
@@ -787,7 +785,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
else:
result = newHiddenAddrTaken(c, n, isOutParam)
proc analyseIfAddressTakenInCall(c: PContext, n: PNode, isConverter = false) =
proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
checkMinSonsLen(n, 1, c.config)
const
FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
@@ -795,15 +793,10 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode, isConverter = false) =
mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy, mMove,
mWasMoved}
template checkIfConverterCalled(c: PContext, n: PNode) =
## Checks if there is a converter call which wouldn't be checked otherwise
# Call can sometimes be wrapped in a deref
let node = if n.kind == nkHiddenDeref: n[0] else: n
if node.kind == nkHiddenCallConv:
analyseIfAddressTakenInCall(c, node, true)
# get the real type of the callee
# it may be a proc var with a generic alias type, so we skip over them
var t = n[0].typ.skipTypes({tyGenericInst, tyAlias, tySink})
if n[0].kind == nkSym and n[0].sym.magic in FakeVarParams:
# BUGFIX: check for L-Value still needs to be done for the arguments!
# note sometimes this is eval'ed twice so we check for nkHiddenAddr here:
@@ -818,8 +811,6 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode, isConverter = false) =
discard "allow access within a cast(unsafeAssign) section"
else:
localError(c.config, it.info, errVarForOutParamNeededX % $it)
# Make sure to still check arguments for converters
c.checkIfConverterCalled(n[i])
# bug #5113: disallow newSeq(result) where result is a 'var T':
if n[0].sym.magic in {mNew, mNewFinalize, mNewSeq}:
var arg = n[1] #.skipAddr
@@ -831,14 +822,15 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode, isConverter = false) =
return
for i in 1..<n.len:
let n = if n.kind == nkHiddenDeref: n[0] else: n
c.checkIfConverterCalled(n[i])
if n[i].kind == nkHiddenCallConv:
# we need to recurse explicitly here as converters can create nested
# calls and then they wouldn't be analysed otherwise
analyseIfAddressTakenInCall(c, n[i])
if i < t.len and
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind in {tyVar}:
# Converters wrap var parameters in nkHiddenAddr but they haven't been analysed yet.
# So we need to make sure we are checking them still when in a converter call
if n[i].kind != nkHiddenAddr or isConverter:
n[i] = analyseIfAddressTaken(c, n[i].skipAddr(), isOutParam(skipTypes(t[i], abstractInst-{tyTypeDesc})))
if n[i].kind != nkHiddenAddr:
n[i] = analyseIfAddressTaken(c, n[i], isOutParam(skipTypes(t[i], abstractInst-{tyTypeDesc})))
include semmagic
proc evalAtCompileTime(c: PContext, n: PNode): PNode =
@@ -986,14 +978,6 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy
return errorNode(c, n)
result = n
when defined(nimsuggest):
if c.config.expandProgress:
if c.config.expandLevels == 0:
return n
else:
c.config.expandLevels -= 1
let callee = result[0].sym
case callee.kind
of skMacro: result = semMacroExpr(c, result, orig, callee, flags, expectedType)
@@ -1004,7 +988,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
if callee.magic != mNone:
result = magicsAfterOverloadResolution(c, result, flags, expectedType)
result = magicsAfterOverloadResolution(c, result, flags)
when false:
if result.typ != nil and
not (result.typ.kind == tySequence and result.typ[0].kind == tyEmpty):
@@ -1904,9 +1888,6 @@ proc semReturn(c: PContext, n: PNode): PNode =
localError(c.config, n.info, "'return' not allowed here")
proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode =
when defined(nimsuggest):
if c.graph.config.expandDone():
return n
openScope(c)
result = semExpr(c, n, expectedType = expectedType)
if c.p.resultSym != nil and not isEmptyType(result.typ):
@@ -1964,8 +1945,6 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
tupleConstr[i] = takeImplicitAddr(c, tupleConstr[i], e.kind == tyLent)
else:
localError(c.config, n[0].info, errXExpected, "tuple constructor")
elif e.kind == tyEmpty:
localError(c.config, n[0].info, errTypeExpected)
else:
when false:
# XXX investigate what we really need here.
@@ -2209,13 +2188,10 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
if ids.len > 0:
dummyTemplate[paramsPos] = newNodeI(nkFormalParams, n.info)
dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "untyped").newSymNode # return type
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[0], getSysSym(c.graph, n.info, "typed").newSymNode, c.graph.emptyNode)
for i in 1..<ids.len:
let typ = semExprWithType(c, quotes[i+1], {}).typ
if tfTriggersCompileTime notin typ.flags and typ.kind != tyTypeDesc:
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[i], newNodeIT(nkType, n.info, typ), c.graph.emptyNode)
else:
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[i], getSysSym(c.graph, n.info, "typed").newSymNode, c.graph.emptyNode)
ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type
ids.add c.graph.emptyNode # no default value
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids)
var tmpl = semTemplateDef(c, dummyTemplate)
quotes[0] = tmpl[namePos]
# This adds a call to newIdentNode("result") as the first argument to the template call
@@ -2915,6 +2891,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
defer:
if isCompilerDebug():
echo ("<", c.config$n.info, n, ?.result.typ)
template directLiteral(typeKind: TTypeKind) =
if result.typ == nil:
if expectedType != nil and (
@@ -2926,19 +2903,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
result.typ = getSysType(c.graph, n.info, typeKind)
result = n
when defined(nimsuggest):
var expandStarted = false
if c.config.ideCmd == ideExpand and not c.config.expandProgress and
((n.kind in {nkFuncDef, nkProcDef, nkIteratorDef, nkTemplateDef, nkMethodDef, nkConverterDef} and
n.info.exactEquals(c.config.expandPosition)) or
(n.kind in {nkCall, nkCommand} and
n[0].info.exactEquals(c.config.expandPosition))):
expandStarted = true
c.config.expandProgress = true
if c.config.expandLevels == 0:
c.config.expandNodeResult = $n
suggestQuit()
if c.config.cmd == cmdIdeTools: suggestExpr(c, n)
if nfSem in n.flags: return
case n.kind
@@ -3078,7 +3042,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
result = semConv(c, n, expectedType)
elif ambig and n.len == 1:
errorUseQualifier(c, n.info, s)
elif n.len == 1 or (n.kind == nkCall and useObjConstr(c, n, flags, expectedType)):
elif n.len == 1:
result = semObjConstr(c, n, flags, expectedType)
elif s.magic == mNone: result = semDirectOp(c, n, flags, expectedType)
else: result = semMagic(c, n, s, flags, expectedType)
@@ -3266,8 +3230,3 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
localError(c.config, n.info, "invalid expression: " &
renderTree(n, {renderNoComments}))
if result != nil: incl(result.flags, nfSem)
when defined(nimsuggest):
if expandStarted:
c.config.expandNodeResult = $result
suggestQuit()

View File

@@ -569,8 +569,6 @@ proc foldDefine(m, s: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
else: result = copyTree(s.astdef) # unreachable
else:
result = copyTree(s.astdef)
if result != nil:
result.info = n.info
proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
result = nil
@@ -595,8 +593,6 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
result = foldDefine(m, s, n, idgen, g)
else:
result = copyTree(s.astdef)
if result != nil:
result.info = n.info
of skProc, skFunc, skMethod:
result = n
of skParam:
@@ -685,7 +681,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
n[0] = a
of nkBracket, nkCurly:
result = copyNode(n)
for son in n.items:
for i, son in n.pairs:
var a = getConstExpr(m, son, idgen, g)
if a == nil: return nil
result.add a
@@ -709,7 +705,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
# tuple constructor
result = copyNode(n)
if (n.len > 0) and (n[0].kind == nkExprColonExpr):
for expr in n.items:
for i, expr in n.pairs:
let exprNew = copyNode(expr) # nkExprColonExpr
exprNew.add expr[0]
let a = getConstExpr(m, expr[1], idgen, g)
@@ -717,7 +713,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
exprNew.add a
result.add exprNew
else:
for expr in n.items:
for i, expr in n.pairs:
let a = getConstExpr(m, expr, idgen, g)
if a == nil: return nil
result.add a

View File

@@ -78,18 +78,14 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
if macroToExpandSym(s):
onUse(n.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
c.friendModules.add(s.owner.getModule)
result = semGenericStmt(c, result, {}, ctx)
discard c.friendModules.pop()
else:
result = symChoice(c, n, s, scOpen)
of skMacro:
if macroToExpandSym(s):
onUse(n.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
c.friendModules.add(s.owner.getModule)
result = semGenericStmt(c, result, {}, ctx)
discard c.friendModules.pop()
else:
result = symChoice(c, n, s, scOpen)
of skGenericParam:
@@ -249,9 +245,7 @@ proc semGenericStmt(c: PContext, n: PNode,
if macroToExpand(s) and sc.safeLen <= 1:
onUse(fn.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
c.friendModules.add(s.owner.getModule)
result = semGenericStmt(c, result, flags, ctx)
discard c.friendModules.pop()
else:
n[0] = sc
result = n
@@ -260,9 +254,7 @@ proc semGenericStmt(c: PContext, n: PNode,
if macroToExpand(s) and sc.safeLen <= 1:
onUse(fn.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
c.friendModules.add(s.owner.getModule)
result = semGenericStmt(c, result, flags, ctx)
discard c.friendModules.pop()
else:
n[0] = sc
result = n
@@ -501,20 +493,6 @@ proc semGenericStmt(c: PContext, n: PNode,
of nkExprColonExpr, nkExprEqExpr:
checkMinSonsLen(n, 2, c.config)
result[1] = semGenericStmt(c, n[1], flags, ctx)
of nkObjConstr:
for i in 0..<n.len:
result[i] = semGenericStmt(c, n[i], flags, ctx)
if result[0].kind == nkSym:
let fmoduleId = getModule(result[0].sym).id
var isVisible = false
for module in c.friendModules:
if module.id == fmoduleId:
isVisible = true
break
if isVisible:
for i in 1..<result.len:
if result[i].kind == nkExprColonExpr:
result[i][1].flags.incl nfSkipFieldChecking
else:
for i in 0..<n.len:
result[i] = semGenericStmt(c, n[i], flags, ctx)

View File

@@ -40,7 +40,7 @@ const
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
internalAssert c.config, n.kind == nkGenericParams
for a in n.items:
for i, a in n.pairs:
internalAssert c.config, a.kind == nkSym
var q = a.sym
if q.typ.kind in {tyTypeDesc, tyGenericParam, tyStatic, tyConcept}+tyTypeClasses:
@@ -127,18 +127,11 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
if sfGenSym in param.flags:
idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
freshGenSyms(c, b, result, orig, symMap)
if sfBorrow notin orig.flags:
# We do not want to generate a body for generic borrowed procs.
# As body is a sym to the borrowed proc.
let resultType = # todo probably refactor it into a function
if result.kind == skMacro:
sysTypeFromName(c.graph, n.info, "NimNode")
elif not isInlineIterator(result.typ):
result.typ[0]
else:
nil
b = semProcBody(c, b, resultType)
b = semProcBody(c, b)
result.ast[bodyPos] = hloBody(c, b)
excl(result.flags, sfForward)
trackProc(c, result, result.ast[bodyPos])
@@ -321,7 +314,7 @@ proc fillMixinScope(c: PContext) =
p = p.next
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym =
info: TLineInfo): PSym {.nosinks.} =
## Generates a new instance of a generic procedure.
## The `pt` parameter is a type-unsafe mapping table used to link generic
## parameters to their concrete types within the generic instance.

View File

@@ -20,8 +20,9 @@ proc addDefaultFieldForNew(c: PContext, n: PNode): PNode =
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[1].info, typ))
asgnExpr.typ = typ
var t = typ.skipTypes({tyGenericInst, tyAlias, tySink})[0]
var id = initIntSet()
while true:
asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n)
asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n, id)
let base = t[0]
if base == nil:
break
@@ -526,7 +527,7 @@ proc checkDefault(c: PContext, n: PNode): PNode =
message(c.config, n.info, warnUnsafeDefault, typeToString(constructed))
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
flags: TExprFlags; expectedType: PType = nil): PNode =
flags: TExprFlags): PNode =
## This is the preferred code point to implement magics.
## ``c`` the current module, a symbol table to a very good approximation
## ``n`` the ast like it would be passed to a real macro
@@ -635,9 +636,5 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result = n
of mPrivateAccess:
result = semPrivateAccess(c, n)
of mArrToSeq:
result = n
if result.typ != nil and expectedType != nil and result.typ.kind == tySequence and expectedType.kind == tySequence and result.typ[0].kind == tyEmpty:
result.typ = expectedType # type inference for empty sequence # bug #21377
else:
result = n

View File

@@ -76,7 +76,7 @@ proc semConstrField(c: PContext, flags: TExprFlags,
let assignment = locateFieldInInitExpr(c, field, initExpr)
if assignment != nil:
if nfSem in assignment.flags: return assignment[1]
if nfSkipFieldChecking in assignment[1].flags:
if nfUseDefaultField in assignment[1].flags:
discard
elif not fieldVisible(c, field):
localError(c.config, initExpr.info,
@@ -142,45 +142,15 @@ proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): strin
if result.len != 0: result.add ", "
result.add field.sym.name.s.quoteStr
proc locateFieldInDefaults(sym: PSym, defaults: seq[PNode]): bool =
result = false
for d in defaults:
if sym.id == d[0].sym.id:
return true
proc collectMissingFields(c: PContext, fieldsRecList: PNode,
constrCtx: var ObjConstrContext, defaults: seq[PNode]
): seq[PSym] =
for r in directFieldsInRecList(fieldsRecList):
constrCtx: var ObjConstrContext) =
for r in directFieldsInRecList(fieldsRecList):
if constrCtx.needsFullInit or
sfRequiresInit in r.sym.flags or
r.sym.typ.requiresInit:
let assignment = locateFieldInInitExpr(c, r.sym, constrCtx.initExpr)
if assignment == nil and not locateFieldInDefaults(r.sym, defaults):
if constrCtx.needsFullInit or
sfRequiresInit in r.sym.flags or
r.sym.typ.requiresInit:
constrCtx.missingFields.add r.sym
else:
result.add r.sym
proc collectMissingCaseFields(c: PContext, branchNode: PNode,
constrCtx: var ObjConstrContext, defaults: seq[PNode]): seq[PSym] =
if branchNode != nil:
let fieldsRecList = branchNode[^1]
result = collectMissingFields(c, fieldsRecList, constrCtx, defaults)
proc collectOrAddMissingCaseFields(c: PContext, branchNode: PNode,
constrCtx: var ObjConstrContext, defaults: var seq[PNode]) =
let res = collectMissingCaseFields(c, branchNode, constrCtx, defaults)
for sym in res:
let asgnType = newType(tyTypeDesc, nextTypeId(c.idgen), sym.typ.owner)
let recTyp = sym.typ.skipTypes(defaultFieldsSkipTypes)
rawAddSon(asgnType, recTyp)
let asgnExpr = newTree(nkCall,
newSymNode(getSysMagic(c.graph, constrCtx.initExpr.info, "zeroDefault", mZeroDefault)),
newNodeIT(nkType, constrCtx.initExpr.info, asgnType)
)
asgnExpr.flags.incl nfSkipFieldChecking
asgnExpr.typ = recTyp
defaults.add newTree(nkExprColonExpr, newSymNode(sym), asgnExpr)
if assignment == nil:
constrCtx.missingFields.add r.sym
proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
@@ -196,6 +166,11 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
let fields = branch[^1]
fieldsPresentInInitExpr(c, fields, constrCtx.initExpr)
template collectMissingFields(branchNode: PNode) =
if branchNode != nil:
let fields = branchNode[^1]
collectMissingFields(c, fields, constrCtx)
let discriminator = n[0]
internalAssert c.config, discriminator.kind == nkSym
var selectedBranch = -1
@@ -313,7 +288,8 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
# When a branch is selected with a partial match, some of the fields
# that were not initialized may be mandatory. We must check for this:
if result.status == initPartial:
collectOrAddMissingCaseFields(c, branchNode, constrCtx, result.defaults)
collectMissingFields branchNode
else:
result.status = initNone
let discriminatorVal = semConstrField(c, flags + {efPreferStatic},
@@ -326,7 +302,7 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
# a result:
let defaultValue = newIntLit(c.graph, constrCtx.initExpr.info, 0)
let matchedBranch = n.pickCaseBranch defaultValue
discard collectMissingCaseFields(c, matchedBranch, constrCtx, @[])
collectMissingFields matchedBranch
else:
result.status = initPartial
if discriminatorVal.kind == nkIntLit:
@@ -336,12 +312,11 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
if matchedBranch != nil:
let (_, defaults) = semConstructFields(c, matchedBranch[^1], constrCtx, flags)
result.defaults.add defaults
collectOrAddMissingCaseFields(c, matchedBranch, constrCtx, result.defaults)
collectMissingFields matchedBranch
else:
# All bets are off. If any of the branches has a mandatory
# fields we must produce an error:
for i in 1..<n.len:
discard collectMissingCaseFields(c, n[i], constrCtx, @[])
for i in 1..<n.len: collectMissingFields n[i]
of nkSym:
let field = n.sym
let e = semConstrField(c, flags, field, constrCtx.initExpr)
@@ -351,13 +326,10 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
result.status = initUnknown
result.defaults.add newTree(nkExprColonExpr, n, field.ast)
else:
if efWantNoDefaults notin flags: # cannot compute defaults at the typeRightPass
let defaultExpr = defaultNodeField(c, n)
if defaultExpr != nil:
result.status = initUnknown
result.defaults.add newTree(nkExprColonExpr, n, defaultExpr)
else:
result.status = initNone
let defaultExpr = defaultNodeField(c, n)
if defaultExpr != nil:
result.status = initUnknown
result.defaults.add newTree(nkExprColonExpr, n, defaultExpr)
else:
result.status = initNone
else:
@@ -373,7 +345,7 @@ proc semConstructTypeAux(c: PContext,
result.status.mergeInitStatus status
result.defaults.add defaults
if status in {initPartial, initNone, initUnknown}:
discard collectMissingFields(c, t.n, constrCtx, result.defaults)
collectMissingFields c, t.n, constrCtx
let base = t[0]
if base == nil: break
t = skipTypes(base, skipPtrs)
@@ -392,7 +364,7 @@ proc initConstrContext(t: PType, initExpr: PNode): ObjConstrContext =
proc computeRequiresInit(c: PContext, t: PType): bool =
assert t.kind == tyObject
var constrCtx = initConstrContext(t, newNode(nkObjConstr))
let initResult = semConstructTypeAux(c, constrCtx, {efWantNoDefaults})
let initResult = semConstructTypeAux(c, constrCtx, {})
constrCtx.missingFields.len > 0
proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
@@ -402,7 +374,7 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
assert objType != nil
if objType.kind == tyObject:
var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
let initResult = semConstructTypeAux(c, constrCtx, {efWantNoDefaults})
let initResult = semConstructTypeAux(c, constrCtx, {})
if constrCtx.missingFields.len > 0:
localError(c.config, info,
"The $1 type doesn't have a default value. The following fields must be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)])
@@ -412,113 +384,15 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
else:
assert false, "Must not enter here."
type
ObjConstrError = enum
none
discriminatorError = "The discriminator can only be initialized with unnamed fields known at the compile time"
mixingError = "When mixing named fields and unnamed fields, every field needs to be initialized in order"
lackingError = "The object construction is given more fields than required"
proc filterObjConstr(c: PContext; field: PNode, n: PNode, iterField: var int, flags: TExprFlags, write: bool): ObjConstrError =
result = none
if iterField >= n.len:
return mixingError
case field.kind
of nkRecCase:
# handle defaults if the ast of the field is known
var discriminatorVal =
case n[iterField].kind
of nkExprColonExpr:
semExprFlagDispatched(c, n[iterField][1], flags + {efPreferStatic})
else:
semExprFlagDispatched(c, n[iterField], flags + {efPreferStatic})
let ret = filterObjConstr(c, field[0], n, iterField, flags, write)
if ret != none:
return ret
if discriminatorVal == nil or discriminatorVal.kind != nkIntLit:
return discriminatorError
let matchedBranch = field.pickCaseBranch discriminatorVal
if matchedBranch != nil:
result = filterObjConstr(c, matchedBranch.lastSon, n, iterField, flags, write)
else:
result = none
of nkSym:
if n[iterField].kind == nkExprColonExpr and field.sym.name.id == considerQuotedIdent(c, n[iterField][0]).id:
inc iterField
elif not fieldVisible(c, field.sym):
discard
elif n[iterField].kind != nkExprColonExpr:
if write:
n[iterField] = newTree(nkExprColonExpr, field, n[iterField])
inc iterField
else:
result = mixingError
of nkRecList:
for f in field:
let ret = filterObjConstr(c, f, n, iterField, flags, write)
if ret != none:
result = ret
break
else:
assert false
proc expandObjConstr(c: PContext, n: PNode, t: PType, flags: TExprFlags): PNode =
result = n
var hasValue = false
for i in 1..<n.len:
if n[i].kind != nkExprColonExpr:
hasValue = true
break
if hasValue:
var iterField = 1
let ret = filterObjConstr(c, t.n, result, iterField, flags, write = true)
if ret != none:
localError(c.config, result.info, $ret)
else:
if iterField > result.len:
localError(c.config, result.info, $mixingError)
elif iterField < result.len:
localError(c.config, result.info, $lackingError)
proc useObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): bool =
var n = copyTree(n)
var t = semTypeNode(c, n[0], nil)
if t == nil:
return false
if t.skipTypes({tyGenericInst,
tyAlias, tySink, tyOwned, tyRef}).kind != tyObject and
expectedType != nil and expectedType.skipTypes({tyGenericInst,
tyAlias, tySink, tyOwned, tyRef}).kind == tyObject:
t = expectedType
t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned})
if t.kind == tyRef:
t = skipTypes(t[0], {tyGenericInst, tyAlias, tySink, tyOwned})
if t.kind != tyObject:
return false
for i in 1..<n.len:
if n[i].kind == nkExprColonExpr:
return true
var iterField = 1
result = filterObjConstr(c, t.n, n, iterField, flags, write = false) == none
if iterField != n.len:
return false
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
var t = semTypeNode(c, n[0], nil)
result = newNodeIT(nkObjConstr, n.info, t)
for i in 0..<n.len:
result.add n[i]
if t == nil:
return localErrorNode(c, result, "object constructor needs an object type")
if t.skipTypes({tyGenericInst,
tyAlias, tySink, tyOwned, tyRef}).kind != tyObject and
expectedType != nil and expectedType.skipTypes({tyGenericInst,
@@ -541,10 +415,6 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
"'; the object's generic parameters cannot be inferred and must be explicitly given"
)
let expanded = expandObjConstr(c, n, t, flags)
for i in 0..<expanded.len:
result.add expanded[i]
# Check if the object is fully initialized by recursively testing each
# field (if this is a case object, initialized fields in two different
# branches will be reported as an error):

View File

@@ -822,6 +822,9 @@ proc checkForSink(tracked: PEffects; n: PNode) =
if tracked.inIfStmt == 0 and optSinkInference in tracked.config.options:
checkForSink(tracked.config, tracked.c.idgen, tracked.owner, n)
proc strictFuncsActive(tracked: PEffects): bool {.inline.} =
sfNoSideEffect in tracked.owner.flags and strictFuncs in tracked.c.features and not tracked.inEnforcedNoSideEffects
proc trackCall(tracked: PEffects; n: PNode) =
template gcsafeAndSideeffectCheck() =
if notGcSafe(op) and not importedFromC(a):
@@ -931,11 +934,9 @@ proc trackCall(tracked: PEffects; n: PNode) =
# initialized until after the call. Since we do this after we analysed the
# call, this is fine.
initVar(tracked, n[i].skipAddr, false)
if strictFuncs in tracked.c.features and not tracked.inEnforcedNoSideEffects and
isDangerousLocation(n[i].skipAddr, tracked.owner):
if sfNoSideEffect in tracked.owner.flags:
localError(tracked.config, n[i].info,
"cannot pass $1 to `var T` parameter within a strict func" % renderTree(n[i]))
if tracked.strictFuncsActive and isDangerousLocation(n[i].skipAddr, tracked.owner):
localError(tracked.config, n[i].info,
"cannot pass $1 to `var T` parameter within a strict func" % renderTree(n[i]))
tracked.hasSideEffect = true
else: discard
@@ -1089,12 +1090,10 @@ proc track(tracked: PEffects, n: PNode) =
createTypeBoundOps(tracked, n[0].typ, n.info)
if n[0].kind != nkSym or not isLocalSym(tracked, n[0].sym):
checkForSink(tracked, n[1])
if strictFuncs in tracked.c.features and not tracked.inEnforcedNoSideEffects and
isDangerousLocation(n[0], tracked.owner):
if tracked.strictFuncsActive and isDangerousLocation(n[0], tracked.owner):
tracked.hasSideEffect = true
if sfNoSideEffect in tracked.owner.flags:
localError(tracked.config, n[0].info,
"cannot mutate location $1 within a strict func" % renderTree(n[0]))
localError(tracked.config, n[0].info,
"cannot mutate location $1 within a strict func" % renderTree(n[0]))
of nkVarSection, nkLetSection:
for child in n:
let last = lastSon(child)
@@ -1451,9 +1450,6 @@ proc hasRealBody(s: PSym): bool =
proc trackProc*(c: PContext; s: PSym, body: PNode) =
let g = c.graph
when defined(nimsuggest):
if g.config.expandDone():
return
var effects = s.typ.n[0]
if effects.kind != nkEffectList: return
# effects already computed?
@@ -1492,10 +1488,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
s.kind in {skProc, skFunc, skConverter, skMethod} and s.magic == mNone:
var res = s.ast[resultPos].sym # get result symbol
if res.id notin t.init:
if tfRequiresInit in s.typ[0].flags:
localError(g.config, body.info, "'$1' requires explicit initialization" % "result")
else:
message(g.config, body.info, warnProveInit, "result")
message(g.config, body.info, warnProveInit, "result")
let p = s.ast[pragmasPos]
let raisesSpec = effectSpec(p, wRaises)
if not isNil(raisesSpec):

View File

@@ -40,13 +40,6 @@ const
proc implicitlyDiscardable(n: PNode): bool
proc hasEmpty(typ: PType): bool =
if typ.kind in {tySequence, tyArray, tySet}:
result = typ.lastSon.kind == tyEmpty
elif typ.kind == tyTuple:
for s in typ.sons:
result = result or hasEmpty(s)
proc semDiscard(c: PContext, n: PNode): PNode =
result = n
checkSonsLen(n, 1, c.config)
@@ -54,9 +47,7 @@ proc semDiscard(c: PContext, n: PNode): PNode =
n[0] = semExprWithType(c, n[0])
let sonType = n[0].typ
let sonKind = n[0].kind
if isEmptyType(sonType) or hasEmpty(sonType) or
sonType.kind in {tyNone, tyTypeDesc} or
sonKind == nkTypeOfExpr:
if isEmptyType(sonType) or sonType.kind in {tyNone, tyTypeDesc} or sonKind == nkTypeOfExpr:
localError(c.config, n.info, errInvalidDiscard)
if sonType.kind == tyProc and sonKind notin nkCallKinds:
# tyProc is disallowed to prevent ``discard foo`` to be valid, when ``discard foo()`` is meant.
@@ -114,6 +105,7 @@ proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode =
result.typ = n[1].typ
elif implicitlyDiscardable(n[1]):
result[1].typ = c.enforceVoidContext
result.typ = c.enforceVoidContext
proc semProc(c: PContext, n: PNode): PNode
@@ -218,8 +210,6 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil)
isImported = true
elif not isException(typ):
localError(c.config, typeNode.info, errExprCannotBeRaised)
elif not isDefectOrCatchableError(typ):
message(c.config, a.info, warnBareExcept, "catch a more precise Exception deriving from CatchableError or Defect.")
if containsOrIncl(check, typ.id):
localError(c.config, typeNode.info, errExceptionAlreadyHandled)
@@ -261,8 +251,7 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil)
elif a.len == 1:
# count number of ``except: body`` blocks
inc catchAllExcepts
message(c.config, a.info, warnBareExcept,
"The bare except clause is deprecated; use `except CatchableError:` instead")
else:
# support ``except KeyError, ValueError, ... : body``
if catchAllExcepts > 0:
@@ -419,6 +408,13 @@ proc semUsing(c: PContext; n: PNode): PNode =
if a[^1].kind != nkEmpty:
localError(c.config, a.info, "'using' sections cannot contain assignments")
proc hasEmpty(typ: PType): bool =
if typ.kind in {tySequence, tyArray, tySet}:
result = typ.lastSon.kind == tyEmpty
elif typ.kind == tyTuple:
for s in typ.sons:
result = result or hasEmpty(s)
proc hasUnresolvedParams(n: PNode; flags: TExprFlags): bool =
result = tfUnresolved in n.typ.flags
when false:
@@ -726,12 +722,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
if v.kind == skLet and sfImportc notin v.flags and (strictDefs notin c.features or not isLocalSym(v)):
localError(c.config, a.info, errLetNeedsInit)
if sfCompileTime in v.flags:
if a.kind != nkVarTuple:
var x = newNodeI(result.kind, v.info)
x.add result[i]
vm.setupCompileTimeVar(c.module, c.idgen, c.graph, x)
else:
localError(c.config, a.info, "cannot destructure to compile time variable")
var x = newNodeI(result.kind, v.info)
x.add result[i]
vm.setupCompileTimeVar(c.module, c.idgen, c.graph, x)
if v.flags * {sfGlobal, sfThread} == {sfGlobal}:
message(c.config, v.info, hintGlobalVar)
if {sfGlobal, sfPure} <= v.flags:
@@ -1692,7 +1685,7 @@ proc semProcAnnotation(c: PContext, prc: PNode;
return result
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
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
@@ -1779,7 +1772,7 @@ proc whereToBindTypeHook(c: PContext; t: PType): PType =
proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
let t = s.typ
var noError = false
let cond = if op in {attachedDestructor, attachedWasMoved}:
let cond = if op == attachedDestructor:
t.len == 2 and t[0] == nil and t[1].kind == tyVar
elif op == attachedTrace:
t.len == 3 and t[0] == nil and t[1].kind == tyVar and t[2].kind == tyPointer
@@ -1894,9 +1887,6 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
of "=trace":
if s.magic != mTrace:
bindTypeHook(c, s, n, attachedTrace)
of "=wasmoved":
if s.magic != mWasMoved:
bindTypeHook(c, s, n, attachedWasMoved)
else:
if sfOverriden in s.flags:
localError(c.config, n.info, errGenerated,
@@ -2161,7 +2151,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if s.kind notin {skMacro, skTemplate} and s.magic == mNone: paramsTypeCheck(c, s.typ)
maybeAddResult(c, s, n)
let resultType =
let resultType =
if s.kind == skMacro:
sysTypeFromName(c.graph, n.info, "NimNode")
elif not isInlineIterator(s.typ):

View File

@@ -642,9 +642,8 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
# body by the absence of the sfGenSym flag:
for i in 1..<s.typ.n.len:
let param = s.typ.n[i].sym
if param.name.s != "_":
param.flags.incl sfTemplateParam
param.flags.excl sfGenSym
param.flags.incl sfTemplateParam
param.flags.excl sfGenSym
if param.typ.kind != tyUntyped: allUntyped = false
else:
s.typ = newTypeS(tyProc, c)

View File

@@ -73,7 +73,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
rawAddSon(result, base)
let isPure = result.sym != nil and sfPure in result.sym.flags
var symbols: TStrTable
initStrTable(symbols)
if isPure: initStrTable(symbols)
var hasNull = false
for i in 1..<n.len:
if n[i].kind == nkEmpty: continue
@@ -145,7 +145,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
addInterfaceOverloadableSymAt(c, c.currentScope, e)
else:
declarePureEnumField(c, e)
if (let conflict = strTableInclReportConflict(symbols, e); conflict != nil):
if isPure and (let conflict = strTableInclReportConflict(symbols, e); conflict != nil):
wrongRedefinition(c, e.info, e.name.s, conflict.info)
inc(counter)
if isPure and sfExported in result.sym.flags:
@@ -222,11 +222,9 @@ proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool =
proc fitDefaultNode(c: PContext, n: PNode): PType =
let expectedType = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil
let oldType = n[^1].typ
n[^1] = semConstExpr(c, n[^1], expectedType = expectedType)
n[^1].flags.incl nfSem
if n[^2].kind != nkEmpty:
if expectedType != nil and oldType != expectedType:
if expectedType != nil:
n[^1] = fitNodeConsiderViewType(c, expectedType, n[^1], n[^1].info)
result = n[^1].typ
else:
@@ -330,8 +328,6 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
proc semArrayIndex(c: PContext, n: PNode): PType =
if isRange(n):
result = semRangeAux(c, n, nil)
elif n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "..<":
result = errorType(c)
else:
let e = semExprWithType(c, n, {efDetermineType})
if e.typ.kind == tyFromExpr:
@@ -519,7 +515,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
let fSym = newSymNode(field)
if hasDefaultField:
fSym.sym.ast = a[^1]
fSym.sym.ast.flags.incl nfSkipFieldChecking
fSym.sym.ast.flags.incl nfUseDefaultField
result.n.add fSym
addSonSkipIntLit(result, typ, c.idgen)
styleCheckDef(c, a[j].info, field)
@@ -868,7 +864,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
let fSym = newSymNode(f)
if hasDefaultField:
fSym.sym.ast = n[^1]
fSym.sym.ast.flags.incl nfSkipFieldChecking
fSym.sym.ast.flags.incl nfUseDefaultField
if a.kind == nkEmpty: father.add fSym
else: a.add fSym
styleCheckDef(c, f)
@@ -1312,15 +1308,13 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if hasDefault:
def = a[^1]
block determineType:
var defTyp = typ
if genericParams != nil and genericParams.len > 0:
defTyp = nil
def = semGenericStmt(c, def)
if hasUnresolvedArgs(c, def):
def.typ = makeTypeFromExpr(c, def.copyTree)
break determineType
def = semExprWithType(c, def, {efDetermineType}, defTyp)
def = semExprWithType(c, def, {efDetermineType})
if def.referencesAnotherParam(getCurrOwner(c)):
def.flags.incl nfDefaultRefsParam
@@ -1376,9 +1370,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
inc(counter)
if def != nil and def.kind != nkEmpty:
arg.ast = copyTree(def)
if arg.name.s == "_":
arg.flags.incl(sfGenSym)
elif containsOrIncl(check, arg.name.id):
if containsOrIncl(check, arg.name.id):
localError(c.config, a[j].info, "attempt to redefine: '" & arg.name.s & "'")
result.n.add newSymNode(arg)
rawAddSon(result, finalType)

View File

@@ -193,24 +193,6 @@ proc replaceObjBranches(cl: TReplTypeVars, n: PNode): PNode =
for i in 0..<n.len:
n[i] = replaceObjBranches(cl, n[i])
proc hasValuelessStatics(n: PNode): bool =
# We should only attempt to call an expression that has no tyStatics
# As those are unresolved generic parameters, which means in the following
# The compiler attempts to do `T == 300` which errors since the typeclass `MyThing` lacks a parameter
#[
type MyThing[T: static int] = object
when T == 300:
a
proc doThing(_: MyThing)
]#
if n.safeLen == 0:
n.typ.kind == tyStatic
else:
for x in n:
if hasValuelessStatics(x):
return true
false
proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
if n == nil: return
result = copyNode(n)
@@ -235,11 +217,10 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
of nkElifBranch:
checkSonsLen(it, 2, cl.c.config)
var cond = prepareNode(cl, it[0])
if not cond.hasValuelessStatics:
var e = cl.c.semConstExpr(cl.c, cond)
if e.kind != nkIntLit:
internalError(cl.c.config, e.info, "ReplaceTypeVarsN: when condition not a bool")
if e.intVal != 0 and branch == nil: branch = it[1]
var e = cl.c.semConstExpr(cl.c, cond)
if e.kind != nkIntLit:
internalError(cl.c.config, e.info, "ReplaceTypeVarsN: when condition not a bool")
if e.intVal != 0 and branch == nil: branch = it[1]
of nkElse:
checkSonsLen(it, 1, cl.c.config)
if branch == nil: branch = it[0]

View File

@@ -9,12 +9,10 @@
## Computes hash values for routine (proc, method etc) signatures.
import ast, tables, ropes, md5, modulegraphs, options, msgs, packages, pathutils
import ast, tables, ropes, md5_old, modulegraphs
from hashes import Hash
import types
import std/os
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -44,7 +42,8 @@ type
CoDistinct
CoHashTypeInsideNode
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: ConfigRef)
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag])
proc hashSym(c: var MD5Context, s: PSym) =
if sfAnon in s.flags or s.kind == skGenericParam:
c &= ":anon"
@@ -55,21 +54,20 @@ proc hashSym(c: var MD5Context, s: PSym) =
c &= "."
it = it.owner
proc hashTypeSym(c: var MD5Context, s: PSym; conf: ConfigRef) =
proc hashTypeSym(c: var MD5Context, s: PSym) =
if sfAnon in s.flags or s.kind == skGenericParam:
c &= ":anon"
else:
var it = s
c &= customPath(conf.toFullPath(s.info))
while it != nil:
if sfFromGeneric in it.flags and it.kind in routineKinds and
it.typ != nil:
hashType c, it.typ, {CoProc}, conf
hashType c, it.typ, {CoProc}
c &= it.name.s
c &= "."
it = it.owner
proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]; conf: ConfigRef) =
proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]) =
if n == nil:
c &= "\255"
return
@@ -84,7 +82,7 @@ proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]; conf: Confi
of nkSym:
hashSym(c, n.sym)
if CoHashTypeInsideNode in flags and n.sym.typ != nil:
hashType(c, n.sym.typ, flags, conf)
hashType(c, n.sym.typ, flags)
of nkCharLit..nkUInt64Lit:
let v = n.intVal
lowlevel v
@@ -94,9 +92,9 @@ proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]; conf: Confi
of nkStrLit..nkTripleStrLit:
c &= n.strVal
else:
for i in 0..<n.len: hashTree(c, n[i], flags, conf)
for i in 0..<n.len: hashTree(c, n[i], flags)
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: ConfigRef) =
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
if t == nil:
c &= "\254"
return
@@ -104,14 +102,14 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
case t.kind
of tyGenericInvocation:
for i in 0..<t.len:
c.hashType t[i], flags, conf
c.hashType t[i], flags
of tyDistinct:
if CoDistinct in flags:
if t.sym != nil: c.hashSym(t.sym)
if t.sym == nil or tfFromGeneric in t.flags:
c.hashType t.lastSon, flags, conf
c.hashType t.lastSon, flags
elif CoType in flags or t.sym == nil:
c.hashType t.lastSon, flags, conf
c.hashType t.lastSon, flags
else:
c.hashSym(t.sym)
of tyGenericInst:
@@ -121,15 +119,15 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
# value for each instantiation, so we hash the generic parameters here:
let normalizedType = t.skipGenericAlias
for i in 0..<normalizedType.len - 1:
c.hashType t[i], flags, conf
c.hashType t[i], flags
else:
c.hashType t.lastSon, flags, conf
c.hashType t.lastSon, flags
of tyAlias, tySink, tyUserTypeClasses, tyInferred:
c.hashType t.lastSon, flags, conf
c.hashType t.lastSon, flags
of tyOwned:
if CoConsiderOwned in flags:
c &= char(t.kind)
c.hashType t.lastSon, flags, conf
c.hashType t.lastSon, flags
of tyBool, tyChar, tyInt..tyUInt64:
# no canonicalization for integral types, so that e.g. ``pid_t`` is
# produced instead of ``NI``:
@@ -143,7 +141,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
t.typeInst = nil
assert inst.kind == tyGenericInst
for i in 0..<inst.len - 1:
c.hashType inst[i], flags, conf
c.hashType inst[i], flags
t.typeInst = inst
return
c &= char(t.kind)
@@ -155,7 +153,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
# The user has set a specific name for this type
c &= t.sym.loc.r
elif CoOwnerSig in flags:
c.hashTypeSym(t.sym, conf)
c.hashTypeSym(t.sym)
else:
c.hashSym(t.sym)
@@ -174,7 +172,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
# xxx instead, use a hash table to indicate we've already visited a type, which
# would also be more efficient.
symWithFlags.flags.excl {sfAnon, sfGenSym}
hashTree(c, t.n, flags + {CoHashTypeInsideNode}, conf)
hashTree(c, t.n, flags + {CoHashTypeInsideNode})
symWithFlags.flags = oldFlags
else:
# The object has no fields: we _must_ add something here in order to
@@ -184,15 +182,15 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
else:
c &= t.id
if t.len > 0 and t[0] != nil:
hashType c, t[0], flags, conf
hashType c, t[0], flags
of tyRef, tyPtr, tyGenericBody, tyVar:
c &= char(t.kind)
if t.sons.len > 0:
c.hashType t.lastSon, flags, conf
c.hashType t.lastSon, flags
if tfVarIsPtr in t.flags: c &= ".varisptr"
of tyFromExpr:
c &= char(t.kind)
c.hashTree(t.n, {}, conf)
c.hashTree(t.n, {})
of tyTuple:
c &= char(t.kind)
if t.n != nil and CoType notin flags:
@@ -201,19 +199,19 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
assert(t.n[i].kind == nkSym)
c &= t.n[i].sym.name.s
c &= ':'
c.hashType(t[i], flags+{CoIgnoreRange}, conf)
c.hashType(t[i], flags+{CoIgnoreRange})
c &= ','
else:
for i in 0..<t.len: c.hashType t[i], flags+{CoIgnoreRange}, conf
for i in 0..<t.len: c.hashType t[i], flags+{CoIgnoreRange}
of tyRange:
if CoIgnoreRange notin flags:
c &= char(t.kind)
c.hashTree(t.n, {}, conf)
c.hashType(t[0], flags, conf)
c.hashTree(t.n, {})
c.hashType(t[0], flags)
of tyStatic:
c &= char(t.kind)
c.hashTree(t.n, {}, conf)
c.hashType(t[0], flags, conf)
c.hashTree(t.n, {})
c.hashType(t[0], flags)
of tyProc:
c &= char(t.kind)
c &= (if tfIterator in t.flags: "iterator " else: "proc ")
@@ -223,11 +221,11 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
let param = params[i].sym
c &= param.name.s
c &= ':'
c.hashType(param.typ, flags, conf)
c.hashType(param.typ, flags)
c &= ','
c.hashType(t[0], flags, conf)
c.hashType(t[0], flags)
else:
for i in 0..<t.len: c.hashType(t[i], flags, conf)
for i in 0..<t.len: c.hashType(t[i], flags)
c &= char(t.callConv)
# purity of functions doesn't have to affect the mangling (which is in fact
# problematic for HCR - someone could have cached a pointer to another
@@ -239,10 +237,10 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
if tfVarargs in t.flags: c &= ".varargs"
of tyArray:
c &= char(t.kind)
for i in 0..<t.len: c.hashType(t[i], flags-{CoIgnoreRange}, conf)
for i in 0..<t.len: c.hashType(t[i], flags-{CoIgnoreRange})
else:
c &= char(t.kind)
for i in 0..<t.len: c.hashType(t[i], flags, conf)
for i in 0..<t.len: c.hashType(t[i], flags)
if tfNotNil in t.flags and CoType notin flags: c &= "not nil"
when defined(debugSigHashes):
@@ -259,19 +257,19 @@ when defined(debugSigHashes):
# select hash, type from sighashes where hash in
# (select hash from sighashes group by hash having count(*) > 1) order by hash;
proc hashType*(t: PType; conf: ConfigRef; flags: set[ConsiderFlag] = {CoType}): SigHash =
proc hashType*(t: PType; flags: set[ConsiderFlag] = {CoType}): SigHash =
var c: MD5Context
md5Init c
hashType c, t, flags+{CoOwnerSig}, conf
hashType c, t, flags+{CoOwnerSig}
md5Final c, result.MD5Digest
when defined(debugSigHashes):
db.exec(sql"INSERT OR IGNORE INTO sighashes(type, hash) VALUES (?, ?)",
typeToString(t), $result)
proc hashProc*(s: PSym; conf: ConfigRef): SigHash =
proc hashProc*(s: PSym): SigHash =
var c: MD5Context
md5Init c
hashType c, s.typ, {CoProc}, conf
hashType c, s.typ, {CoProc}
var m = s
while m.kind != skModule: m = m.owner
@@ -317,9 +315,9 @@ proc hashOwner*(s: PSym): SigHash =
md5Final c, result.MD5Digest
proc sigHash*(s: PSym; conf: ConfigRef): SigHash =
proc sigHash*(s: PSym): SigHash =
if s.kind in routineKinds and s.typ != nil:
result = hashProc(s, conf)
result = hashProc(s)
else:
result = hashNonProc(s)
@@ -380,7 +378,7 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash =
var c: MD5Context
md5Init(c)
c.hashType(sym.typ, {CoProc}, graph.config)
c.hashType(sym.typ, {CoProc})
c &= char(sym.kind)
c.md5Final(result.MD5Digest)
graph.symBodyHashes[sym.id] = result # protect from recursion in the body
@@ -393,12 +391,12 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash =
graph.symBodyHashes[sym.id] = result
proc idOrSig*(s: PSym, currentModule: string,
sigCollisions: var CountTable[SigHash]; conf: ConfigRef): Rope =
sigCollisions: var CountTable[SigHash]): Rope =
if s.kind in routineKinds and s.typ != nil:
# signatures for exported routines are reliable enough to
# produce a unique name and this means produced C++ is more stable regarding
# Nim changes:
let sig = hashProc(s, conf)
let sig = hashProc(s)
result = rope($sig)
#let m = if s.typ.callConv != ccInline: findPendingModule(m, s) else: m
let counter = sigCollisions.getOrDefault(sig)

View File

@@ -322,32 +322,26 @@ proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
else:
result = arg.typ.typeToString(prefer)
template describeArgImpl(c: PContext, n: PNode, i: int, startIdx = 1; prefer = preferName) =
var arg = n[i]
if n[i].kind == nkExprEqExpr:
result.add renderTree(n[i][0])
result.add ": "
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
# XXX we really need to 'tryExpr' here!
arg = c.semOperand(c, n[i][1])
n[i].typ = arg.typ
n[i][1] = arg
else:
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo, nkElse,
nkOfBranch, nkElifBranch,
nkExceptBranch}:
arg = c.semOperand(c, n[i])
n[i] = arg
if arg.typ != nil and arg.typ.kind == tyError: return
result.add argTypeToString(arg, prefer)
proc describeArg*(c: PContext, n: PNode, i: int, startIdx = 1; prefer = preferName): string =
describeArgImpl(c, n, i, startIdx, prefer)
proc describeArgs*(c: PContext, n: PNode, startIdx = 1; prefer = preferName): string =
result = ""
for i in startIdx..<n.len:
describeArgImpl(c, n, i, startIdx, prefer)
var arg = n[i]
if n[i].kind == nkExprEqExpr:
result.add renderTree(n[i][0])
result.add ": "
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
# XXX we really need to 'tryExpr' here!
arg = c.semOperand(c, n[i][1])
n[i].typ = arg.typ
n[i][1] = arg
else:
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo, nkElse,
nkOfBranch, nkElifBranch,
nkExceptBranch}:
arg = c.semOperand(c, n[i])
n[i] = arg
if arg.typ != nil and arg.typ.kind == tyError: return
result.add argTypeToString(arg, prefer)
if i != n.len - 1: result.add ", "
proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType =
@@ -1840,9 +1834,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
elif f.base.kind == tyNone:
result = isGeneric
else:
let r = typeRel(c, f.base, a.base, flags)
if r >= isIntConv:
result = r
result = typeRel(c, f.base, a.base, flags)
if result != isNone:
put(c, f, a)
@@ -1850,9 +1842,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
if tfUnresolved in f.flags:
result = typeRel(c, prev.base, a, flags)
elif a.kind == tyTypeDesc:
let r = typeRel(c, prev.base, a.base, flags)
if r >= isIntConv:
result = r
result = typeRel(c, prev.base, a.base, flags)
else:
result = isNone
@@ -1979,7 +1969,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
if srca == isSubtype:
param = implicitConv(nkHiddenSubConv, src, copyTree(arg), m, c)
elif src.kind in {tyVar}:
# Analyse the converter return type.
# Analyse the converter return type
param = newNodeIT(nkHiddenAddr, arg.info, s.typ[1])
param.add copyTree(arg)
else:
@@ -2065,7 +2055,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
a.n == nil and
tfGenericTypeParam notin a.flags:
return newNodeIT(nkType, argOrig.info, makeTypeFromExpr(c, arg))
elif arg.kind != nkEmpty:
else:
var evaluated = c.semTryConstExpr(c, arg)
if evaluated != nil:
# Don't build the type in-place because `evaluated` and `arg` may point
@@ -2160,8 +2150,6 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
elif arg.sym.kind in {skMacro, skTemplate}:
return nil
else:
if arg.sym.ast == nil:
return nil
let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info)
result = newSymNode(inferred, arg.info)
if r == isInferredConvertible:
@@ -2671,9 +2659,11 @@ proc argtypeMatches*(c: PContext, f, a: PType, fromHlo = false): bool =
# pattern templates do not allow for conversions except from int literal
res != nil and m.convMatches == 0 and m.intConvMatches in [0, 256]
when not defined(nimHasSinkInference):
{.pragma: nosinks.}
proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
op: TTypeAttachedOp; col: int): PSym =
op: TTypeAttachedOp; col: int): PSym {.nosinks.} =
var m = newCandidate(c, dc.typ)
if col >= dc.typ.len:
localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'")

View File

@@ -164,7 +164,7 @@ func toSourceMap*(info: SourceInfo, file: string): SourceMap {.raises: [].} =
result.names = info.names
# Convert nodes into mappings.
# Mappings are split into blocks where each block referes to a line in the outputted JS.
# Blocks can be separated into statements which refere to tokens on the line.
# Blocks can be seperated into statements which refere to tokens on the line.
# Since the mappings depend on previous values we need to
# keep track of previous file, name, etc
var

View File

@@ -36,7 +36,7 @@ import algorithm, sets, prefixmatches, parseutils, tables
from wordrecg import wDeprecated, wError, wAddr, wYield
when defined(nimsuggest):
import tables, pathutils # importer
import passes, tables, pathutils # importer
const
sep = '\t'
@@ -120,9 +120,7 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int
proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo;
quality: range[0..100]; prefix: PrefixMatch;
inTypeContext: bool; scope: int;
useSuppliedInfo = false,
endLine: uint16 = 0,
endCol = 0): Suggest =
useSuppliedInfo = false): Suggest =
new(result)
result.section = section
result.quality = quality
@@ -178,8 +176,6 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info
else:
getTokenLenFromSource(g.config, s.name.s, infox)
result.version = g.config.suggestVersion
result.endLine = endLine
result.endCol = endCol
proc `$`*(suggest: Suggest): string =
result = $suggest.section
@@ -220,12 +216,6 @@ proc `$`*(suggest: Suggest): string =
result.add(sep)
result.add($suggest.prefix)
if (suggest.version == 3 and suggest.section in {ideOutline, ideExpand}):
result.add(sep)
result.add($suggest.endLine)
result.add(sep)
result.add($suggest.endCol)
proc suggestResult*(conf: ConfigRef; s: Suggest) =
if not isNil(conf.suggestionResultHook):
conf.suggestionResultHook(s)
@@ -299,7 +289,7 @@ proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var
s.getQuality, pm, c.inTypeContext > 0, 0))
template wholeSymTab(cond, section: untyped) {.dirty.} =
for (item, scopeN, isLocal) in uniqueSyms(c):
for (item, scopeN, isLocal) in allSyms(c):
let it = item
var pm: PrefixMatch
if cond:
@@ -372,7 +362,7 @@ proc suggestOperations(c: PContext, n, f: PNode, typ: PType, outputs: var Sugges
proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) =
# do not produce too many symbols:
for (it, scopeN, isLocal) in uniqueSyms(c):
for (it, scopeN, isLocal) in allSyms(c):
var pm: PrefixMatch
if filterSym(it, f, pm):
outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, ideSug, n.info,
@@ -690,7 +680,7 @@ proc suggestSentinel*(c: PContext) =
inc(c.compilesContextId)
var outputs: Suggestions = @[]
# suggest everything:
for (it, scopeN, isLocal) in uniqueSyms(c):
for (it, scopeN, isLocal) in allSyms(c):
var pm: PrefixMatch
if filterSymNoOpr(it, nil, pm):
outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, ideSug,

View File

@@ -31,7 +31,7 @@ type
TransformBodyFlag* = enum
dontUseCache, useCache
proc transformBody*(g: ModuleGraph; idgen: IdGenerator, prc: PSym, flag: TransformBodyFlag, force = false): PNode
proc transformBody*(g: ModuleGraph; idgen: IdGenerator, prc: PSym, flag: TransformBodyFlag): PNode
import closureiters, lambdalifting
@@ -50,7 +50,6 @@ type
module: PSym
transCon: PTransCon # top of a TransCon stack
inlining: int # > 0 if we are in inlining context (copy vars)
isIntroducingNewLocalVars: bool # true if we are in `introducingNewLocalVars` (don't transform yields)
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
deferDetected, tooEarly: bool
graph: ModuleGraph
@@ -451,9 +450,7 @@ proc transformYield(c: PTransf, n: PNode): PNode =
result.add(c.transCon.forLoopBody)
else:
# we need to introduce new local variables:
c.isIntroducingNewLocalVars = true # don't transform yields when introducing new local vars
result.add(introduceNewLocalVars(c, c.transCon.forLoopBody))
c.isIntroducingNewLocalVars = false
for idx in 0 ..< result.len:
var changeNode = result[idx]
@@ -1039,7 +1036,7 @@ proc transform(c: PTransf, n: PNode): PNode =
else:
result = transformSons(c, n)
of nkYieldStmt:
if c.inlining > 0 and not c.isIntroducingNewLocalVars:
if c.inlining > 0:
result = transformYield(c, n)
else:
result = transformSons(c, n)
@@ -1148,7 +1145,7 @@ template liftDefer(c, root) =
if c.deferDetected:
liftDeferAux(root)
proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flag: TransformBodyFlag, force = false): PNode =
proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flag: TransformBodyFlag): PNode =
assert prc.kind in routineKinds
if prc.transformedBody != nil:
@@ -1158,7 +1155,7 @@ proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flag: Transfo
else:
prc.transformedBody = newNode(nkEmpty) # protects from recursion
var c = openTransf(g, prc.getModule, "", idgen)
result = liftLambdas(g, prc, getBody(g, prc), c.tooEarly, c.idgen, force)
result = liftLambdas(g, prc, getBody(g, prc), c.tooEarly, c.idgen)
result = processTransf(c, result, prc)
liftDefer(c, result)
result = liftLocalsIfRequested(prc, result, g.cache, g.config, c.idgen)

View File

@@ -1721,18 +1721,6 @@ proc isDefectException*(t: PType): bool =
t = skipTypes(t[0], abstractPtrs)
return false
proc isDefectOrCatchableError*(t: PType): bool =
var t = t.skipTypes(abstractPtrs)
while t.kind == tyObject:
if t.sym != nil and t.sym.owner != nil and
sfSystemModule in t.sym.owner.flags and
(t.sym.name.s == "Defect" or
t.sym.name.s == "CatchableError"):
return true
if t[0] == nil: break
t = skipTypes(t[0], abstractPtrs)
return false
proc isSinkTypeForParam*(t: PType): bool =
# a parameter like 'seq[owned T]' must not be used only once, but its
# elements must, so we detect this case here:

View File

@@ -10,10 +10,10 @@
## This file implements the new evaluation engine for Nim code.
## An instruction is 1-3 int32s in memory, it is a register based VM.
import semmacrosanity
import
std/[strutils, tables, parseutils],
msgs, vmdef, vmgen, nimsets, types,
msgs, vmdef, vmgen, nimsets, types, passes,
parser, vmdeps, idents, trees, renderer, options, transf,
gorgeimpl, lineinfos, btrees, macrocacheimpl,
modulegraphs, sighashes, int128, vmprofiler
@@ -32,6 +32,8 @@ const
when hasFFI:
import evalffi
when not defined(nimHasCursor):
{.pragma: cursor.}
proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
if x != nil:
@@ -531,6 +533,9 @@ template maybeHandlePtr(node2: PNode, reg: TFullReg, isAssign2: bool): bool =
else:
false
when not defined(nimHasSinkInference):
{.pragma: nosinks.}
template takeAddress(reg, source) =
reg.nodeAddr = addr source
GC_ref source
@@ -1271,7 +1276,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let ast = a.sym.ast.shallowCopy
for i in 0..<a.sym.ast.len:
ast[i] = a.sym.ast[i]
ast[bodyPos] = transformBody(c.graph, c.idgen, a.sym, useCache, force=true)
ast[bodyPos] = transformBody(c.graph, c.idgen, a.sym, useCache)
ast.copyTree()
of opcSymOwner:
decodeB(rkNode)
@@ -1351,7 +1356,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let prc = if not isClosure: bb.sym else: bb[0].sym
if prc.offset < -1:
# it's a callback:
c.callbacks[-prc.offset-2](
c.callbacks[-prc.offset-2].value(
VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[ptr UncheckedArray[TFullReg]](addr regs[0]),
currentException: c.currentExceptionA,
currentLineInfo: c.debug[pc])
@@ -1408,9 +1413,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
for i in 1..rc-1:
let node = regs[rb+i].regToNode
node.info = c.debug[pc]
if prc.typ[i].kind notin {tyTyped, tyUntyped}:
node.annotateType(prc.typ[i], c.config)
macroCall.add(node)
var a = evalTemplate(macroCall, prc, genSymOwner, c.config, c.cache, c.templInstCounter, c.idgen)
if a.kind == nkStmtList and a.len == 1: a = a[0]
@@ -1606,7 +1608,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcRepr:
decodeB(rkNode)
createStr regs[ra]
regs[ra].node.strVal = renderTree(regs[rb].regToNode, {renderNoComments, renderDocComments, renderNonExportedFields})
regs[ra].node.strVal = renderTree(regs[rb].regToNode, {renderNoComments, renderDocComments})
of opcQuit:
if c.mode in {emRepl, emStaticExpr, emStaticStmt}:
message(c.config, c.debug[pc], hintQuitCalled)
@@ -1677,7 +1679,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
rb = instr.regB
rc = instr.regC
idx = int(regs[rb+rc-1].intVal)
callback = c.callbacks[idx]
callback = c.callbacks[idx].value
args = VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[ptr UncheckedArray[TFullReg]](addr regs[0]),
currentException: c.currentExceptionA,
currentLineInfo: c.debug[pc])
@@ -1855,7 +1857,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[rb].node.kind != nkSym:
stackTrace(c, tos, pc, "node is not a symbol")
else:
regs[ra].node.strVal = $sigHash(regs[rb].node.sym, c.config)
regs[ra].node.strVal = $sigHash(regs[rb].node.sym)
of opcSlurp:
decodeB(rkNode)
createStr regs[ra]
@@ -1893,7 +1895,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var error: string
let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
regs[rc].node.strVal, 0,
proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) {.nosinks.} =
if error.len == 0 and msg <= errMax:
error = formatMsg(conf, info, msg, arg))
if error.len > 0:
@@ -1908,7 +1910,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var error: string
let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
regs[rc].node.strVal, 0,
proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) {.nosinks.} =
if error.len == 0 and msg <= errMax:
error = formatMsg(conf, info, msg, arg))
if error.len > 0:
@@ -1932,24 +1934,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of 1: # getLine
regs[ra].node = newIntNode(nkIntLit, n.info.line.int)
of 2: # getColumn
regs[ra].node = newIntNode(nkIntLit, n.info.col.int)
regs[ra].node = newIntNode(nkIntLit, n.info.col)
else:
internalAssert c.config, false
regs[ra].node.info = n.info
regs[ra].node.typ = n.typ
of opcNCopyLineInfo:
of opcNSetLineInfo:
decodeB(rkNode)
regs[ra].node.info = regs[rb].node.info
of opcNSetLineInfoLine:
decodeB(rkNode)
regs[ra].node.info.line = regs[rb].intVal.uint16
of opcNSetLineInfoColumn:
decodeB(rkNode)
regs[ra].node.info.col = regs[rb].intVal.int16
of opcNSetLineInfoFile:
decodeB(rkNode)
regs[ra].node.info.fileIndex =
fileInfoIdx(c.config, RelativeFile regs[rb].node.strVal)
of opcEqIdent:
decodeBC(rkInt)
# aliases for shorter and easier to understand code below
@@ -2074,6 +2066,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
dest.ident = regs[rb].node.ident
else:
stackTrace(c, tos, pc, errFieldXNotFound & "ident")
of opcNSetType:
decodeB(rkNode)
let b = regs[rb].node
internalAssert c.config, b.kind == nkSym and b.sym.kind == skType
internalAssert c.config, regs[ra].node != nil
regs[ra].node.typ = b.sym.typ
of opcNSetStrVal:
decodeB(rkNode)
var dest = regs[ra].node
@@ -2309,7 +2307,7 @@ proc setupGlobalCtx*(module: PSym; graph: ModuleGraph; idgen: IdGenerator) =
else:
refresh(PCtx graph.vm, module, idgen)
proc setupEvalGen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} =
#var c = newEvalContext(module, emRepl)
#c.features = {allowCast, allowInfiniteLoops}
#pushStackFrame(c, newStackFrame())
@@ -2318,7 +2316,7 @@ proc setupEvalGen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassC
setupGlobalCtx(module, graph, idgen)
result = PCtx graph.vm
proc interpreterCode*(c: PPassContext, n: PNode): PNode =
proc myProcess(c: PPassContext, n: PNode): PNode =
let c = PCtx(c)
# don't eval errornous code:
if c.oldErrorCount == c.config.errorCounter:
@@ -2328,12 +2326,14 @@ proc interpreterCode*(c: PPassContext, n: PNode): PNode =
result = n
c.oldErrorCount = c.config.errorCounter
proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
result = myProcess(c, n)
const evalPass* = makePass(myOpen, myProcess, myClose)
proc evalConstExprAux(module: PSym; idgen: IdGenerator;
g: ModuleGraph; prc: PSym, n: PNode,
mode: TEvalMode): PNode =
when defined(nimsuggest):
if g.config.expandDone():
return n
#if g.config.errorCounter > 0: return n
let n = transformExpr(g, idgen, module, n)
setupGlobalCtx(module, g, idgen)

View File

@@ -10,7 +10,7 @@
## This module contains the type definitions for the new evaluation engine.
## An instruction is 1-3 int32s in memory, it is a register based VM.
import std/[tables, strutils]
import tables
import ast, idents, options, modulegraphs, lineinfos
@@ -127,7 +127,7 @@ type
opcNGetSize,
opcNSetIntVal,
opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetStrVal,
opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal,
opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree, opcNDel, opcGenSym,
opcNccValue, opcNccInc, opcNcsAdd, opcNcsIncl, opcNcsLen, opcNcsAt,
@@ -141,8 +141,7 @@ type
opcNError,
opcNWarning,
opcNHint,
opcNGetLineInfo, opcNCopyLineInfo, opcNSetLineInfoLine,
opcNSetLineInfoColumn, opcNSetLineInfoFile
opcNGetLineInfo, opcNSetLineInfo,
opcEqIdent,
opcStrToIdent,
opcGetImpl,
@@ -259,8 +258,7 @@ type
traceActive*: bool
loopIterations*: int
comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces
callbacks*: seq[VmCallback]
callbackIndex*: Table[string, int]
callbacks*: seq[tuple[key: string, value: VmCallback]]
errorFlag*: string
cache*: IdentCache
config*: ConfigRef
@@ -293,7 +291,7 @@ proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph; idgen: IdGenerator
PCtx(code: @[], debug: @[],
globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
prc: PProc(blocks: @[]), module: module, loopIterations: g.config.maxLoopIterationsVM,
comesFromHeuristic: unknownLineInfo, callbacks: @[], callbackIndex: initTable[string, int](), errorFlag: "",
comesFromHeuristic: unknownLineInfo, callbacks: @[], errorFlag: "",
cache: cache, config: g.config, graph: g, idgen: idgen)
proc refresh*(c: PCtx, module: PSym; idgen: IdGenerator) =
@@ -302,18 +300,9 @@ proc refresh*(c: PCtx, module: PSym; idgen: IdGenerator) =
c.loopIterations = c.config.maxLoopIterationsVM
c.idgen = idgen
proc reverseName(s: string): string =
result = newStringOfCap(s.len)
let y = s.split('.')
for i in 1..y.len:
result.add y[^i]
if i != y.len:
result.add '.'
proc registerCallback*(c: PCtx; name: string; callback: VmCallback): int {.discardable.} =
result = c.callbacks.len
c.callbacks.add(callback)
c.callbackIndex[reverseName(name)] = result
c.callbacks.add((name, callback))
const
firstABxInstr* = opcTJmp

View File

@@ -32,7 +32,7 @@ when defined(nimPreviewSlimSystem):
import std/assertions
import
strutils, ast, types, msgs, renderer, vmdef, trees,
strutils, ast, types, msgs, renderer, vmdef,
intsets, magicsys, options, lowerings, lineinfos, transf, astmsgs
from modulegraphs import getBody
@@ -1313,6 +1313,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mNSetIdent:
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetIdent)
of mNSetType:
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetType)
of mNSetStrVal:
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetStrVal)
@@ -1332,19 +1335,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of "copyLineInfo":
internalAssert c.config, n.len == 3
unused(c, n, dest)
genBinaryStmt(c, n, opcNCopyLineInfo)
of "setLine":
internalAssert c.config, n.len == 3
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetLineInfoLine)
of "setColumn":
internalAssert c.config, n.len == 3
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetLineInfoColumn)
of "setFile":
internalAssert c.config, n.len == 3
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetLineInfoFile)
genBinaryStmt(c, n, opcNSetLineInfo)
else: internalAssert c.config, false
of mNHint:
unused(c, n, dest)
@@ -1829,7 +1820,7 @@ proc getNullValueAux(t: PType; obj: PNode, result: PNode; conf: ConfigRef; currP
let field = newNodeI(nkExprColonExpr, result.info)
field.add(obj)
let value = getNullValue(obj.sym.typ, result.info, conf)
value.flags.incl nfSkipFieldChecking
value.flags.incl nfUseDefaultField
field.add(value)
result.add field
doAssert obj.sym.position == currPosition
@@ -1909,19 +1900,6 @@ proc genVarSection(c: PCtx; n: PNode) =
c.genAdditionalCopy(a[2], opcWrDeref, tmp, 0, val)
c.freeTemp(val)
c.freeTemp(tmp)
elif not importcCondVar(s) and not (s.typ.kind == tyProc and s.typ.callConv == ccClosure) and
sfPure notin s.flags: # fixes #10938
# there is a pre-existing issue with closure types in VM
# if `(var s: proc () = default(proc ()); doAssert s == nil)` works for you;
# you might remove the second condition.
# the problem is that closure types are tuples in VM, but the types of its children
# shouldn't have the same type as closure types.
let tmp = c.genx(a[0], {gfNodeAddr})
let sa = getNullValue(s.typ, a.info, c.config)
let val = c.genx(sa)
c.genAdditionalCopy(sa, opcWrDeref, tmp, 0, val)
c.freeTemp(val)
c.freeTemp(tmp)
else:
setSlot(c, s)
if a[2].kind == nkEmpty:
@@ -2024,29 +2002,25 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
proc genProc*(c: PCtx; s: PSym): int
proc toKey(s: PSym): string =
proc matches(s: PSym; x: string): bool =
let y = x.split('.')
var s = s
while s != nil:
result.add s.name.s
if s.owner != nil:
if sfFromGeneric in s.flags:
s = s.owner.owner
else:
s = s.owner
result.add "."
else:
break
for i in 1..y.len:
if s == nil or (y[^i].cmpIgnoreStyle(s.name.s) != 0 and y[^i] != "*"):
return false
s = if sfFromGeneric in s.flags: s.owner.owner else: s.owner
while s != nil and s.kind == skPackage and s.owner != nil: s = s.owner
result = true
proc procIsCallback(c: PCtx; s: PSym): bool =
if s.offset < -1: return true
let key = toKey(s)
if c.callbackIndex.contains(key):
let index = c.callbackIndex[key]
doAssert s.offset == -1
s.offset = -2 - index
result = true
else:
result = false
var i = -2
for key, value in items(c.callbacks):
if s.matches(key):
doAssert s.offset == -1
s.offset = i
return true
dec i
proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
when defined(nimCompilerStacktraceHints):
@@ -2067,10 +2041,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
genLit(c, n, dest)
of skConst:
let constVal = if s.astdef != nil: s.astdef else: s.typ.n
if dontInlineConstant(n, constVal):
genLit(c, constVal, dest)
else:
gen(c, constVal, dest)
gen(c, constVal, dest)
of skEnumField:
# we never reach this case - as of the time of this comment,
# skEnumField is folded to an int in semfold.nim, but this code

View File

@@ -36,9 +36,7 @@ from std/osproc import nil
when defined(nimPreviewSlimSystem):
import std/syncio
else:
from std/formatfloat import addFloatRoundtrip, addFloatSprintf
from std/strutils import formatBiggestFloat, FloatFormatMode
from std/formatfloat import addFloatRoundtrip, addFloatSprintf
# There are some useful procs in vmconv.
import vmconv, vmmarshal
@@ -143,40 +141,39 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode =
for k, f in walkDir(path, relative):
result.add toLit((k, f))
from std / compilesettings import SingleValueSetting, MultipleValueSetting
when defined(nimHasInvariant):
from std / compilesettings import SingleValueSetting, MultipleValueSetting
proc querySettingImpl(conf: ConfigRef, switch: BiggestInt): string =
{.push warning[Deprecated]:off.}
case SingleValueSetting(switch)
of arguments: result = conf.arguments
of outFile: result = conf.outFile.string
of outDir: result = conf.outDir.string
of nimcacheDir: result = conf.getNimcacheDir().string
of projectName: result = conf.projectName
of projectPath: result = conf.projectPath.string
of projectFull: result = conf.projectFull.string
of command: result = conf.command
of commandLine: result = conf.commandLine
of linkOptions: result = conf.linkOptions
of compileOptions: result = conf.compileOptions
of ccompilerPath: result = conf.cCompilerPath
of backend: result = $conf.backend
of libPath: result = conf.libpath.string
of gc: result = $conf.selectedGC
of mm: result = $conf.selectedGC
{.pop.}
proc querySettingImpl(conf: ConfigRef, switch: BiggestInt): string =
case SingleValueSetting(switch)
of arguments: result = conf.arguments
of outFile: result = conf.outFile.string
of outDir: result = conf.outDir.string
of nimcacheDir: result = conf.getNimcacheDir().string
of projectName: result = conf.projectName
of projectPath: result = conf.projectPath.string
of projectFull: result = conf.projectFull.string
of command: result = conf.command
of commandLine: result = conf.commandLine
of linkOptions: result = conf.linkOptions
of compileOptions: result = conf.compileOptions
of ccompilerPath: result = conf.cCompilerPath
of backend: result = $conf.backend
of libPath: result = conf.libpath.string
of gc: result = $conf.selectedGC
of mm: result = $conf.selectedGC
proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] =
template copySeq(field: untyped): untyped =
for i in field: result.add i.string
proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] =
template copySeq(field: untyped): untyped =
for i in field: result.add i.string
case MultipleValueSetting(switch)
of nimblePaths: copySeq(conf.nimblePaths)
of searchPaths: copySeq(conf.searchPaths)
of lazyPaths: copySeq(conf.lazyPaths)
of commandArgs: result = conf.commandArgs
of cincludes: copySeq(conf.cIncludes)
of clibs: copySeq(conf.cLibs)
case MultipleValueSetting(switch)
of nimblePaths: copySeq(conf.nimblePaths)
of searchPaths: copySeq(conf.searchPaths)
of lazyPaths: copySeq(conf.lazyPaths)
of commandArgs: result = conf.commandArgs
of cincludes: copySeq(conf.cIncludes)
of clibs: copySeq(conf.cLibs)
proc stackTrace2(c: PCtx, msg: string, n: PNode) =
stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr, msg, n.info)
@@ -256,12 +253,13 @@ proc registerAdditionalOps*(c: PCtx) =
wrap2si(readLines, ioop)
systemop getCurrentExceptionMsg
systemop getCurrentException
registerCallback c, "stdlib.osdirs.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1)))
registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) =
setResult(a, querySettingImpl(c.config, getInt(a, 0)))
registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) =
setResult(a, querySettingSeqImpl(c.config, getInt(a, 0)))
when defined(nimHasInvariant):
registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) =
setResult(a, querySettingImpl(c.config, getInt(a, 0)))
registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) =
setResult(a, querySettingSeqImpl(c.config, getInt(a, 0)))
if defined(nimsuggest) or c.config.cmd == cmdCheck:
discard "don't run staticExec for 'nim suggest'"
@@ -284,12 +282,6 @@ proc registerAdditionalOps*(c: PCtx) =
stackTrace2(c, "isExported() requires a symbol. '$#' is of kind '$#'" % [$n, $n.kind], n)
setResult(a, sfExported in n.sym.flags)
registerCallback c, "stdlib.macrocache.hasKey", proc (a: VmArgs) =
let
table = getString(a, 0)
key = getString(a, 1)
setResult(a, table in c.graph.cacheTables and key in c.graph.cacheTables[table])
registerCallback c, "stdlib.vmutils.vmTrace", proc (a: VmArgs) =
c.config.isVmTrace = getBool(a, 0)
@@ -382,10 +374,6 @@ proc registerAdditionalOps*(c: PCtx) =
let x = a.getFloat(1)
addFloatSprintf(p.strVal, x)
registerCallback c, "stdlib.strutils.formatBiggestFloat", proc(a: VmArgs) =
setResult(a, formatBiggestFloat(a.getFloat(0), FloatFormatMode(a.getInt(1)),
a.getInt(2), chr(a.getInt(3))))
wrapIterator("stdlib.envvars.envPairsImplSeq"): envPairs()
registerCallback c, "stdlib.marshal.toVM", proc(a: VmArgs) =

View File

@@ -130,7 +130,20 @@ const
wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile, wUsing}
from std/enumutils import genEnumCaseStmt
from strutils import normalize
proc findStr*[T: enum](a, b: static[T], s: string, default: T): T =
genEnumCaseStmt(T, s, default, ord(a), ord(b), normalize)
const enumUtilsExist = compiles:
import std/enumutils
when enumUtilsExist:
from std/enumutils import genEnumCaseStmt
from strutils import normalize
proc findStr*[T: enum](a, b: static[T], s: string, default: T): T =
genEnumCaseStmt(T, s, default, ord(a), ord(b), normalize)
else:
from strutils import cmpIgnoreStyle
proc findStr*[T: enum](a, b: static[T], s: string, default: T): T {.deprecated.} =
# used for compiler bootstrapping only
for i in a..b:
if cmpIgnoreStyle($i, s) == 0:
return i
result = default

View File

@@ -1,5 +1,5 @@
nim_comment="key-value pairs for windows/posix bootstrapping build scripts"
nim_csourcesDir=csources_v2
nim_csourcesUrl=https://github.com/nim-lang/csources_v2.git
nim_csourcesDir=csources_v1
nim_csourcesUrl=https://github.com/nim-lang/csources_v1.git
nim_csourcesBranch=master
nim_csourcesHash=86742fb02c6606ab01a532a0085784effb2e753e
nim_csourcesHash=561b417c65791cd8356b5f73620914ceff845d10

View File

@@ -39,7 +39,7 @@ arm64.linux.gcc.linkerexe = "aarch64-linux-gnu-gcc"
riscv32.linux.gcc.exe = "riscv64-linux-gnu-gcc"
riscv32.linux.gcc.linkerexe = "riscv64-linux-gnu-gcc"
riscv64.linux.gcc.exe = "riscv64-linux-gnu-gcc"
riscv64.linux.gcc.linkerexe = "riscv64-linux-gnu-gcc"
riscv64.linux.gcc.linkerexe = "arm-linux-gnueabihf-gcc"
# For OpenWRT, you will also need to adjust PATH to point to your toolchain.
mips.linux.gcc.exe = "mips-openwrt-linux-gcc"
@@ -100,11 +100,6 @@ nimblepath="$home/.nimble/pkgs/"
gcc.options.always %= "${gcc.options.always} -fsanitize=null -fsanitize-undefined-trap-on-error"
@end
# Turn off threads support when compiling for bare-metal targets (--os:any)
@if any:
threads:off
@end
@if unix and mingw:
# Cross compile for Windows from Linux/OSX using MinGW
i386.windows.gcc.exe = "i686-w64-mingw32-gcc"
@@ -186,9 +181,10 @@ nimblepath="$home/.nimble/pkgs/"
gcc.maxerrorsimpl = "-fmax-errors=3"
@if freebsd or netbsd:
@if freebsd:
tlsEmulation:off
@elif bsd:
# at least NetBSD has problems with thread local storage:
tlsEmulation:on
@end

View File

@@ -1,7 +1,7 @@
=====================================================
Nim -- a Compiler for Nim. https://nim-lang.org/
Copyright (C) 2006-2023 Andreas Rumpf. All rights reserved.
Copyright (C) 2006-2022 Andreas Rumpf. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -4,11 +4,8 @@ Advanced commands:
//compileToOC, objc compile project to Objective C code
//js compile project to Javascript
//e run a Nimscript file
//md2html convert a Markdown file to HTML
use `--docCmd:skip` to skip compiling snippets
//rst2html convert a reStructuredText file to HTML
use `--docCmd:skip` to skip compiling snippets
//md2tex convert a Markdown file to LaTeX
//rst2tex convert a reStructuredText file to LaTeX
//doc2tex extract the documentation to a LaTeX file
//jsondoc extract the documentation to a json file
@@ -133,9 +130,7 @@ Advanced options:
select which memory management to use; default is 'orc'
--exceptions:setjmp|cpp|goto|quirky
select the exception handling implementation
--index:on|off|only docgen: turn index file generation? (`only` means
not generate output files like HTML)
--noImportdoc:on|off disable loading documentation ``.idx`` files?
--index:on|off turn index file generation on|off
--putenv:key=value set an environment variable
--NimblePath:PATH add a path for Nimble support
--noNimblePath deactivate the Nimble path
@@ -172,6 +167,6 @@ Advanced options:
--useVersion:1.0|1.2|1.6 emulate Nim version X of the Nim compiler, for testing
--benchmarkVM:on|off turn benchmarking of VM code with cpuTime() on|off
--profileVM:on|off turn compile time VM profiler on|off
--sinkInference:on|off turn sink parameter inference on|off (default: off)
--sinkInference:on|off turn sink parameter inference on|off (default: on)
--panics:on|off turn panics into process terminations (default: off)
--deepcopy:on|off enable 'system.deepCopy' for ``--mm:arc|orc``

View File

@@ -9,7 +9,6 @@
.. include:: rstcommon.rst
.. contents::
.. importdoc:: markdown_rst.md, compiler/docgen.nim
Introduction
============
@@ -44,7 +43,6 @@ Generate HTML documentation for a whole project:
# or `$nimcache/htmldocs` with `--usenimcache` which avoids clobbering your sources;
# and likewise without `--project`.
# Adding `-r` will open in a browser directly.
# Use `--showNonExports` to show non-exported fields of an exported type.
```
Documentation Comments
@@ -105,64 +103,6 @@ won't influence RST formatting.
## Paragraph.
```
Structuring output directories
------------------------------
Basic directory for output is set by `--outdir:OUTDIR`:option: switch,
by default `OUTDIR` is ``htmldocs`` sub-directory in the directory of
the processed file.
There are 2 basic options as to how generated HTML output files are stored:
1) complex hierarchy when docgen-compiling with `--project`:option:,
which follows directory structure of the project itself.
So `nim doc`:cmd: replicates project's directory structure
inside `--outdir:OUTDIR`:option: directory.
`--project`:option: is well suited for projects that have 1 main module.
File name clashes are impossible in this case.
2) flattened structure, where user-provided script goes through all
needed input files and calls commands like `nim doc`:cmd:
with `--outdir:OUTDIR`:option: switch, thus putting all HTML (and
``.idx``) files into 1 directory.
.. Important:: Make sure that you don't have files with same base name
like ``x.nim`` and ``x.md`` in the same package, otherwise you'll
have name conflict for ``x.html``.
.. Tip:: To structure your output directories and avoid file name
clashes you can split your project into
different *packages* -- parts of your repository that are
docgen-compiled with different `--outdir:OUTDIR`:option: options.
An example of such strategy is Nim repository itself which has:
* its stdlib ``.nim`` files from different directories and ``.md``
documentation from ``doc/`` directory are all docgen-compiled
into `--outdir:web/upload/<version>/`:option: directory
* its ``.nim`` files from ``compiler/`` directory are docgen-compiled
into `--outdir:web/upload/<version>/compiler/`:option: directory.
Interestingly, it's compiled with complex hierarchy using
`--project`:option: switch.
Contents of ``web/upload/<version>`` are then deployed into Nim's
Web server.
This output directory structure allows to work correctly with files like
``compiler/docgen.nim`` (implementation) and ``doc/docgen.md`` (user
documentation) in 1 repository.
Index files
-----------
Index (``.idx``) files are used for 2 different purposes:
1. easy cross-referencing between different ``.nim`` and/or ``.md`` / ``.rst``
files described in [Nim external referencing]
2. creating a whole-project index for searching of symbols and keywords,
see [Buildindex command].
Document Types
==============
@@ -286,46 +226,13 @@ Note that the `jsondoc`:option: command outputs its JSON without pretty-printing
while `jsondoc0`:option: outputs pretty-printed JSON.
Simple documentation links
==========================
Referencing Nim symbols: simple documentation links
===================================================
It's possible to use normal Markdown/RST syntax to *manually*
reference Nim symbols using HTML anchors, however Nim has an *automatic*
facility that makes referencing inside ``.nim`` and ``.md/.rst`` files and
between them easy and seamless.
The point is that such links will be resolved automatically
by `nim doc`:cmd: (or `md2html`:option:, or `jsondoc`:option:,
or `doc2tex`:option:, ...). And, unlike manual links, such automatic
links **check** that their target exists -- a warning is emitted for
any broken link, so you avoid broken links in your project.
Nim treats both ``.md/.rst`` files and ``.nim`` modules (their doc comment
part) as *documents* uniformly.
Hence all directions of referencing are equally possible having the same syntax:
1. ``.md/rst`` -> itself (internal). See [Markup local referencing].
2. ``.md/rst`` -> external ``.md/rst``. See [Markup external referencing].
To summarize, referencing in `.md`/`.rst` files was already described in
[Nim-flavored Markdown and reStructuredText]
(particularly it described usage of index files for referencing),
while in this document we focus on Nim-specific details.
3. ``.md/rst`` -> external ``.nim``. See [Nim external referencing].
4. ``.nim`` -> itself (internal). See [Nim local referencing].
5. ``.nim`` -> external ``.md/rst``. See [Markup external referencing].
6. ``.nim`` -> external ``.nim``. See [Nim external referencing].
To put it shortly, local referencing always works out of the box,
external referencing requires to use ``.. importdoc:: <file>``
directive to import `file` and to ensure that the corresponding
``.idx`` file was generated.
Nim local referencing
---------------------
You can reference Nim identifiers from Nim documentation comments
inside their ``.nim`` file (or inside a ``.rst`` file included from
a ``.nim``).
You can reference Nim identifiers from Nim documentation comments, currently
only inside their ``.nim`` file (or inside a ``.rst`` file included from
a ``.nim``). The point is that such links will be resolved automatically
by `nim doc`:cmd: (or `nim jsondoc`:cmd: or `nim doc2tex`:cmd:).
This pertains to any exported symbol like `proc`, `const`, `iterator`, etc.
Syntax for referencing is basically a normal RST one: addition of
underscore `_` to a *link text*.
@@ -498,143 +405,6 @@ recognized fine:
...
## Ref. `CopyFlag enum`_
Nim external referencing
------------------------
Just like for [Markup external referencing], which saves markup anchors,
the Nim symbols are also saved in ``.idx`` files, so one needs
to generate them beforehand, and they should be loaded by
an ``.. importdoc::`` directive. Arguments to ``.. importdoc::`` is a
comma-separated list of Nim modules or Markdown/RST documents.
`--index:only`:option: tells Nim to only generate ``.idx`` file and
do **not** attempt to generate HTML/LaTeX output.
For ``.nim`` modules there are 2 alternatives to work with ``.idx`` files:
1. using [Project switch] implies generation of ``.idx`` files,
however, if ``importdoc`` is called on upper modules as its arguments,
their ``.idx`` are not yet created. Thus one should generate **all**
required ``.idx`` first:
```cmd
nim doc --project --index:only <main>.nim
nim doc --project <main>.nim
```
2. or run `nim doc --index:only <module.nim>`:cmd: command for **all** (used)
Nim modules in your project. Then run `nim doc <module.nim>` on them for
output HTML generation.
.. Warning:: A mere `nim doc --index:on`:cmd: may fail on an attempt to do
``importdoc`` from another module (for which ``.idx`` was not yet
generated), that's why `--index:only`:option: shall be used instead.
For ``.md``/``.rst`` markup documents point 2 is the only option.
Then, you can freely use something like this in ``your_module.nim``:
```nim
## .. importdoc:: user_manual.md, another_module.nim
...
## Ref. [some section from User Manual].
...
## Ref. [proc f]
## (assuming you have a proc `f` in ``another_module``).
```
and compile it by `nim doc`:cmd:. Note that link text will
be automatically prefixed by the module name of symbol,
so you will see something like "Ref. [another_module: proc f](#)"
in the generated output.
It's also possible to reference a whole module by prefixing or
suffixing full canonical module name with "module":
Ref. [module subdir/name] or [subdir/name module].
Markup documents as a whole can be referenced just by their title
(or by their file name if the title was not set) without any prefix.
.. Tip:: During development process the stage of ``.idx`` files generation
can be done only *once*, after that you use already generated ``.idx``
files while working with a document *being developed* (unless you do
incompatible changes to *referenced* documents).
.. Hint:: After changing a *referenced* document file one may need
to regenerate its corresponding ``.idx`` file to get correct results.
Of course, when referencing *internally* inside any given ``.nim`` file,
it's not needed, one can even immediately use any freshly added anchor
(a document's own ``.idx`` file is not used for resolving its internal links).
If an ``importdoc`` directive fails to find a ``.idx``, then an error
is emitted.
In case of such compilation failures please note that:
* **all** relative paths, given to ``importdoc``, relate to insides of
``OUTDIR``, and **not** project's directory structure.
* ``importdoc`` searches for ``.idx`` in `--outdir:OUTDIR`:option: directory
(``htmldocs`` by default) and **not** around original modules, so:
.. Tip:: look into ``OUTDIR`` to understand what's going on.
* also keep in mind that ``.html`` and ``.idx`` files should always be
output to the same directory, so check this and, if it's not true, check
that both runs *with* and *without* `--index:only`:option: have all
other options the same.
To summarize, for 2 basic options of [Structuring output directories]
compilation options are different:
1) complex hierarchy with `--project`:option: switch.
As the **original** project's directory structure is replicated in
`OUTDIR`, all passed paths are related to this structure also.
E.g. if a module ``path1/module.nim`` does
``.. importdoc:: path2/another.nim`` then docgen tries to load file
``OUTDIR/path1/path2/another.idx``.
.. Note:: markup documents are just placed into the specified directory
`OUTDIR`:option: by default (i.e. they are **not** affected by
`--project`:option:), so if you have ``PROJECT/doc/manual.md``
document and want to use complex hirearchy (with ``doc/``),
compile it with `--docroot`:option:\:
```cmd
# 1st stage
nim md2html --outdir:OUTDIR --docroot:/absolute/path/to/PROJECT \
--index:only PROJECT/doc/manual.md
...
# 2nd stage
nim md2html --outdir:OUTDIR --docroot:/absolute/path/to/PROJECT \
PROJECT/doc/manual.md
```
Then the output file will be placed as ``OUTDIR/doc/manual.idx``.
So if you have ``PROJECT/path1/module.nim``, then ``manual.md`` can
be referenced as ``../doc/manual.md``.
2) flattened structure.
E.g. if a module ``path1/module.nim`` does
``.. importdoc:: path2/another.nim`` then docgen tries to load
``OUTDIR/path2/another.idx``, so the path ``path1``
does not matter and providing ``path2`` can be useful only
in the case it contains another package that was placed there
using `--outdir:OUTDIR/path2`:option:.
The links' text will be prefixed as ``another: ...`` in both cases.
.. Warning:: Again, the same `--outdir:OUTDIR`:option: option should
be provided to both `doc --index:only`:option: /
`md2html --index:only`:option: and final generation by
`doc`:option:/`md2html`:option: inside 1 package.
To temporarily disable ``importdoc``, e.g. if you don't need
correct link resolution at the moment, use a `--noImportdoc`:option: switch
(only warnings about unresolved links will be generated for external references).
Related Options
===============
@@ -664,21 +434,10 @@ 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.
.. Note:: `--index`:option: switch only affects creation of ``.idx``
index files, while user-searchable Index HTML file is created by
`buildIndex`:option: commmand.
Buildindex command
------------------
Once index files have been generated for one or more modules, the Nim
compiler command `nim buildIndex directory`:cmd: 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](theindex.html)
file:
```cmd
nim buildIndex -o:path/to/htmldocs/theindex.html path/to/htmldocs
```
file.
See source switch
-----------------
@@ -809,22 +568,10 @@ references so they can be later concatenated into a big index file with
the file format in detail.
Index files are line-oriented and tab-separated (newline and tab characters
have to be escaped). Each line represents a record with 6 fields.
The content of these columns is:
have to be escaped). Each line represents a record with at least two fields
but can have up to four (additional columns are ignored). The content of these
columns is:
0. Discriminator tag denoting type of the index entry, allowed values are:
`markupTitle`
: a title for ``.md``/``.rst`` document
`nimTitle`
: a title of ``.nim`` module
`heading`
: heading of sections, can be both in Nim and markup files
`idx`
: terms marked with :idx: role
`nim`
: a Nim symbol
`nimgrp`
: a Nim group for overloadable symbols like `proc`s
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``).
@@ -834,20 +581,29 @@ The content of these columns is:
not for an API symbol but for a TOC entry.
4. Optional title or description of the hyperlink. Browsers usually display
this as a tooltip after hovering a moment over the hyperlink.
5. A line number of file where the entry was defined.
The index generation tools differentiate between documentation
generated from ``.nim`` files and documentation generated from ``.md`` or
``.rst`` files by tag `nimTitle` or `markupTitle` in the 1st line of
the ``.idx`` file.
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
consist mainly of API entries. The latter are generic documents meant for
human reading.
.. TODO Normal symbols are added to the index with surrounding whitespaces removed. An
exception to this are the table of content (TOC) entries. TOC entries are added to
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.
To differentiate both types (documents and APIs), the index generator will add
to the index of documents an entry with the title of the document. Since the
title is the topmost element, it will be added with a second field containing
just the filename without any HTML anchor. By convention, this entry without
anchor is the *title entry*, and since entries in the index file are added as
they are scanned, the title entry will be the first line. The title for APIs
is not present because it can be generated concatenating the name of the file
to the word **Module**.
Normal symbols are added to the index with surrounding whitespaces removed. An
exception to this are the table of content (TOC) entries. TOC entries are added to
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.
Additional resources
@@ -859,8 +615,6 @@ Additional resources
[Markdown and RST markup languages](markdown_rst.html), which also
contains the list of implemented features of these markup languages.
* the implementation is in [module compiler/docgen].
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.

View File

@@ -1828,23 +1828,6 @@ an `object` type or a `ref object` type:
Note that, unlike tuples, objects require the field names along with their values.
For a `ref object` type `system.new` is invoked implicitly.
The field names can be omitted if all the values are given in order. It can be mixed with field names along with values.
```nim
var a1 = Student("Anton", 5)
var a2 = PStudent("Anton", age: 5)
```
Note that, objects with only one field must use field names along with values. Otherwise, they will be recognized as type conversions.
```nim
type
Teacher = object
name: string
# var t = Teacher("lisa") # Error: type mismatch: got 'string' for '"lisa"'
# but expected 'Teacher = object'
var t = Teacher(name: "lisa")
```
Object variants
---------------
@@ -3591,8 +3574,8 @@ Example:
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
---------------
@@ -4139,7 +4122,7 @@ the operator is in scope (including if it is private).
```
Type bound operators are:
`=destroy`, `=copy`, `=sink`, `=trace`, `=deepcopy`, `=wasMoved`.
`=destroy`, `=copy`, `=sink`, `=trace`, `=deepcopy`.
These operations can be *overridden* instead of *overloaded*. This means that
the implementation is automatically lifted to structured types. For instance,
@@ -4790,8 +4773,8 @@ Example:
echo "overflow!"
except ValueError, IOError:
echo "catch multiple exceptions!"
except CatchableError:
echo "Catchable exception!"
except:
echo "Unknown exception!"
finally:
close(f)
```
@@ -4803,6 +4786,9 @@ listed in an `except` clause, the corresponding statements are executed.
The statements following the `except` clauses are called
`exception handlers`:idx:.
The empty `except`:idx: clause is executed if there is an exception that is
not listed otherwise. It is similar to an `else` clause in `if` statements.
If there is a `finally`:idx: clause, it is always executed after the
exception handlers.
@@ -4820,11 +4806,11 @@ 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`:
```nim test
```nim
from std/strutils import parseInt
let x = try: parseInt("133a")
except ValueError: -1
except: -1
finally: echo "hi"
```
@@ -4832,9 +4818,8 @@ branch always has to be `void`:
To prevent confusing code there is a parsing limitation; if the `try`
follows a `(` it has to be written as a one liner:
```nim test
from std/strutils import parseInt
let x = (try: parseInt("133a") except ValueError: -1)
```nim
let x = (try: parseInt("133a") except: -1)
```
@@ -4882,7 +4867,7 @@ error message from `e`, and for such situations, it is enough to use
```nim
try:
# ...
except CatchableError:
except:
echo getCurrentExceptionMsg()
```
@@ -5070,7 +5055,7 @@ An empty `raises` list (`raises: []`) means that no exception may be raised:
try:
unsafeCall()
result = true
except CatchableError:
except:
result = false
```
@@ -5472,7 +5457,7 @@ more complex type classes:
```nim
# create a type class that will match all tuple and object types
type RecordType = (tuple or object)
type RecordType = tuple or object
proc printFields[T: RecordType](rec: T) =
for key, value in fieldPairs(rec):
@@ -5521,7 +5506,7 @@ A type class can be used directly as the parameter's type.
```nim
# create a type class that will match all tuple and object types
type RecordType = (tuple or object)
type RecordType = tuple or object
proc printFields(rec: RecordType) =
for key, value in fieldPairs(rec):

View File

@@ -9,8 +9,6 @@ Nim-flavored Markdown and reStructuredText
.. include:: rstcommon.rst
.. contents::
.. importdoc:: docgen.md
Both `Markdown`:idx: (md) and `reStructuredText`:idx: (RST) are markup
languages whose goal is to typeset texts with complex structure,
formatting and references using simple plaintext representation.
@@ -112,8 +110,6 @@ Supported standard RST features:
Additional Nim-specific features
--------------------------------
* referencing to definitions in external files, see
[Markup external referencing] section
* directives: ``code-block`` \[cmp:Sphinx], ``title``,
``index`` \[cmp:Sphinx]
* predefined roles
@@ -174,86 +170,6 @@ Optional additional features, by default turned on:
.. warning:: Using Nim-specific features can cause other RST implementations
to fail on your document.
Referencing
===========
To be able to copy and share links Nim generates anchors for all
main document elements:
* headlines (including document title)
* footnotes
* explicitly set anchors: RST internal cross-references and
inline internal targets
* Nim symbols (external referencing), see [Nim DocGen Tools Guide] for details.
But direct use of those anchors have 2 problems:
1. the anchors are usually mangled (e.g. spaces substituted to minus
signs, etc).
2. manual usage of anchors is not checked, so it's easy to get broken
links inside your project if e.g. spelling has changed for a heading
or you use a wrong relative path to your document.
That's why Nim implementation has syntax for using
*original* labels for referencing.
Such referencing can be either local/internal or external:
* Local referencing (inside any given file) is defined by
RST standard or Pandoc Markdown User guide.
* External (cross-document) referencing is a Nim-specific feature,
though it's not really different from local referencing by its syntax.
Markup local referencing
------------------------
There are 2 syntax option available for referencing to objects
inside any given file, e.g. for headlines:
Markdown RST
Some headline Some headline
============= =============
Ref. [Some headline] Ref. `Some headline`_
Markup external referencing
---------------------------
The syntax is the same as for local referencing, but the anchors are
saved in ``.idx`` files, so one needs to generate them beforehand,
and they should be loaded by an `.. importdoc::` directive.
E.g. if we want to reference section "Some headline" in ``file1.md``
from ``file2.md``, then ``file2.md`` may look like:
```
.. importdoc:: file1.md
Ref. [Some headline]
```
```cmd
nim md2html --index:only file1.md # creates ``htmldocs/file1.idx``
nim md2html file2.md # creates ``htmldocs/file2.html``
```
To allow cross-references between any files in any order (especially, if
circular references are present), it's strongly reccommended
to make a run for creating all the indexes first:
```cmd
nim md2html --index:only file1.md # creates ``htmldocs/file1.idx``
nim md2html --index:only file2.md # creates ``htmldocs/file2.idx``
nim md2html file1.md # creates ``htmldocs/file1.html``
nim md2html file2.md # creates ``htmldocs/file2.html``
```
and then one can freely reference any objects as if these 2 documents
are actually 1 file.
Other
=====
Idiosyncrasies
--------------

View File

@@ -316,16 +316,14 @@ 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`) with options defined in
`$cpu.$os.$cc.options.always`. The configuration system is used to provide
meaningful defaults. For example, for Linux on a 32-bit ARM CPU, your
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
configuration file should contain something like:
arm.linux.gcc.path = "/usr/bin"
arm.linux.gcc.exe = "arm-linux-gcc"
arm.linux.gcc.linkerexe = "arm-linux-gcc"
arm.linux.gcc.options.always = "-w -fmax-errors=3"
Cross-compilation for Windows
=============================
@@ -715,7 +713,7 @@ Nim's thread API provides a simple wrapper around more advanced
RTOS task features. Customizing the stack size and stack guard size can
be done by setting `-d:nimThreadStackSize=16384` or `-d:nimThreadStackGuard=32`.
Currently only Zephyr, NuttX and FreeRTOS support these configurations.
Currently only Zephyr and FreeRTOS support these configurations.
Nim for realtime systems
========================

View File

@@ -147,15 +147,6 @@ body {
box-sizing: border-box;
margin-left: 1%; }
@media print {
#global-links, .link-seesrc, .theme-switch-wrapper, #searchInputDiv, .search-groupby {
display:none;
}
.columns {
width:100% !important;
}
}
.column:first-child, .columns:first-child {
margin-left: 0; }

View File

@@ -77,7 +77,7 @@ That means you can always use only 1 such an option with logical OR, e.g.
.. Note::
If you want logical AND on patterns you should compose 1 appropriate pattern,
possibly combined with multi-line mode `(?s)`:literal:.
E.g. to require that multi-line context of matches has occurrences of
E.g. to require that multi-line context of matches has occurences of
**both** PAT1 and PAT2 use positive lookaheads (`(?=PAT)`:literal:):
```cmd
nimgrep --inContext:'(?s)(?=.*PAT1)(?=.*PAT2)'

View File

@@ -211,7 +211,7 @@ ends with ``.nims``:
echo "hello world"
```
Use `#!/usr/bin/env -S nim e --hints:off` to disable hints and relax the file extension constraint.
Use `#!/usr/bin/env -S nim --hints:off` to disable hints.
Benefits

View File

@@ -69,11 +69,8 @@ Hints on the build process:
What to install:
- The expected stdlib location is `/usr/lib/nim/lib`, previously it was just `/usr/lib/nim`
- `nimdoc.css` and `nimdoc.cls` from the `doc` folder should go into `/usr/lib/nim/doc/`
- `tools/debug/nim-gdb.py` should go into `/usr/lib/nim/tools/`
- `tools/dochack/dochack.js` should be installed to `/usr/lib/nim/tools/dochack/`
- Global configuration files under `/etc/nim`
- The expected stdlib location is /usr/lib/nim
- Global configuration files under /etc/nim
- Optionally: manpages, documentation, shell completion
- When installing documentation, .idx files are not required
- The "compiler" directory contains compiler sources and should not be part of the compiler binary package

View File

@@ -138,7 +138,6 @@ The garbage collector won't try to free them, you need to call their respective
when you are done with them or they will leak.
Heap dump
=========

View File

@@ -50,7 +50,6 @@ Options
--colors:on|off Turn messages coloring on|off.
--backendLogging:on|off Disable or enable backend logging. By default turned on.
--megatest:on|off Enable or disable megatest. Default is on.
--valgrind:on|off Enable or disable valgrind support. Default is on.
--skipFrom:file Read tests to skip from `file` - one test per line, # comments ignored

View File

@@ -393,7 +393,7 @@ The `try` statement handles exceptions:
echo "could not convert string to integer"
except IOError:
echo "IO error!"
except CatchableError:
except:
echo "Unknown exception!"
# reraise the unknown exception:
raise
@@ -425,7 +425,7 @@ module. Example:
```nim
try:
doSomethingHere()
except CatchableError:
except:
let
e = getCurrentException()
msg = getCurrentExceptionMsg()

View File

@@ -10,7 +10,7 @@
#
const
NimbleStableCommit = "7efb226ef908297e8791cade20d991784b4e8bfc" # master
NimbleStableCommit = "0777f33d1ddbd505b3aa7b714032125349323ceb" # master
# examples of possible values: #head, #ea82b54, 1.2.3
FusionStableHash = "#372ee4313827ef9f2ea388840f7d6b46c2b1b014"
HeadHash = "#head"
@@ -295,7 +295,11 @@ proc boot(args: string) =
let nimStart = findStartNim().quoteShell()
for i in 0..2:
let defaultCommand = if useCpp: "cpp" else: "c"
# Nim versions < (1, 1) expect Nim's exception type to have a 'raiseId' field for
# C++ interop. Later Nim versions do this differently and removed the 'raiseId' field.
# Thus we always bootstrap the first iteration with "c" and not with "cpp" as
# a workaround.
let defaultCommand = if useCpp and i > 0: "cpp" else: "c"
let bootOptions = if args.len == 0 or args.startsWith("-"): defaultCommand else: ""
echo "iteration: ", i+1
var extraOption = ""
@@ -530,7 +534,8 @@ proc runCI(cmd: string) =
# boot without -d:nimHasLibFFI to make sure this still works
# `--lib:lib` is needed for bootstrap on openbsd, for reasons described in
# https://github.com/nim-lang/Nim/pull/14291 (`getAppFilename` bugsfor older nim on openbsd).
kochExecFold("Boot Nim ORC", "boot -d:release -d:nimStrictMode --lib:lib")
kochExecFold("Boot in release mode", "boot -d:release --gc:refc -d:nimStrictMode --lib:lib")
kochExecFold("Boot Nim ORC", "boot -d:release --lib:lib")
when false: # debugging: when you need to run only 1 test in CI, use something like this:
execFold("debugging test", "nim r tests/stdlib/tosproc.nim")
@@ -586,9 +591,6 @@ proc runCI(cmd: string) =
execFold("Run atlas tests", "nim c -r -d:atlasTests tools/atlas/atlas.nim clone https://github.com/disruptek/balls")
kochExecFold("Testing booting in refc", "boot -d:release --mm:refc -d:nimStrictMode --lib:lib")
proc testUnixInstall(cmdLineRest: string) =
csource("-d:danger" & cmdLineRest)
xz(false, cmdLineRest)

View File

@@ -181,32 +181,6 @@ proc `[]`*(t: CacheTable; key: string): NimNode {.magic: "NctGet".} =
# get the NimNode back
assert mcTable["toAdd"].kind == nnkStmtList
proc hasKey*(t: CacheTable; key: string): bool =
## Returns true if `key` is in the table `t`.
##
## See also:
## * [contains proc][contains(CacheTable, string)] for use with the `in` operator
runnableExamples:
import std/macros
const mcTable = CacheTable"hasKeyEx"
static:
assert not mcTable.hasKey("foo")
mcTable["foo"] = newEmptyNode()
# Will now be true since we inserted a value
assert mcTable.hasKey("foo")
discard "Implemented in vmops"
proc contains*(t: CacheTable; key: string): bool {.inline.} =
## Alias of [hasKey][hasKey(CacheTable, string)] for use with the `in` operator.
runnableExamples:
import std/macros
const mcTable = CacheTable"containsEx"
static:
mcTable["foo"] = newEmptyNode()
# Will be true since we gave it a value before
assert "foo" in mcTable
t.hasKey(key)
proc hasNext(t: CacheTable; iter: int): bool {.magic: "NctHasNext".}
proc next(t: CacheTable; iter: int): (string, NimNode, int) {.magic: "NctNext".}

View File

@@ -23,8 +23,6 @@ when defined(nimPreviewSlimSystem):
## .. include:: ../../doc/astspec.txt
## .. importdoc:: system.nim
# If you look for the implementation of the magic symbol
# ``{.magic: "Foo".}``, search for `mFoo` and `opcFoo`.
@@ -535,22 +533,6 @@ proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.}
proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffect.}
## Copy lineinfo from `info`.
proc setLine(arg: NimNode, line: uint16) {.magic: "NLineInfo", noSideEffect.}
proc setColumn(arg: NimNode, column: int16) {.magic: "NLineInfo", noSideEffect.}
proc setFile(arg: NimNode, file: string) {.magic: "NLineInfo", noSideEffect.}
proc setLineInfo*(arg: NimNode, file: string, line: int, column: int) =
## Sets the line info on the NimNode. The file needs to exists, but can be a
## relative path. If you want to attach line info to a block using `quote`
## you'll need to add the line information after the quote block.
arg.setFile(file)
arg.setLine(line.uint16)
arg.setColumn(column.int16)
proc setLineInfo*(arg: NimNode, lineInfo: LineInfo) =
## See `setLineInfo proc<#setLineInfo,NimNode,string,int,int>`_
setLineInfo(arg, lineInfo.filename, lineInfo.line, lineInfo.column)
proc lineInfoObj*(n: NimNode): LineInfo =
## Returns `LineInfo` of `n`, using absolute path for `filename`.
result = LineInfo(filename: n.getFile, line: n.getLine, column: n.getColumn)
@@ -1521,10 +1503,11 @@ proc boolVal*(n: NimNode): bool {.noSideEffect.} =
if n.kind == nnkIntLit: n.intVal != 0
else: n == bindSym"true" # hacky solution for now
proc nodeID*(n: NimNode): int {.magic: "NodeId".}
## Returns the id of `n`, when the compiler has been compiled
## with the flag `-d:useNodeids`, otherwise returns `-1`. This
## proc is for the purpose to debug the compiler only.
when defined(nimMacrosGetNodeId):
proc nodeID*(n: NimNode): int {.magic: "NodeId".}
## Returns the id of `n`, when the compiler has been compiled
## with the flag `-d:useNodeids`, otherwise returns `-1`. This
## proc is for the purpose to debug the compiler only.
macro expandMacros*(body: typed): untyped =
## Expands one level of macro - useful for debugging.
@@ -1591,7 +1574,7 @@ proc customPragmaNode(n: NimNode): NimNode =
elif impl.kind in {nnkIdentDefs, nnkConstDef} and impl[0].kind == nnkPragmaExpr:
return impl[0][1]
else:
let timpl = getImpl(if typ.kind == nnkBracketExpr: typ[0] else: typ)
let timpl = typ.getImpl()
if timpl.len>0 and timpl[0].len>1:
return timpl[0][1]
else:

View File

@@ -132,12 +132,12 @@ else:
proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {.
importCompilerProc.}
template `+!!`(a, b): untyped = cast[pointer](cast[int](a) + b)
template `+!!`(a, b): untyped = cast[pointer](cast[ByteAddress](a) + b)
proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
assert(n.kind == nkCase)
var d: int
let a = cast[int](aa)
let a = cast[ByteAddress](aa)
case n.typ.size
of 1: d = int(cast[ptr uint8](a +% n.offset)[])
of 2: d = int(cast[ptr uint16](a +% n.offset)[])

View File

@@ -20,17 +20,15 @@ when defined(js):
## search the internet for a wide variety of third-party documentation and
## tools.
##
## .. warning:: 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:
## **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:
runnableExamples:
# either `import std/nre except toSeq` or fully qualify `sequtils.toSeq`:
import std/sequtils
iterator iota(n: int): int =
for i in 0..<n: yield i
assert sequtils.toSeq(iota(3)) == @[0, 1, 2]
## .. note:: There are also alternative nimble packages such as [tinyre](https://github.com/khchen/tinyre)
## and [regex](https://github.com/nitely/nim-regex).
## Licencing
## ---------
##

Some files were not shown because too many files have changed in this diff Show More