mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-01 03:13:41 +00:00
Compare commits
309 Commits
pr_remove_
...
pr_move_sy
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3eddba8b5e | ||
|
|
911e302d37 | ||
|
|
6987408dae | ||
|
|
eebe3b59af | ||
|
|
8f6fee9098 | ||
|
|
2efcbd55c3 | ||
|
|
dd89ef9605 | ||
|
|
4f602e475c | ||
|
|
56cf60b446 | ||
|
|
6dbeb3cf46 | ||
|
|
cc923b3422 | ||
|
|
553d7c72b4 | ||
|
|
8cbb0a3452 | ||
|
|
d67317ce5c | ||
|
|
ba218f8a80 | ||
|
|
40aa0294f3 | ||
|
|
a4a8cd86ce | ||
|
|
4a883c5c5f | ||
|
|
21df5beb3d | ||
|
|
347b0fa0ba | ||
|
|
42d017a95e | ||
|
|
7dd1d096da | ||
|
|
e905df2135 | ||
|
|
d606c6bf81 | ||
|
|
5c0a036152 | ||
|
|
8511346cfb | ||
|
|
edc8f6497c | ||
|
|
0bab6fe0b6 | ||
|
|
9d95883024 | ||
|
|
38fd3a28f2 | ||
|
|
0d9c28205b | ||
|
|
2d4cd386c0 | ||
|
|
54bbc9837f | ||
|
|
b3c7ddaea0 | ||
|
|
e846f40758 | ||
|
|
2408bf4a33 | ||
|
|
b13bfa05a2 | ||
|
|
df42b85c5c | ||
|
|
dd343a9a6d | ||
|
|
a7719009f3 | ||
|
|
c6055c0d86 | ||
|
|
c06bfeb37f | ||
|
|
5e1faeae31 | ||
|
|
5358bf12c0 | ||
|
|
54199d93d5 | ||
|
|
ae74f4cd2c | ||
|
|
5834a5dac5 | ||
|
|
dba3546bbc | ||
|
|
2cece88e0d | ||
|
|
f76e59a8bf | ||
|
|
0ab1f41412 | ||
|
|
28ca6e11ca | ||
|
|
e0ceaba773 | ||
|
|
ad119a2188 | ||
|
|
fcffc84765 | ||
|
|
8fd8905382 | ||
|
|
99653a0b8b | ||
|
|
e5aa3924fb | ||
|
|
d94c9dccd7 | ||
|
|
76f299e2c0 | ||
|
|
8af6e92606 | ||
|
|
96920dace2 | ||
|
|
8070ba46e0 | ||
|
|
45b4eb49ca | ||
|
|
efbdda55d1 | ||
|
|
829b9aad05 | ||
|
|
d0fd779b4c | ||
|
|
245763c29f | ||
|
|
deba8d4c18 | ||
|
|
b48e21db34 | ||
|
|
76ca4298f1 | ||
|
|
79413cf74c | ||
|
|
1a0949c9df | ||
|
|
e6f0b0b016 | ||
|
|
18bd38d4da | ||
|
|
7f7f90abbb | ||
|
|
c9d5a1081d | ||
|
|
13429077a0 | ||
|
|
5e768b34ec | ||
|
|
5673f8fdb6 | ||
|
|
189f8f8dd1 | ||
|
|
13d081aa5d | ||
|
|
feb550f0b4 | ||
|
|
59d4f801ef | ||
|
|
b5cbae1726 | ||
|
|
2720c2f818 | ||
|
|
1bc4196603 | ||
|
|
0f9554fbbc | ||
|
|
956bcc4715 | ||
|
|
484ef29df1 | ||
|
|
f4312b4c82 | ||
|
|
a511b9f918 | ||
|
|
9034bc173f | ||
|
|
faadf3eb85 | ||
|
|
f6cd14bc61 | ||
|
|
f155fd122d | ||
|
|
50426e3f23 | ||
|
|
b0624c8eff | ||
|
|
6f9876dc04 | ||
|
|
9528b9d853 | ||
|
|
b7adea8e18 | ||
|
|
d4f66891e6 | ||
|
|
20b5cc6985 | ||
|
|
b4e02ea65c | ||
|
|
33935a547c | ||
|
|
08fafdc2c1 | ||
|
|
16fee27851 | ||
|
|
58d6166fac | ||
|
|
c12b6a894a | ||
|
|
e102f4fb86 | ||
|
|
fb463f545f | ||
|
|
95b4524705 | ||
|
|
ef92d6ec76 | ||
|
|
9f35bb3968 | ||
|
|
2b6e1d4836 | ||
|
|
196a801c3f | ||
|
|
60e92168f9 | ||
|
|
35dadac3fb | ||
|
|
6f7c749ea5 | ||
|
|
988a4ef900 | ||
|
|
6c6a7e34e9 | ||
|
|
60f707fdad | ||
|
|
c2daf0055e | ||
|
|
aa4184b375 | ||
|
|
83b5a2bc57 | ||
|
|
dcfe341955 | ||
|
|
5bc1ac4a51 | ||
|
|
16976718da | ||
|
|
196aad2c57 | ||
|
|
a202556ac7 | ||
|
|
209b4a171e | ||
|
|
0dcdfa0ab5 | ||
|
|
7407d00052 | ||
|
|
043d77d2bc | ||
|
|
24c0887f54 | ||
|
|
8fb1a0fa9e | ||
|
|
a69826615a | ||
|
|
f9f73aed79 | ||
|
|
2179f45be2 | ||
|
|
2157ebc536 | ||
|
|
8023c2c851 | ||
|
|
7240056537 | ||
|
|
88791d9a9e | ||
|
|
01648fead0 | ||
|
|
c71afbcd53 | ||
|
|
b984992511 | ||
|
|
b612c42e1c | ||
|
|
1bb90ad3ae | ||
|
|
0e5874a93a | ||
|
|
00e4d53100 | ||
|
|
76ae6168d8 | ||
|
|
4eb3dda5e4 | ||
|
|
f882499ca2 | ||
|
|
657f3bdfd0 | ||
|
|
3e4072c6ea | ||
|
|
f1a64fdb1c | ||
|
|
4ade87d840 | ||
|
|
593b731002 | ||
|
|
9a99aeac00 | ||
|
|
d34c093f8d | ||
|
|
32c87721a7 | ||
|
|
512d1d0bb2 | ||
|
|
910dd6bcc9 | ||
|
|
c49e9ff84b | ||
|
|
8ce203abe0 | ||
|
|
9743e567ae | ||
|
|
1c8496a3ad | ||
|
|
af073ad381 | ||
|
|
9e21f3aa24 | ||
|
|
1c2b176d62 | ||
|
|
7c01f52e92 | ||
|
|
20cd512457 | ||
|
|
a6997fb8eb | ||
|
|
d0cc21e322 | ||
|
|
769869c699 | ||
|
|
344d861247 | ||
|
|
a3eb2381f2 | ||
|
|
2834588250 | ||
|
|
05f1ddc34c | ||
|
|
234ecc42fa | ||
|
|
36a191c9e6 | ||
|
|
246b6e3ae0 | ||
|
|
53836903d3 | ||
|
|
900d65ae91 | ||
|
|
a17c1f85c3 | ||
|
|
31c1148eb0 | ||
|
|
2702689fe7 | ||
|
|
c337a17fb0 | ||
|
|
40e8c2d744 | ||
|
|
541d93bd90 | ||
|
|
16c646c816 | ||
|
|
aaf7187fe5 | ||
|
|
255c7670c9 | ||
|
|
1cc74251ee | ||
|
|
0ed7f08bed | ||
|
|
9b7320d352 | ||
|
|
03a0fda1bd | ||
|
|
730580382c | ||
|
|
ea15babc09 | ||
|
|
eb1a2176e7 | ||
|
|
ce00e9284f | ||
|
|
942694fd46 | ||
|
|
abee78c3b0 | ||
|
|
4ea64743cb | ||
|
|
d0bc5875b0 | ||
|
|
51b0bd3121 | ||
|
|
e5a46907ab | ||
|
|
4f663a104e | ||
|
|
ec08afd847 | ||
|
|
021fe523b1 | ||
|
|
26afc0703a | ||
|
|
8c93fc2229 | ||
|
|
e8b734dde1 | ||
|
|
4b4613fc57 | ||
|
|
14c0c64c59 | ||
|
|
68eab87dd2 | ||
|
|
a9c1a94037 | ||
|
|
4be74a1d20 | ||
|
|
bed7bc325f | ||
|
|
ce8659ac36 | ||
|
|
d02789dd6e | ||
|
|
e745c73dea | ||
|
|
0a735a6f12 | ||
|
|
9e3d2d725e | ||
|
|
ea72ccbaf8 | ||
|
|
ad8ac587e0 | ||
|
|
747245aa82 | ||
|
|
a9d421e40f | ||
|
|
a271a07b64 | ||
|
|
81dcfba125 | ||
|
|
cc4073fa60 | ||
|
|
5e801014fa | ||
|
|
0c583a38b4 | ||
|
|
e922895883 | ||
|
|
1b4db44660 | ||
|
|
acadc5f5eb | ||
|
|
bc84a6e7ce | ||
|
|
e8442eaf11 | ||
|
|
5bd3fbb2d6 | ||
|
|
20de1a342e | ||
|
|
8f0e58819e | ||
|
|
1b686605d1 | ||
|
|
1a05787855 | ||
|
|
a04fc1c0f3 | ||
|
|
1518052813 | ||
|
|
b8296988d0 | ||
|
|
1b5c7a6941 | ||
|
|
70a19c8db8 | ||
|
|
4010ad7229 | ||
|
|
14c6c1c695 | ||
|
|
33f668caaf | ||
|
|
c699f4b5ab | ||
|
|
eaad754508 | ||
|
|
f3c0728405 | ||
|
|
b2d26fa9ca | ||
|
|
89fe268007 | ||
|
|
fbb62a6c32 | ||
|
|
5b8ae3cbf4 | ||
|
|
42a503b069 | ||
|
|
d078a65a4d | ||
|
|
69b6a2dc3a | ||
|
|
2bfe76908d | ||
|
|
0ac0f2e2c4 | ||
|
|
90fe5e03af | ||
|
|
8a40b19273 | ||
|
|
f20f3269fc | ||
|
|
d11230ea13 | ||
|
|
79654a8191 | ||
|
|
e02ee2c195 | ||
|
|
fb481c0df8 | ||
|
|
ad45dcd223 | ||
|
|
8c15451400 | ||
|
|
ed588265ca | ||
|
|
ebdbdb0ca5 | ||
|
|
f503ef5fd9 | ||
|
|
e1b3dc208a | ||
|
|
870869d081 | ||
|
|
a9a982c5e9 | ||
|
|
d409e7f4ba | ||
|
|
fdf460d131 | ||
|
|
a6664bf8e3 | ||
|
|
e6e5e86f5c | ||
|
|
46eb616a37 | ||
|
|
457ef2855b | ||
|
|
118e4667b7 | ||
|
|
5da8e91358 | ||
|
|
4998c99d05 | ||
|
|
0a9ca2633f | ||
|
|
c7703ec24f | ||
|
|
01c6a074c1 | ||
|
|
bb3f67be0e | ||
|
|
c90a02503b | ||
|
|
6201c0ba56 | ||
|
|
832dc48f89 | ||
|
|
d05879916d | ||
|
|
79ced725f0 | ||
|
|
714341b1e3 | ||
|
|
bb03ef88b3 | ||
|
|
faefcaf47e | ||
|
|
0e7254f2eb | ||
|
|
9f6219d5cf | ||
|
|
f17a5c0c6b | ||
|
|
1df6a386a7 | ||
|
|
701187b6d7 | ||
|
|
790515ff98 | ||
|
|
19896f6a42 | ||
|
|
7c1e294e23 | ||
|
|
b021a7c91b | ||
|
|
4cba67edd7 |
5
.github/workflows/ci_packages.yml
vendored
5
.github/workflows/ci_packages.yml
vendored
@@ -4,7 +4,6 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- 'devel'
|
||||
- 'version-2-0'
|
||||
- 'version-1-6'
|
||||
- 'version-1-2'
|
||||
|
||||
@@ -28,12 +27,12 @@ jobs:
|
||||
NIM_TESTAMENT_BATCH: ${{ matrix.batch }}
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
|
||||
4
.github/workflows/ci_publish.yml
vendored
4
.github/workflows/ci_publish.yml
vendored
@@ -17,12 +17,12 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -67,7 +67,6 @@ testament.db
|
||||
|
||||
/csources
|
||||
/csources_v1
|
||||
/csources_v2
|
||||
|
||||
/dist/
|
||||
# /lib/fusion # fusion is now unbundled; `git status` should reveal if it's there so users can act on it
|
||||
|
||||
250
changelog.md
250
changelog.md
@@ -1,31 +1,273 @@
|
||||
# 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`.
|
||||
|
||||
- [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.
|
||||
|
||||
- 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.
|
||||
|
||||
## 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 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 `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.
|
||||
|
||||
## 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".
|
||||
- `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.
|
||||
- [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
|
||||
```
|
||||
|
||||
- Redefining templates with the same signature implicitly was previously
|
||||
allowed to support certain macro code. A `{.redefine.}` pragma has been
|
||||
added to make this work explicitly, and a warning is generated in the case
|
||||
where it is implicit. This behavior only applies to templates, redefinition
|
||||
is generally disallowed for other symbols.
|
||||
|
||||
- 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 supports Nimble version 0.14 which added support for lock-files. This is done by
|
||||
a simple configuration change setting that you can do yourself too. In `$nim/config/nim.cfg`
|
||||
replace `pkgs` by `pkgs2`.
|
||||
|
||||
33
changelogs/changelog.md
Normal file
33
changelogs/changelog.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# v1.xx.x - yyyy-mm-dd
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
- `std/sharedlist` and `std/sharedtables` are now deprecated, see RFC [#433](https://github.com/nim-lang/RFCs/issues/433).
|
||||
|
||||
### New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall
|
||||
|
||||
This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17.
|
||||
|
||||
On linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall.
|
||||
|
||||
When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be:
|
||||
```sh
|
||||
$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details
|
||||
$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8
|
||||
$ sh build.sh # per unix install instructions
|
||||
$ bin/nim c koch # per unix install instructions
|
||||
$ ./koch boot -d:release # per unix install instructions
|
||||
$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall
|
||||
```
|
||||
|
||||
This is necessary to pass when building nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for stdlib (sysrand in particular).
|
||||
|
||||
## Language changes
|
||||
|
||||
|
||||
## Compiler changes
|
||||
|
||||
|
||||
## Tool changes
|
||||
@@ -1,358 +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)
|
||||
```
|
||||
|
||||
- - 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.
|
||||
|
||||
## 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`).
|
||||
@@ -706,13 +706,13 @@ 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,
|
||||
mNHint, mNWarning, mNError,
|
||||
mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2,
|
||||
mNimvm, mIntDefine, mStrDefine, mBoolDefine, mGenericDefine, mRunnableExamples,
|
||||
mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples,
|
||||
mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
|
||||
mSymIsInstantiationOf, mNodeId, mPrivateAccess, mZeroDefault
|
||||
|
||||
@@ -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.:
|
||||
@@ -1694,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[]
|
||||
@@ -1748,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
|
||||
@@ -2055,9 +2047,6 @@ template detailedInfo*(sym: PSym): string =
|
||||
proc isInlineIterator*(typ: PType): bool {.inline.} =
|
||||
typ.kind == tyProc and tfIterator in typ.flags and typ.callConv != ccClosure
|
||||
|
||||
proc isIterator*(typ: PType): bool {.inline.} =
|
||||
typ.kind == tyProc and tfIterator in typ.flags
|
||||
|
||||
proc isClosureIterator*(typ: PType): bool {.inline.} =
|
||||
typ.kind == tyProc and tfIterator in typ.flags and typ.callConv == ccClosure
|
||||
|
||||
|
||||
@@ -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("[")
|
||||
|
||||
@@ -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:
|
||||
@@ -1879,13 +1879,9 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
# Bug #9279, len(toOpenArray()) has to work:
|
||||
if a.kind in nkCallKinds and a[0].kind == nkSym and a[0].sym.magic == mSlice:
|
||||
# magic: pass slice to openArray:
|
||||
var m: TLoc
|
||||
var b, c: TLoc
|
||||
initLocExpr(p, a[1], m)
|
||||
initLocExpr(p, a[2], b)
|
||||
initLocExpr(p, a[3], c)
|
||||
if optBoundsCheck in p.options:
|
||||
genBoundsCheck(p, m, b, c)
|
||||
if op == mHigh:
|
||||
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)", [rdLoc(b), rdLoc(c)]))
|
||||
else:
|
||||
@@ -2126,7 +2122,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)
|
||||
@@ -3200,8 +3196,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)
|
||||
@@ -3285,7 +3279,6 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
|
||||
if constOrNil != nil:
|
||||
for i in 1..<constOrNil.len:
|
||||
if constOrNil[i].kind == nkExprColonExpr:
|
||||
assert constOrNil[i][0].kind == nkSym, "illformed object constr; the field is not a sym"
|
||||
if constOrNil[i][0].sym.name.id == field.name.id:
|
||||
genBracedInit(p, constOrNil[i][1], isConst, field.typ, result)
|
||||
return
|
||||
@@ -3331,8 +3324,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"
|
||||
@@ -3342,8 +3333,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"
|
||||
|
||||
@@ -1620,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)
|
||||
|
||||
@@ -48,9 +48,11 @@ proc fillBackendName(m: BModule; s: PSym) =
|
||||
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)
|
||||
# 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)
|
||||
|
||||
@@ -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
|
||||
@@ -1345,7 +1348,7 @@ proc genDisplay(t: PType, depth: int): Rope =
|
||||
result.add seqs[0]
|
||||
result.add "}"
|
||||
|
||||
proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) =
|
||||
proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) =
|
||||
cgsym(m, "TNimTypeV2")
|
||||
m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name])
|
||||
|
||||
@@ -1361,6 +1364,7 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin
|
||||
|
||||
let objDepth = if t.kind == tyObject: getObjDepth(t) else: -1
|
||||
|
||||
|
||||
if t.kind in {tyObject, tyDistinct} and incompleteType(t):
|
||||
localError(m.config, info, "request for RTTI generation for incomplete object: " &
|
||||
typeToString(t))
|
||||
@@ -1386,48 +1390,6 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin
|
||||
if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
|
||||
discard genTypeInfoV1(m, t, info)
|
||||
|
||||
proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) =
|
||||
cgsym(m, "TNimTypeV2")
|
||||
m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name])
|
||||
|
||||
var flags = 0
|
||||
if not canFormAcycle(t): flags = flags or 1
|
||||
|
||||
var typeEntry = newRopeAppender()
|
||||
addf(typeEntry, "N_LIB_PRIVATE TNimTypeV2 $1 = {", [name])
|
||||
add(typeEntry, ".destructor = (void*)")
|
||||
genHook(m, t, info, attachedDestructor, typeEntry)
|
||||
|
||||
let objDepth = if t.kind == tyObject: getObjDepth(t) else: -1
|
||||
|
||||
if t.kind in {tyObject, tyDistinct} and incompleteType(t):
|
||||
localError(m.config, info, "request for RTTI generation for incomplete object: " &
|
||||
typeToString(t))
|
||||
|
||||
addf(typeEntry, ", .size = sizeof($1), .align = (NI16) NIM_ALIGNOF($1), .depth = $2",
|
||||
[getTypeDesc(m, t), rope(objDepth)])
|
||||
|
||||
if objDepth >= 0:
|
||||
let objDisplay = genDisplay(t, objDepth)
|
||||
let objDisplayStore = getTempName(m)
|
||||
m.s[cfsVars].addf("static NIM_CONST $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), skVar), objDisplayStore, rope(objDepth+1), objDisplay])
|
||||
addf(typeEntry, ", .display = $1", [rope(objDisplayStore)])
|
||||
if isDefined(m.config, "nimTypeNames"):
|
||||
var typeName: Rope
|
||||
if t.kind in {tyObject, tyDistinct}:
|
||||
typeName = genTypeInfo2Name(m, t)
|
||||
else:
|
||||
typeName = rope("NIM_NIL")
|
||||
addf(typeEntry, ", .name = $1", [typeName])
|
||||
add(typeEntry, ", .traceImpl = (void*)")
|
||||
genHook(m, t, info, attachedTrace, typeEntry)
|
||||
|
||||
addf(typeEntry, ", .flags = $1};$n", [rope(flags)])
|
||||
m.s[cfsVars].add typeEntry
|
||||
|
||||
if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
|
||||
discard genTypeInfoV1(m, t, info)
|
||||
|
||||
proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope =
|
||||
let origType = t
|
||||
# distinct types can have their own destructors
|
||||
@@ -1461,10 +1423,7 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope =
|
||||
return prefixTI.rope & result & ")".rope
|
||||
|
||||
m.g.typeInfoMarkerV2[sig] = (str: result, owner: owner)
|
||||
if m.compileToCpp:
|
||||
genTypeInfoV2OldImpl(m, t, origType, result, info)
|
||||
else:
|
||||
genTypeInfoV2Impl(m, t, origType, result, info)
|
||||
genTypeInfoV2Impl(m, t, origType, result, info)
|
||||
result = prefixTI.rope & result & ")".rope
|
||||
|
||||
proc openArrayToTuple(m: BModule; t: PType): PType =
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1801,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", [])
|
||||
|
||||
@@ -1932,6 +1929,8 @@ template injectG() {.dirty.} =
|
||||
graph.backend = newModuleList(graph)
|
||||
let g = BModuleList(graph.backend)
|
||||
|
||||
when not defined(nimHasSinkInference):
|
||||
{.pragma: nosinks.}
|
||||
|
||||
proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} =
|
||||
injectG()
|
||||
|
||||
@@ -172,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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,6 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasCallsitePragma")
|
||||
defineSymbol("nimHasAmbiguousEnumHint")
|
||||
|
||||
defineSymbol("nimHasWarnCastSizes")
|
||||
defineSymbol("nimHasOutParams")
|
||||
defineSymbol("nimHasSystemRaisesDefect")
|
||||
defineSymbol("nimHasWarnUnnamedBreak")
|
||||
defineSymbol("nimHasGenericDefine")
|
||||
defineSymbol("nimHasDefineAliases")
|
||||
defineSymbol("nimHasWarnBareExcept")
|
||||
|
||||
@@ -100,6 +100,9 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
|
||||
rope(project.splitFile.name), b.dotGraph],
|
||||
changeFileExt(project, "dot"))
|
||||
|
||||
when not defined(nimHasSinkInference):
|
||||
{.pragma: nosinks.}
|
||||
|
||||
proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} =
|
||||
var g: PGen
|
||||
new(g)
|
||||
|
||||
@@ -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,
|
||||
@@ -583,7 +558,7 @@ proc runAllExamples(d: PDoc) =
|
||||
|
||||
proc quoted(a: string): string = result.addQuoted(a)
|
||||
|
||||
proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): (string, int, int) =
|
||||
proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): auto =
|
||||
# xxx expose in compiler/lineinfos.nim
|
||||
(conf.toMsgFilename(info), info.line.int, info.col.int + ColOffset)
|
||||
|
||||
@@ -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``.
|
||||
@@ -997,7 +962,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
|
||||
var literal = ""
|
||||
var r: TSrcGen
|
||||
initTokRender(r, genNode, {renderNoBody, renderNoComments,
|
||||
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
|
||||
renderNoPragmas, renderNoProcDefs})
|
||||
var kind = tkEof
|
||||
while true:
|
||||
getNextTok(r, kind, literal)
|
||||
@@ -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 = ""
|
||||
@@ -1026,7 +995,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
|
||||
var r: TSrcGen
|
||||
# Obtain the plain rendered string for hyperlink titles.
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments,
|
||||
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
|
||||
renderNoPragmas, renderNoProcDefs})
|
||||
while true:
|
||||
getNextTok(r, kind, literal)
|
||||
if kind == tkEof:
|
||||
@@ -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}, 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,20 +1076,25 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
|
||||
"itemSymOrID", symbolOrId.replace(",", ",<wbr>"),
|
||||
"itemSymOrIDEnc", symbolOrIdEnc])
|
||||
|
||||
setIndexTerm(d[], ieNim, htmlFile = external, id = symbolOrId, term = name,
|
||||
linkTitle = detailedName,
|
||||
linkDesc = xmltree.escape(plainDocstring.docstringSummary),
|
||||
line = n.info.line.int)
|
||||
# Ironically for types the complexSymbol is *cleaner* than the plainName
|
||||
# because it doesn't include object fields or documentation comments. So we
|
||||
# use the plain one for callable elements, and the complex for the rest.
|
||||
var linkTitle = changeFileExt(extractFilename(d.filename), "") & ": "
|
||||
if n.kind in routineDefs: linkTitle.add(xmltree.escape(plainName.strip))
|
||||
else: linkTitle.add(xmltree.escape(complexSymbol.strip))
|
||||
|
||||
setIndexTerm(d[], external, symbolOrId, name, linkTitle,
|
||||
xmltree.escape(plainDocstring.docstringSummary))
|
||||
if k == skType and nameNode.kind == nkSym:
|
||||
d.types.strTableAdd nameNode.sym
|
||||
|
||||
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): 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})
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
|
||||
result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
|
||||
"col": %n.info.col}
|
||||
if comm != nil:
|
||||
@@ -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)
|
||||
|
||||
@@ -50,7 +50,7 @@ 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 =
|
||||
result = n
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -528,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)
|
||||
@@ -851,17 +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 else: 32_000
|
||||
if linkCmd.len > MaxCmdLen:
|
||||
linkViaResponseFile(conf, linkCmd)
|
||||
else:
|
||||
execLinkCmd(conf, linkCmd)
|
||||
|
||||
proc callCCompiler*(conf: ConfigRef) =
|
||||
var
|
||||
linkCmd: string
|
||||
@@ -938,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:
|
||||
@@ -1022,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]
|
||||
@@ -1039,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 =
|
||||
|
||||
@@ -24,7 +24,7 @@ when defined(nimPreviewSlimSystem):
|
||||
## `RodFile` represents a Rod File (versioned binary format), and the
|
||||
## associated data for common interactions such as IO and error tracking
|
||||
## (`RodFileError`). The file format broken up into sections (`RodSection`)
|
||||
## and preceded by a header (see: `cookie`). The precise layout, section
|
||||
## and preceeded by a header (see: `cookie`). The precise layout, section
|
||||
## ordering and data following the section are determined by the user. See
|
||||
## `ic.loadRodFile`.
|
||||
##
|
||||
|
||||
@@ -829,10 +829,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
if ri.kind != nkEmpty:
|
||||
result.add moveOrCopy(v, ri, c, s, if v.kind == nkSym: {IsDecl} else: {})
|
||||
elif ri.kind == nkEmpty and c.inLoop > 0:
|
||||
let skipInit = v.kind == nkDotExpr and # Closure var
|
||||
sfNoInit in v[1].sym.flags
|
||||
if not skipInit:
|
||||
result.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, if v.kind == nkSym: {IsDecl} else: {})
|
||||
result.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, if v.kind == nkSym: {IsDecl} else: {})
|
||||
else: # keep the var but transform 'ri':
|
||||
var v = copyNode(n)
|
||||
var itCopy = copyNode(it)
|
||||
|
||||
@@ -70,7 +70,6 @@ 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]
|
||||
|
||||
@@ -724,9 +724,8 @@ proc hasFrameInfo(p: PProc): bool =
|
||||
((p.prc == nil) or not (sfPure in p.prc.flags))
|
||||
|
||||
proc lineDir(config: ConfigRef, info: TLineInfo, line: int): Rope =
|
||||
"/* line $2:$3 \"$1\" */$n" % [
|
||||
rope(toFullPath(config, info)), rope(line), rope(info.toColumn)
|
||||
]
|
||||
ropes.`%`("/* line $2 \"$1\" */$n",
|
||||
[rope(toFullPath(config, info)), rope(line)])
|
||||
|
||||
proc genLineDir(p: PProc, n: PNode) =
|
||||
let line = toLinenumber(n.info)
|
||||
@@ -2209,9 +2208,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
|
||||
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)", true)
|
||||
of mSetLengthStr:
|
||||
binaryExpr(p, n, r, "mnewString",
|
||||
"""if ($1.length < $2) { for (var i = $3.length; i < $4; ++i) $3.push(0); }
|
||||
else {$3.length = $4; }""")
|
||||
binaryExpr(p, n, r, "mnewString", "($1.length = $2)")
|
||||
of mSetLengthSeq:
|
||||
var x, y: TCompRes
|
||||
gen(p, n[1], x)
|
||||
@@ -2484,18 +2481,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]
|
||||
@@ -2889,8 +2885,7 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||
# Generate an optional source map.
|
||||
if optSourcemap in m.config.globalOptions:
|
||||
var map: SourceMap
|
||||
map = genSourceMap($code, outFile.string)
|
||||
code &= "\n//# sourceMappingURL=$#.map" % [outFile.string]
|
||||
(code, map) = genSourceMap($(code), outFile.string)
|
||||
writeFile(outFile.string & ".map", $(%map))
|
||||
# Check if the generated JS code matches the output file, or else
|
||||
# write it to the file.
|
||||
|
||||
@@ -12,9 +12,7 @@
|
||||
import
|
||||
intsets, strutils, options, ast, astalgo, msgs,
|
||||
idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos,
|
||||
liftdestructors, typeallowed
|
||||
|
||||
from transf import nil
|
||||
transf, liftdestructors, typeallowed
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -443,7 +441,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
if innerProc:
|
||||
if s.isIterator: c.somethingToDo = true
|
||||
if not c.processed.containsOrIncl(s.id):
|
||||
let body = transf.transformBody(c.graph, c.idgen, s, transf.useCache)
|
||||
let body = transformBody(c.graph, c.idgen, s, useCache)
|
||||
detectCapturedVars(body, s, c)
|
||||
let ow = s.skipGenericOwner
|
||||
if ow == owner:
|
||||
@@ -739,7 +737,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
|
||||
# echo renderTree(s.getBody, {renderIds})
|
||||
let oldInContainer = c.inContainer
|
||||
c.inContainer = 0
|
||||
var body = transf.transformBody(d.graph, d.idgen, s, transf.dontUseCache)
|
||||
var body = transformBody(d.graph, d.idgen, s, dontUseCache)
|
||||
body = liftCapturedVars(body, s, d, c)
|
||||
if c.envVars.getOrDefault(s.id).isNil:
|
||||
s.transformedBody = body
|
||||
@@ -861,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 ...
|
||||
|
||||
@@ -870,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -609,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)
|
||||
@@ -637,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)
|
||||
|
||||
@@ -57,7 +57,6 @@ type
|
||||
warnRstBrokenLink = "BrokenLink",
|
||||
warnRstLanguageXNotSupported = "LanguageXNotSupported",
|
||||
warnRstFieldXNotSupported = "FieldXNotSupported",
|
||||
warnRstUnusedImportdoc = "UnusedImportdoc",
|
||||
warnRstStyle = "warnRstStyle",
|
||||
warnCommentXIgnored = "CommentXIgnored",
|
||||
warnTypelessParam = "TypelessParam",
|
||||
@@ -84,10 +83,8 @@ type
|
||||
warnPtrToCstringConv = "PtrToCstringConv",
|
||||
warnEffect = "Effect",
|
||||
warnCastSizes = "CastSizes"
|
||||
warnImplicitTemplateRedefinition = "ImplicitTemplateRedefinition",
|
||||
warnTemplateRedefinition = "TemplateRedefinition",
|
||||
warnUnnamedBreak = "UnnamedBreak",
|
||||
warnStmtListLambda = "StmtListLambda",
|
||||
warnBareExcept = "BareExcept",
|
||||
warnUser = "User",
|
||||
# hints
|
||||
hintSuccess = "Success", hintSuccessX = "SuccessX",
|
||||
@@ -143,7 +140,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
|
||||
@@ -185,10 +181,8 @@ const
|
||||
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future",
|
||||
warnEffect: "$1",
|
||||
warnCastSizes: "$1",
|
||||
warnImplicitTemplateRedefinition: "template '$1' is implicitly redefined; this is deprecated, add an explicit .redefine pragma",
|
||||
warnTemplateRedefinition: "template '$1' is implicitly redefined, consider adding 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`
|
||||
|
||||
@@ -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,7 +311,6 @@ 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.owner == conflict.owner:
|
||||
@@ -452,7 +422,7 @@ type SpellCandidate = object
|
||||
msg: string
|
||||
sym: PSym
|
||||
|
||||
template toOrderTup(a: SpellCandidate): (int, int, string) =
|
||||
template toOrderTup(a: SpellCandidate): auto =
|
||||
# `dist` is first, to favor nearby matches
|
||||
# `depth` is next, to favor nearby enclosing scopes among ties
|
||||
# `sym.name.s` is last, to make the list ordered and deterministic among ties
|
||||
@@ -475,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
|
||||
@@ -497,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 & "'"
|
||||
|
||||
297
compiler/md5_old.nim
Normal file
297
compiler/md5_old.nim
Normal file
@@ -0,0 +1,297 @@
|
||||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# `std/md5` without VM and JavaScript support, to circumvent a bug with
|
||||
# openarrays on Nim < 1.4.
|
||||
|
||||
when defined(nimHasStyleChecks):
|
||||
{.push styleChecks: off.}
|
||||
|
||||
type
|
||||
MD5State = array[0..3, uint32]
|
||||
MD5Block = array[0..15, uint32]
|
||||
MD5CBits = array[0..7, uint8]
|
||||
MD5Digest* = array[0..15, uint8]
|
||||
## MD5 checksum of a string, obtained with the `toMD5 proc <#toMD5,string>`_.
|
||||
MD5Buffer = array[0..63, uint8]
|
||||
MD5Context* {.final.} = object
|
||||
state: MD5State
|
||||
count: array[0..1, uint32]
|
||||
buffer: MD5Buffer
|
||||
|
||||
const
|
||||
padding: array[0..63, uint8] = [
|
||||
0x80'u8, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
]
|
||||
|
||||
proc F(x, y, z: uint32): uint32 {.inline.} =
|
||||
result = (x and y) or ((not x) and z)
|
||||
|
||||
proc G(x, y, z: uint32): uint32 {.inline.} =
|
||||
result = (x and z) or (y and (not z))
|
||||
|
||||
proc H(x, y, z: uint32): uint32 {.inline.} =
|
||||
result = x xor y xor z
|
||||
|
||||
proc I(x, y, z: uint32): uint32 {.inline.} =
|
||||
result = y xor (x or (not z))
|
||||
|
||||
proc rot(x: var uint32, n: uint8) {.inline.} =
|
||||
x = (x shl n) or (x shr (32'u32 - n))
|
||||
|
||||
proc FF(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + F(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a + b
|
||||
|
||||
proc GG(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + G(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a + b
|
||||
|
||||
proc HH(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + H(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a + b
|
||||
|
||||
proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + I(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a + b
|
||||
|
||||
proc encode(dest: var MD5Block, src: openArray[uint8]) =
|
||||
var j = 0
|
||||
for i in 0..high(dest):
|
||||
dest[i] = uint32(ord(src[j])) or
|
||||
uint32(ord(src[j+1])) shl 8 or
|
||||
uint32(ord(src[j+2])) shl 16 or
|
||||
uint32(ord(src[j+3])) shl 24
|
||||
inc(j, 4)
|
||||
|
||||
proc decode(dest: var openArray[uint8], src: openArray[uint32]) =
|
||||
var i = 0
|
||||
for j in 0..high(src):
|
||||
dest[i] = uint8(src[j] and 0xff'u32)
|
||||
dest[i+1] = uint8(src[j] shr 8 and 0xff'u32)
|
||||
dest[i+2] = uint8(src[j] shr 16 and 0xff'u32)
|
||||
dest[i+3] = uint8(src[j] shr 24 and 0xff'u32)
|
||||
inc(i, 4)
|
||||
|
||||
template slice(s: string | cstring, a, b): openArray[uint8] =
|
||||
s.toOpenArrayByte(a, b)
|
||||
|
||||
template slice(s: openArray[uint8], a, b): openArray[uint8] =
|
||||
s.toOpenArray(a, b)
|
||||
|
||||
proc transform(buffer: openArray[uint8], state: var MD5State) =
|
||||
var
|
||||
myBlock: MD5Block
|
||||
encode(myBlock, buffer)
|
||||
var a = state[0]
|
||||
var b = state[1]
|
||||
var c = state[2]
|
||||
var d = state[3]
|
||||
FF(a, b, c, d, myBlock[0], 7'u8, 0xD76AA478'u32)
|
||||
FF(d, a, b, c, myBlock[1], 12'u8, 0xE8C7B756'u32)
|
||||
FF(c, d, a, b, myBlock[2], 17'u8, 0x242070DB'u32)
|
||||
FF(b, c, d, a, myBlock[3], 22'u8, 0xC1BDCEEE'u32)
|
||||
FF(a, b, c, d, myBlock[4], 7'u8, 0xF57C0FAF'u32)
|
||||
FF(d, a, b, c, myBlock[5], 12'u8, 0x4787C62A'u32)
|
||||
FF(c, d, a, b, myBlock[6], 17'u8, 0xA8304613'u32)
|
||||
FF(b, c, d, a, myBlock[7], 22'u8, 0xFD469501'u32)
|
||||
FF(a, b, c, d, myBlock[8], 7'u8, 0x698098D8'u32)
|
||||
FF(d, a, b, c, myBlock[9], 12'u8, 0x8B44F7AF'u32)
|
||||
FF(c, d, a, b, myBlock[10], 17'u8, 0xFFFF5BB1'u32)
|
||||
FF(b, c, d, a, myBlock[11], 22'u8, 0x895CD7BE'u32)
|
||||
FF(a, b, c, d, myBlock[12], 7'u8, 0x6B901122'u32)
|
||||
FF(d, a, b, c, myBlock[13], 12'u8, 0xFD987193'u32)
|
||||
FF(c, d, a, b, myBlock[14], 17'u8, 0xA679438E'u32)
|
||||
FF(b, c, d, a, myBlock[15], 22'u8, 0x49B40821'u32)
|
||||
GG(a, b, c, d, myBlock[1], 5'u8, 0xF61E2562'u32)
|
||||
GG(d, a, b, c, myBlock[6], 9'u8, 0xC040B340'u32)
|
||||
GG(c, d, a, b, myBlock[11], 14'u8, 0x265E5A51'u32)
|
||||
GG(b, c, d, a, myBlock[0], 20'u8, 0xE9B6C7AA'u32)
|
||||
GG(a, b, c, d, myBlock[5], 5'u8, 0xD62F105D'u32)
|
||||
GG(d, a, b, c, myBlock[10], 9'u8, 0x02441453'u32)
|
||||
GG(c, d, a, b, myBlock[15], 14'u8, 0xD8A1E681'u32)
|
||||
GG(b, c, d, a, myBlock[4], 20'u8, 0xE7D3FBC8'u32)
|
||||
GG(a, b, c, d, myBlock[9], 5'u8, 0x21E1CDE6'u32)
|
||||
GG(d, a, b, c, myBlock[14], 9'u8, 0xC33707D6'u32)
|
||||
GG(c, d, a, b, myBlock[3], 14'u8, 0xF4D50D87'u32)
|
||||
GG(b, c, d, a, myBlock[8], 20'u8, 0x455A14ED'u32)
|
||||
GG(a, b, c, d, myBlock[13], 5'u8, 0xA9E3E905'u32)
|
||||
GG(d, a, b, c, myBlock[2], 9'u8, 0xFCEFA3F8'u32)
|
||||
GG(c, d, a, b, myBlock[7], 14'u8, 0x676F02D9'u32)
|
||||
GG(b, c, d, a, myBlock[12], 20'u8, 0x8D2A4C8A'u32)
|
||||
HH(a, b, c, d, myBlock[5], 4'u8, 0xFFFA3942'u32)
|
||||
HH(d, a, b, c, myBlock[8], 11'u8, 0x8771F681'u32)
|
||||
HH(c, d, a, b, myBlock[11], 16'u8, 0x6D9D6122'u32)
|
||||
HH(b, c, d, a, myBlock[14], 23'u8, 0xFDE5380C'u32)
|
||||
HH(a, b, c, d, myBlock[1], 4'u8, 0xA4BEEA44'u32)
|
||||
HH(d, a, b, c, myBlock[4], 11'u8, 0x4BDECFA9'u32)
|
||||
HH(c, d, a, b, myBlock[7], 16'u8, 0xF6BB4B60'u32)
|
||||
HH(b, c, d, a, myBlock[10], 23'u8, 0xBEBFBC70'u32)
|
||||
HH(a, b, c, d, myBlock[13], 4'u8, 0x289B7EC6'u32)
|
||||
HH(d, a, b, c, myBlock[0], 11'u8, 0xEAA127FA'u32)
|
||||
HH(c, d, a, b, myBlock[3], 16'u8, 0xD4EF3085'u32)
|
||||
HH(b, c, d, a, myBlock[6], 23'u8, 0x04881D05'u32)
|
||||
HH(a, b, c, d, myBlock[9], 4'u8, 0xD9D4D039'u32)
|
||||
HH(d, a, b, c, myBlock[12], 11'u8, 0xE6DB99E5'u32)
|
||||
HH(c, d, a, b, myBlock[15], 16'u8, 0x1FA27CF8'u32)
|
||||
HH(b, c, d, a, myBlock[2], 23'u8, 0xC4AC5665'u32)
|
||||
II(a, b, c, d, myBlock[0], 6'u8, 0xF4292244'u32)
|
||||
II(d, a, b, c, myBlock[7], 10'u8, 0x432AFF97'u32)
|
||||
II(c, d, a, b, myBlock[14], 15'u8, 0xAB9423A7'u32)
|
||||
II(b, c, d, a, myBlock[5], 21'u8, 0xFC93A039'u32)
|
||||
II(a, b, c, d, myBlock[12], 6'u8, 0x655B59C3'u32)
|
||||
II(d, a, b, c, myBlock[3], 10'u8, 0x8F0CCC92'u32)
|
||||
II(c, d, a, b, myBlock[10], 15'u8, 0xFFEFF47D'u32)
|
||||
II(b, c, d, a, myBlock[1], 21'u8, 0x85845DD1'u32)
|
||||
II(a, b, c, d, myBlock[8], 6'u8, 0x6FA87E4F'u32)
|
||||
II(d, a, b, c, myBlock[15], 10'u8, 0xFE2CE6E0'u32)
|
||||
II(c, d, a, b, myBlock[6], 15'u8, 0xA3014314'u32)
|
||||
II(b, c, d, a, myBlock[13], 21'u8, 0x4E0811A1'u32)
|
||||
II(a, b, c, d, myBlock[4], 6'u8, 0xF7537E82'u32)
|
||||
II(d, a, b, c, myBlock[11], 10'u8, 0xBD3AF235'u32)
|
||||
II(c, d, a, b, myBlock[2], 15'u8, 0x2AD7D2BB'u32)
|
||||
II(b, c, d, a, myBlock[9], 21'u8, 0xEB86D391'u32)
|
||||
state[0] = state[0] + a
|
||||
state[1] = state[1] + b
|
||||
state[2] = state[2] + c
|
||||
state[3] = state[3] + d
|
||||
|
||||
proc md5Init*(c: var MD5Context) {.raises: [], tags: [], gcsafe.}
|
||||
proc md5Update*(c: var MD5Context, input: openArray[uint8]) {.raises: [],
|
||||
tags: [], gcsafe.}
|
||||
proc md5Final*(c: var MD5Context, digest: var MD5Digest) {.raises: [], tags: [], gcsafe.}
|
||||
|
||||
proc md5Update*(c: var MD5Context, input: cstring, len: int) {.raises: [],
|
||||
tags: [], gcsafe.} =
|
||||
## Updates the `MD5Context` with the `input` data of length `len`.
|
||||
##
|
||||
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
|
||||
## function explicitly.
|
||||
md5Update(c, input.slice(0, len - 1))
|
||||
|
||||
|
||||
proc toMD5*(s: string): MD5Digest =
|
||||
## Computes the `MD5Digest` value for a string `s`.
|
||||
##
|
||||
## **See also:**
|
||||
## * `getMD5 proc <#getMD5,string>`_ which returns a string representation
|
||||
## of the `MD5Digest`
|
||||
## * `$ proc <#$,MD5Digest>`_ for converting MD5Digest to string
|
||||
runnableExamples:
|
||||
assert $toMD5("abc") == "900150983cd24fb0d6963f7d28e17f72"
|
||||
|
||||
var c: MD5Context
|
||||
md5Init(c)
|
||||
md5Update(c, s.slice(0, s.len - 1))
|
||||
md5Final(c, result)
|
||||
|
||||
proc `$`*(d: MD5Digest): string =
|
||||
## Converts a `MD5Digest` value into its string representation.
|
||||
const digits = "0123456789abcdef"
|
||||
result = ""
|
||||
for i in 0..15:
|
||||
add(result, digits[(d[i].int shr 4) and 0xF])
|
||||
add(result, digits[d[i].int and 0xF])
|
||||
|
||||
proc getMD5*(s: string): string =
|
||||
## Computes an MD5 value of `s` and returns its string representation.
|
||||
##
|
||||
## **See also:**
|
||||
## * `toMD5 proc <#toMD5,string>`_ which returns the `MD5Digest` of a string
|
||||
runnableExamples:
|
||||
assert getMD5("abc") == "900150983cd24fb0d6963f7d28e17f72"
|
||||
|
||||
var
|
||||
c: MD5Context
|
||||
d: MD5Digest
|
||||
md5Init(c)
|
||||
md5Update(c, s.slice(0, s.len - 1))
|
||||
md5Final(c, d)
|
||||
result = $d
|
||||
|
||||
proc `==`*(D1, D2: MD5Digest): bool =
|
||||
## Checks if two `MD5Digest` values are identical.
|
||||
for i in 0..15:
|
||||
if D1[i] != D2[i]: return false
|
||||
return true
|
||||
|
||||
|
||||
proc clearBuffer(c: var MD5Context) {.inline.} =
|
||||
zeroMem(addr(c.buffer), sizeof(MD5Buffer))
|
||||
|
||||
proc md5Init*(c: var MD5Context) =
|
||||
## Initializes an `MD5Context`.
|
||||
##
|
||||
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
|
||||
## function explicitly.
|
||||
c.state[0] = 0x67452301'u32
|
||||
c.state[1] = 0xEFCDAB89'u32
|
||||
c.state[2] = 0x98BADCFE'u32
|
||||
c.state[3] = 0x10325476'u32
|
||||
c.count[0] = 0'u32
|
||||
c.count[1] = 0'u32
|
||||
clearBuffer(c)
|
||||
|
||||
proc writeBuffer(c: var MD5Context, index: int,
|
||||
input: openArray[uint8], inputIndex, len: int) {.inline.} =
|
||||
copyMem(addr(c.buffer[index]), unsafeAddr(input[inputIndex]), len)
|
||||
|
||||
proc md5Update*(c: var MD5Context, input: openArray[uint8]) =
|
||||
## Updates the `MD5Context` with the `input` data.
|
||||
##
|
||||
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
|
||||
## function explicitly.
|
||||
var Index = int((c.count[0] shr 3) and 0x3F)
|
||||
c.count[0] = c.count[0] + (uint32(input.len) shl 3)
|
||||
if c.count[0] < (uint32(input.len) shl 3): c.count[1] = c.count[1] + 1'u32
|
||||
c.count[1] = c.count[1] + (uint32(input.len) shr 29)
|
||||
var PartLen = 64 - Index
|
||||
if input.len >= PartLen:
|
||||
writeBuffer(c, Index, input, 0, PartLen)
|
||||
transform(c.buffer, c.state)
|
||||
var i = PartLen
|
||||
while i + 63 < input.len:
|
||||
transform(input.slice(i, i + 63), c.state)
|
||||
inc(i, 64)
|
||||
if i < input.len:
|
||||
writeBuffer(c, 0, input, i, input.len - i)
|
||||
elif input.len > 0:
|
||||
writeBuffer(c, Index, input, 0, input.len)
|
||||
|
||||
proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
|
||||
## Finishes the `MD5Context` and stores the result in `digest`.
|
||||
##
|
||||
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
|
||||
## function explicitly.
|
||||
var
|
||||
Bits: MD5CBits
|
||||
PadLen: int
|
||||
decode(Bits, c.count)
|
||||
var Index = int((c.count[0] shr 3) and 0x3F)
|
||||
if Index < 56: PadLen = 56 - Index
|
||||
else: PadLen = 120 - Index
|
||||
md5Update(c, padding.slice(0, PadLen - 1))
|
||||
md5Update(c, Bits)
|
||||
decode(digest, c.state)
|
||||
clearBuffer(c)
|
||||
|
||||
|
||||
when defined(nimHasStyleChecks):
|
||||
{.pop.} #{.push styleChecks: off.}
|
||||
@@ -11,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]
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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,9 +193,10 @@ 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!
|
||||
implicitDeref, # deadcode; remains here for backwards compatibility
|
||||
dotOperators,
|
||||
callOperator,
|
||||
parallel,
|
||||
@@ -234,7 +232,6 @@ type
|
||||
## are not anymore.
|
||||
laxEffects
|
||||
## Lax effects system prior to Nim 2.0.
|
||||
verboseTypeMismatch
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
|
||||
@@ -279,9 +276,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 +406,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:
|
||||
@@ -468,7 +457,7 @@ when false:
|
||||
fn(globalOptions)
|
||||
fn(selectedGC)
|
||||
|
||||
const oldExperimentalFeatures* = {dotOperators, callOperator, parallel}
|
||||
const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel}
|
||||
|
||||
const
|
||||
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck,
|
||||
@@ -717,24 +706,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.
|
||||
@@ -878,8 +865,7 @@ const stdlibDirs* = [
|
||||
"pure/concurrency",
|
||||
"pure/unidecode", "impure",
|
||||
"wrappers", "wrappers/linenoise",
|
||||
"windows", "posix", "js",
|
||||
"deprecated/pure"]
|
||||
"windows", "posix", "js"]
|
||||
|
||||
const
|
||||
pkgPrefix = "pkg/"
|
||||
@@ -1007,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
|
||||
@@ -1052,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"
|
||||
|
||||
@@ -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
|
||||
@@ -79,7 +79,7 @@ type
|
||||
smNormal, smAllowNil, smAfterDot
|
||||
|
||||
PrimaryMode = enum
|
||||
pmNormal, pmTypeDesc, pmTypeDef, pmTrySimple
|
||||
pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix
|
||||
|
||||
proc parseAll*(p: var Parser): PNode
|
||||
proc closeParser*(p: var Parser)
|
||||
@@ -286,8 +286,7 @@ proc newIdentNodeP(ident: PIdent, p: Parser): PNode =
|
||||
|
||||
proc parseExpr(p: var Parser): PNode
|
||||
proc parseStmt(p: var Parser): PNode
|
||||
proc parseTypeDesc(p: var Parser, fullExpr = false): PNode
|
||||
proc parseTypeDefValue(p: var Parser): PNode
|
||||
proc parseTypeDesc(p: var Parser): PNode
|
||||
proc parseParamList(p: var Parser, retColon = true): PNode
|
||||
|
||||
proc isSigilLike(tok: Token): bool {.inline.} =
|
||||
@@ -354,12 +353,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,17 +405,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:
|
||||
result = newNodeP(nkExprEqExpr, p)
|
||||
getTok(p)
|
||||
#optInd(p, result)
|
||||
result.add(a)
|
||||
result.add(parseExpr(p))
|
||||
else:
|
||||
result = a
|
||||
|
||||
proc colonOrEquals(p: var Parser, a: PNode): PNode =
|
||||
if p.tok.tokType == tkColon:
|
||||
@@ -432,8 +414,14 @@ proc colonOrEquals(p: var Parser, a: PNode): PNode =
|
||||
#optInd(p, result)
|
||||
result.add(a)
|
||||
result.add(parseExpr(p))
|
||||
elif p.tok.tokType == tkEquals:
|
||||
result = newNodeP(nkExprEqExpr, p)
|
||||
getTok(p)
|
||||
#optInd(p, result)
|
||||
result.add(a)
|
||||
result.add(parseExpr(p))
|
||||
else:
|
||||
result = equals(p, a)
|
||||
result = a
|
||||
|
||||
proc exprColonEqExpr(p: var Parser): PNode =
|
||||
#| exprColonEqExpr = expr (':'|'=' expr)?
|
||||
@@ -443,14 +431,6 @@ proc exprColonEqExpr(p: var Parser): PNode =
|
||||
else:
|
||||
result = colonOrEquals(p, a)
|
||||
|
||||
proc exprEqExpr(p: var Parser): PNode =
|
||||
#| exprEqExpr = expr ('=' expr)?
|
||||
var a = parseExpr(p)
|
||||
if p.tok.tokType == tkDo:
|
||||
result = postExprBlocks(p, a)
|
||||
else:
|
||||
result = equals(p, a)
|
||||
|
||||
proc exprList(p: var Parser, endTok: TokType, result: PNode) =
|
||||
#| exprList = expr ^+ comma
|
||||
when defined(nimpretty):
|
||||
@@ -458,24 +438,6 @@ proc exprList(p: var Parser, endTok: TokType, result: PNode) =
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
# progress guaranteed
|
||||
var a = parseExpr(p)
|
||||
result.add(a)
|
||||
while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof):
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
var a = parseExpr(p)
|
||||
result.add(a)
|
||||
when defined(nimpretty):
|
||||
dec p.em.doIndentMore
|
||||
|
||||
proc optionalExprList(p: var Parser, endTok: TokType, result: PNode) =
|
||||
#| optionalExprList = expr ^* comma
|
||||
when defined(nimpretty):
|
||||
inc p.em.doIndentMore
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
# progress guaranteed
|
||||
while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof):
|
||||
var a = parseExpr(p)
|
||||
result.add(a)
|
||||
@@ -584,7 +546,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 +568,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 +672,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
|
||||
@@ -843,24 +802,25 @@ proc namedParams(p: var Parser, callee: PNode,
|
||||
proc commandParam(p: var Parser, isFirstParam: var bool; mode: PrimaryMode): PNode =
|
||||
if mode == pmTypeDesc:
|
||||
result = simpleExpr(p, mode)
|
||||
elif not isFirstParam:
|
||||
result = exprEqExpr(p)
|
||||
else:
|
||||
result = parseExpr(p)
|
||||
if p.tok.tokType == tkDo:
|
||||
result = postExprBlocks(p, result)
|
||||
if p.tok.tokType == tkDo:
|
||||
result = postExprBlocks(p, result)
|
||||
elif p.tok.tokType == tkEquals and not isFirstParam:
|
||||
let lhs = result
|
||||
result = newNodeP(nkExprEqExpr, p)
|
||||
getTok(p)
|
||||
result.add(lhs)
|
||||
result.add(parseExpr(p))
|
||||
isFirstParam = false
|
||||
|
||||
proc commandExpr(p: var Parser; r: PNode; mode: PrimaryMode): PNode =
|
||||
if mode == pmTrySimple:
|
||||
result = r
|
||||
else:
|
||||
result = newNodeP(nkCommand, p)
|
||||
result.add(r)
|
||||
var isFirstParam = true
|
||||
# progress NOT guaranteed
|
||||
p.hasProgress = false
|
||||
result.add commandParam(p, isFirstParam, mode)
|
||||
result = newNodeP(nkCommand, p)
|
||||
result.add(r)
|
||||
var isFirstParam = true
|
||||
# progress NOT guaranteed
|
||||
p.hasProgress = false
|
||||
result.add commandParam(p, isFirstParam, mode)
|
||||
|
||||
proc isDotLike(tok: Token): bool =
|
||||
result = tok.tokType == tkOpr and tok.ident.s.len > 1 and
|
||||
@@ -873,7 +833,7 @@ proc primarySuffix(p: var Parser, r: PNode,
|
||||
#| | DOTLIKEOP optInd symbol generalizedLit?
|
||||
#| | '[' optInd exprColonEqExprList optPar ']'
|
||||
#| | '{' optInd exprColonEqExprList optPar '}'
|
||||
# XXX strong spaces need to be reflected above
|
||||
#| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr (comma expr)* # command syntax
|
||||
result = r
|
||||
|
||||
# progress guaranteed
|
||||
@@ -884,6 +844,13 @@ proc primarySuffix(p: var Parser, r: PNode,
|
||||
# progress guaranteed
|
||||
if p.tok.strongSpaceA:
|
||||
result = commandExpr(p, result, mode)
|
||||
# type sections allow full command syntax
|
||||
if mode == pmTypeDef:
|
||||
var isFirstParam = false
|
||||
while p.tok.tokType == tkComma:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.add(commandParam(p, isFirstParam, mode))
|
||||
break
|
||||
result = namedParams(p, result, nkCall, tkParRi)
|
||||
if result.len > 1 and result[1].kind == nkExprColonExpr:
|
||||
@@ -924,9 +891,18 @@ proc primarySuffix(p: var Parser, r: PNode,
|
||||
# actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
|
||||
# solution, but pragmas.nim can't handle that
|
||||
result = commandExpr(p, result, mode)
|
||||
if mode == pmTypeDef:
|
||||
var isFirstParam = false
|
||||
while p.tok.tokType == tkComma:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.add(commandParam(p, isFirstParam, mode))
|
||||
break
|
||||
else:
|
||||
break
|
||||
# type sections allow post-expr blocks
|
||||
if mode == pmTypeDef:
|
||||
result = postExprBlocks(p, result)
|
||||
|
||||
proc parseOperators(p: var Parser, headNode: PNode,
|
||||
limit: int, mode: PrimaryMode): PNode =
|
||||
@@ -951,13 +927,9 @@ 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
|
||||
result = primary(p, mode)
|
||||
if mode == pmTrySimple:
|
||||
mode = pmNormal
|
||||
if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)) and
|
||||
mode == pmNormal:
|
||||
var pragmaExp = newNodeP(nkPragmaExpr, p)
|
||||
@@ -1001,7 +973,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
|
||||
@@ -1039,9 +1010,9 @@ type
|
||||
|
||||
proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode =
|
||||
#| declColonEquals = identWithPragma (comma identWithPragma)* comma?
|
||||
#| (':' optInd typeDescExpr)? ('=' optInd expr)?
|
||||
#| (':' optInd typeDesc)? ('=' optInd expr)?
|
||||
#| identColonEquals = IDENT (comma IDENT)* comma?
|
||||
#| (':' optInd typeDescExpr)? ('=' optInd expr)?)
|
||||
#| (':' optInd typeDesc)? ('=' optInd expr)?)
|
||||
var a: PNode
|
||||
result = newNodeP(nkIdentDefs, p)
|
||||
# progress guaranteed
|
||||
@@ -1059,7 +1030,7 @@ proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode =
|
||||
if p.tok.tokType == tkColon:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.add(parseTypeDesc(p, fullExpr = true))
|
||||
result.add(parseTypeDesc(p))
|
||||
else:
|
||||
result.add(newNodeP(nkEmpty, p))
|
||||
if p.tok.tokType != tkEquals and withBothOptional notin flags:
|
||||
@@ -1070,13 +1041,11 @@ 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 ']'
|
||||
#| tupleType = 'tuple' tupleTypeBracket
|
||||
#| tupleDecl = 'tuple' (tupleTypeBracket /
|
||||
#| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?)
|
||||
#| tupleDecl = 'tuple'
|
||||
#| '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' |
|
||||
#| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
|
||||
result = newNodeP(nkTupleTy, p)
|
||||
getTok(p)
|
||||
if p.tok.tokType == tkBracketLe:
|
||||
@@ -1115,7 +1084,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 +1132,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,11 +1152,9 @@ 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)?
|
||||
#| routineType = ('proc' | 'iterator') paramListColon pragma?
|
||||
# either a proc type or a anonymous proc
|
||||
let info = parLineInfo(p)
|
||||
let hasSignature = p.tok.tokType in {tkParLe, tkColon} and p.tok.indent < 0
|
||||
@@ -1208,14 +1173,13 @@ 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
|
||||
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkFor,
|
||||
tkProc, tkFunc, tkIterator, tkBind, tkBuiltInMagics,
|
||||
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCustomLit, tkVar, tkRef, tkPtr,
|
||||
tkEnum, tkTuple, tkObject, tkWhen, tkCase, tkOut, tkTry, tkBlock:
|
||||
tkTuple, tkObject, tkWhen, tkCase, tkOut, tkTry, tkBlock:
|
||||
result = true
|
||||
else: result = false
|
||||
|
||||
@@ -1228,7 +1192,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 =
|
||||
@@ -1236,12 +1199,8 @@ proc parseTypeDescKAux(p: var Parser, kind: TNodeKind,
|
||||
getTok(p)
|
||||
if p.tok.indent != -1 and p.tok.indent <= p.currInd: return
|
||||
optInd(p, result)
|
||||
let isTypedef = mode == pmTypeDef and p.tok.tokType in {tkObject, tkTuple}
|
||||
if not isOperator(p.tok) and isExprStart(p):
|
||||
if isTypedef:
|
||||
result.add(parseTypeDefValue(p))
|
||||
else:
|
||||
result.add(primary(p, mode))
|
||||
result.add(primary(p, mode))
|
||||
if kind == nkDistinctTy and p.tok.tokType == tkSymbol:
|
||||
# XXX document this feature!
|
||||
var nodeKind: TNodeKind
|
||||
@@ -1255,14 +1214,11 @@ proc parseTypeDescKAux(p: var Parser, kind: TNodeKind,
|
||||
let list = newNodeP(nodeKind, p)
|
||||
result.add list
|
||||
parseSymbolList(p, list)
|
||||
if mode == pmTypeDef and not isTypedef:
|
||||
result = parseOperators(p, result, -1, mode)
|
||||
setEndInfo()
|
||||
|
||||
proc parseVarTuple(p: var Parser): PNode
|
||||
|
||||
proc parseFor(p: var Parser): PNode =
|
||||
#| forStmt = 'for' ((varTuple / identWithPragma) ^+ comma) 'in' expr colcom stmt
|
||||
#| forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
|
||||
#| forExpr = forStmt
|
||||
getTokNoInd(p)
|
||||
result = newNodeP(nkForStmt, p)
|
||||
@@ -1283,7 +1239,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,25 +1277,17 @@ 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
|
||||
proc parseTypeClass(p: var Parser): PNode
|
||||
|
||||
proc primary(p: var Parser, mode: PrimaryMode): PNode =
|
||||
#| simplePrimary = SIGILLIKEOP? identOrLiteral primarySuffix*
|
||||
#| commandStart = &('`'|IDENT|literal|'cast'|'addr'|'type'|'var'|'out'|
|
||||
#| 'static'|'enum'|'tuple'|'object'|'proc')
|
||||
#| primary = simplePrimary (commandStart expr)
|
||||
#| / operatorB primary
|
||||
#| / routineExpr
|
||||
#| / rawTypeDesc
|
||||
#| / prefixOperator primary
|
||||
# XXX strong spaces need to be reflected in commandStart
|
||||
# command part is handled in the primarySuffix proc
|
||||
|
||||
# prefix operators:
|
||||
#| primary = operatorB primary primarySuffix* |
|
||||
#| tupleDecl | routineExpr | enumDecl
|
||||
#| objectDecl | conceptDecl | ('bind' primary)
|
||||
#| ('var' | 'out' | 'ref' | 'ptr' | 'distinct') primary
|
||||
#| / prefixOperator* identOrLiteral primarySuffix*
|
||||
if isOperator(p.tok):
|
||||
# Note 'sigil like' operators are currently not reflected in the grammar
|
||||
# and should be removed for Nim 2.0, I don't think anybody uses them.
|
||||
@@ -1350,39 +1297,60 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode =
|
||||
result.add(a)
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
const identOrLiteralKinds = tkBuiltInMagics + {tkSymbol, tkAccent, tkNil,
|
||||
tkIntLit..tkCustomLit, tkCast, tkOut, tkParLe, tkBracketLe, tkCurlyLe}
|
||||
if isSigil and p.tok.tokType in identOrLiteralKinds:
|
||||
if isSigil:
|
||||
#XXX prefix operators
|
||||
let baseInd = p.lex.currLineIndent
|
||||
result.add(identOrLiteral(p, mode))
|
||||
result.add(primary(p, pmSkipSuffix))
|
||||
result = primarySuffix(p, result, baseInd, mode)
|
||||
else:
|
||||
result.add(primary(p, pmNormal))
|
||||
return
|
||||
|
||||
case p.tok.tokType
|
||||
of tkTuple: result = parseTuple(p, mode == pmTypeDef)
|
||||
of tkProc:
|
||||
getTok(p)
|
||||
result = parseProcExpr(p, mode != pmTypeDesc, nkLambda)
|
||||
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkLambda)
|
||||
of tkFunc:
|
||||
getTok(p)
|
||||
result = parseProcExpr(p, mode != pmTypeDesc, nkFuncDef)
|
||||
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkFuncDef)
|
||||
of tkIterator:
|
||||
getTok(p)
|
||||
result = parseProcExpr(p, mode != pmTypeDesc, nkIteratorDef)
|
||||
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkIteratorDef)
|
||||
of tkEnum:
|
||||
if mode == pmTypeDef:
|
||||
prettySection:
|
||||
result = parseEnum(p)
|
||||
else:
|
||||
result = newNodeP(nkEnumTy, p)
|
||||
getTok(p)
|
||||
of tkObject:
|
||||
if mode == pmTypeDef:
|
||||
prettySection:
|
||||
result = parseObject(p)
|
||||
else:
|
||||
result = newNodeP(nkObjectTy, p)
|
||||
getTok(p)
|
||||
of tkConcept:
|
||||
if mode == pmTypeDef:
|
||||
result = parseTypeClass(p)
|
||||
else:
|
||||
parMessage(p, "the 'concept' keyword is only valid in 'type' sections")
|
||||
of tkBind:
|
||||
# legacy syntax, no-op in current nim
|
||||
result = newNodeP(nkBind, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.add(primary(p, pmNormal))
|
||||
of tkTuple, tkEnum, tkObject, tkConcept,
|
||||
tkVar, tkOut, tkRef, tkPtr, tkDistinct:
|
||||
result = parseTypeDesc(p)
|
||||
of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode)
|
||||
of tkOut: result = parseTypeDescKAux(p, nkOutTy, mode)
|
||||
of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
|
||||
of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
|
||||
of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode)
|
||||
else:
|
||||
let baseInd = p.lex.currLineIndent
|
||||
result = identOrLiteral(p, mode)
|
||||
result = primarySuffix(p, result, baseInd, mode)
|
||||
if mode != pmSkipSuffix:
|
||||
result = primarySuffix(p, result, baseInd, mode)
|
||||
|
||||
proc binaryNot(p: var Parser; a: PNode): PNode =
|
||||
if p.tok.tokType == tkNot:
|
||||
@@ -1397,73 +1365,17 @@ proc binaryNot(p: var Parser; a: PNode): PNode =
|
||||
else:
|
||||
result = a
|
||||
|
||||
proc parseTypeDesc(p: var Parser, fullExpr = false): PNode =
|
||||
#| rawTypeDesc = (tupleType | routineType | 'enum' | 'object' |
|
||||
#| ('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?)
|
||||
#| ('not' expr)?
|
||||
#| typeDescExpr = (routineType / simpleExpr) ('not' expr)?
|
||||
#| typeDesc = rawTypeDesc / typeDescExpr
|
||||
proc parseTypeDesc(p: var Parser): PNode =
|
||||
#| typeDesc = simpleExpr ('not' expr)?
|
||||
newlineWasSplitting(p)
|
||||
if fullExpr:
|
||||
result = simpleExpr(p, pmTypeDesc)
|
||||
else:
|
||||
case p.tok.tokType
|
||||
of tkTuple:
|
||||
result = parseTuple(p, false)
|
||||
of tkProc:
|
||||
getTok(p)
|
||||
result = parseProcExpr(p, false, nkLambda)
|
||||
of tkIterator:
|
||||
getTok(p)
|
||||
result = parseProcExpr(p, false, nkIteratorDef)
|
||||
of tkEnum:
|
||||
result = newNodeP(nkEnumTy, p)
|
||||
getTok(p)
|
||||
of tkObject:
|
||||
result = newNodeP(nkObjectTy, p)
|
||||
getTok(p)
|
||||
of tkConcept:
|
||||
parMessage(p, "the 'concept' keyword is only valid in 'type' sections")
|
||||
of tkVar: result = parseTypeDescKAux(p, nkVarTy, pmTypeDesc)
|
||||
of tkOut: result = parseTypeDescKAux(p, nkOutTy, pmTypeDesc)
|
||||
of tkRef: result = parseTypeDescKAux(p, nkRefTy, pmTypeDesc)
|
||||
of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, pmTypeDesc)
|
||||
of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, pmTypeDesc)
|
||||
else:
|
||||
result = simpleExpr(p, pmTypeDesc)
|
||||
result = simpleExpr(p, pmTypeDesc)
|
||||
result = binaryNot(p, result)
|
||||
setEndInfo()
|
||||
|
||||
proc parseTypeDefValue(p: var Parser): PNode =
|
||||
#| typeDefValue = ((tupleDecl | enumDecl | objectDecl | conceptDecl |
|
||||
#| ('ref' | 'ptr' | 'distinct') (tupleDecl | objectDecl))
|
||||
#| / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)?))
|
||||
#| ('not' expr)?
|
||||
case p.tok.tokType
|
||||
of tkTuple: result = parseTuple(p, true)
|
||||
of tkRef: result = parseTypeDescKAux(p, nkRefTy, pmTypeDef)
|
||||
of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, pmTypeDef)
|
||||
of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, pmTypeDef)
|
||||
of tkEnum:
|
||||
prettySection:
|
||||
result = parseEnum(p)
|
||||
of tkObject:
|
||||
prettySection:
|
||||
result = parseObject(p)
|
||||
of tkConcept:
|
||||
result = parseTypeClass(p)
|
||||
else:
|
||||
result = simpleExpr(p, pmTypeDef)
|
||||
if p.tok.tokType != tkNot:
|
||||
if result.kind == nkCommand:
|
||||
var isFirstParam = false
|
||||
while p.tok.tokType == tkComma:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.add(commandParam(p, isFirstParam, pmTypeDef))
|
||||
result = postExprBlocks(p, result)
|
||||
proc parseTypeDefAux(p: var Parser): PNode =
|
||||
#| typeDefAux = simpleExpr ('not' expr
|
||||
#| | postExprBlocks)?
|
||||
result = simpleExpr(p, pmTypeDef)
|
||||
result = binaryNot(p, result)
|
||||
setEndInfo()
|
||||
|
||||
proc makeCall(n: PNode): PNode =
|
||||
## Creates a call if the given node isn't already a call.
|
||||
@@ -1477,7 +1389,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
|
||||
#| postExprBlocks = ':' stmt? ( IND{=} doBlock
|
||||
#| | IND{=} 'of' exprList ':' stmt
|
||||
#| | IND{=} 'elif' expr ':' stmt
|
||||
#| | IND{=} 'except' optionalExprList ':' stmt
|
||||
#| | IND{=} 'except' exprList ':' stmt
|
||||
#| | IND{=} 'finally' ':' stmt
|
||||
#| | IND{=} 'else' ':' stmt )*
|
||||
result = x
|
||||
@@ -1535,7 +1447,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
|
||||
nextBlock.add parseExpr(p)
|
||||
of tkExcept:
|
||||
nextBlock = newNodeP(nkExceptBranch, p)
|
||||
optionalExprList(p, tkColon, nextBlock)
|
||||
exprList(p, tkColon, nextBlock)
|
||||
of tkFinally:
|
||||
nextBlock = newNodeP(nkFinally, p)
|
||||
getTok(p)
|
||||
@@ -1555,10 +1467,12 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
|
||||
parMessage(p, "expected ':'")
|
||||
|
||||
proc parseExprStmt(p: var Parser): PNode =
|
||||
#| exprStmt = simpleExpr postExprBlocks?
|
||||
#| / simplePrimary (exprEqExpr ^+ comma) postExprBlocks?
|
||||
#| / simpleExpr '=' optInd (expr postExprBlocks?)
|
||||
var a = simpleExpr(p, pmTrySimple)
|
||||
#| exprStmt = simpleExpr
|
||||
#| (( '=' optInd expr colonBody? )
|
||||
#| / ( expr ^+ comma
|
||||
#| postExprBlocks
|
||||
#| ))?
|
||||
var a = simpleExpr(p)
|
||||
if p.tok.tokType == tkEquals:
|
||||
result = newNodeP(nkAsgn, p)
|
||||
getTok(p)
|
||||
@@ -1568,23 +1482,25 @@ proc parseExprStmt(p: var Parser): PNode =
|
||||
result.add(a)
|
||||
result.add(b)
|
||||
else:
|
||||
# simpleExpr parsed 'p a' from 'p a, b'?
|
||||
var isFirstParam = false
|
||||
# if an expression is starting here, a simplePrimary was parsed and
|
||||
# this is the start of a command
|
||||
if p.tok.indent < 0 and isExprStart(p):
|
||||
if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand:
|
||||
result = a
|
||||
while true:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.add(commandParam(p, isFirstParam, pmNormal))
|
||||
if p.tok.tokType != tkComma: break
|
||||
elif p.tok.indent < 0 and isExprStart(p):
|
||||
result = newTreeI(nkCommand, a.info, a)
|
||||
let baseIndent = p.currInd
|
||||
while true:
|
||||
result.add(commandParam(p, isFirstParam, pmNormal))
|
||||
if p.tok.tokType != tkComma or
|
||||
(p.tok.indent >= 0 and p.tok.indent < baseIndent):
|
||||
break
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
else:
|
||||
result = a
|
||||
result = postExprBlocks(p, result)
|
||||
setEndInfo()
|
||||
|
||||
proc parseModuleName(p: var Parser, kind: TNodeKind): PNode =
|
||||
result = parseExpr(p)
|
||||
@@ -1596,7 +1512,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 +1540,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 +1556,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 +1576,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 +1597,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 +1621,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 +1645,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 +1654,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,27 +1701,24 @@ 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')
|
||||
#| (IND{=}? 'except' optionalExprList colcom stmt)*
|
||||
#| (IND{=}? 'except' exprList colcom stmt)*
|
||||
#| (IND{=}? 'finally' colcom stmt)?
|
||||
#| tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
|
||||
#| (optInd 'except' optionalExprList colcom stmt)*
|
||||
#| (optInd 'except' exprList 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)
|
||||
optionalExprList(p, tkColon, b)
|
||||
exprList(p, tkColon, b)
|
||||
of tkFinally:
|
||||
b = newNodeP(nkFinally, p)
|
||||
getTok(p)
|
||||
@@ -1822,14 +1727,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 +1743,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 +1751,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 +1767,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 +1802,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 +1820,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 +1870,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 +1905,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 +1951,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 +1976,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 +2017,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 +2049,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 +2069,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 +2086,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,11 +2129,10 @@ proc parseTypeClass(p: var Parser): PNode =
|
||||
result.add(p.emptyNode)
|
||||
else:
|
||||
result.add(parseStmt(p))
|
||||
setEndInfo()
|
||||
|
||||
proc parseTypeDef(p: var Parser): PNode =
|
||||
#|
|
||||
#| typeDef = identVisDot genericParamList? pragma '=' optInd typeDefValue
|
||||
#| typeDef = identVisDot genericParamList? pragma '=' optInd typeDefAux
|
||||
#| indAndComment?
|
||||
result = newNodeP(nkTypeDef, p)
|
||||
var identifier = identVis(p, allowDot=true)
|
||||
@@ -2270,11 +2158,10 @@ proc parseTypeDef(p: var Parser): PNode =
|
||||
result.info = parLineInfo(p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.add(parseTypeDefValue(p))
|
||||
result.add(parseTypeDefAux(p))
|
||||
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 +2178,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 +2190,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 +2209,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 +2224,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 +2235,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 +2377,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 +2392,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 +2425,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 +2436,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)
|
||||
|
||||
@@ -81,8 +81,7 @@ const
|
||||
wGuard, wGoto, wCursor, wNoalias, wAlign}
|
||||
constPragmas* = declPragmas + {wHeader, wMagic,
|
||||
wGensym, wInject,
|
||||
wIntDefine, wStrDefine, wBoolDefine, wDefine,
|
||||
wCompilerProc, wCore}
|
||||
wIntDefine, wStrDefine, wBoolDefine, wCompilerProc, wCore}
|
||||
paramPragmas* = {wNoalias, wInject, wGensym}
|
||||
letPragmas* = varPragmas
|
||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect,
|
||||
@@ -477,16 +476,8 @@ proc processPop(c: PContext, n: PNode) =
|
||||
when defined(debugOptions):
|
||||
echo c.config $ n.info, " POP config is now ", c.config.options
|
||||
|
||||
proc processDefineConst(c: PContext, n: PNode, sym: PSym, kind: TMagic) =
|
||||
sym.magic = kind
|
||||
if n.kind in nkPragmaCallKinds and n.len == 2:
|
||||
# could also use TLib
|
||||
n[1] = getStrLitNode(c, n)
|
||||
|
||||
proc processDefine(c: PContext, n: PNode, sym: PSym) =
|
||||
if sym != nil and sym.kind == skConst:
|
||||
processDefineConst(c, n, sym, mGenericDefine)
|
||||
elif (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent):
|
||||
proc processDefine(c: PContext, n: PNode) =
|
||||
if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent):
|
||||
defineSymbol(c.config.symbols, n[1].ident.s)
|
||||
else:
|
||||
invalidPragma(c, n)
|
||||
@@ -513,11 +504,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])
|
||||
@@ -1078,7 +1066,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
recordPragma(c, it, "error", s)
|
||||
localError(c.config, it.info, errUser, s)
|
||||
of wFatal: fatal(c.config, it.info, expectStrLit(c, it))
|
||||
of wDefine: processDefine(c, it, sym)
|
||||
of wDefine: processDefine(c, it)
|
||||
of wUndef: processUndef(c, it)
|
||||
of wCompile: processCompile(c, it)
|
||||
of wLink: processLink(c, it)
|
||||
@@ -1225,11 +1213,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
noVal(c, it)
|
||||
sym.flags.incl sfBase
|
||||
of wIntDefine:
|
||||
processDefineConst(c, n, sym, mIntDefine)
|
||||
sym.magic = mIntDefine
|
||||
of wStrDefine:
|
||||
processDefineConst(c, n, sym, mStrDefine)
|
||||
sym.magic = mStrDefine
|
||||
of wBoolDefine:
|
||||
processDefineConst(c, n, sym, mBoolDefine)
|
||||
sym.magic = mBoolDefine
|
||||
of wUsed:
|
||||
noVal(c, it)
|
||||
if sym == nil: invalidPragma(c, it)
|
||||
|
||||
@@ -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
|
||||
TRenderFlags* = set[TRenderFlag]
|
||||
TRenderTok* = object
|
||||
kind*: TokType
|
||||
@@ -434,24 +434,6 @@ proc lsons(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
|
||||
result = 0
|
||||
for i in start..n.len + theEnd: inc(result, lsub(g, n[i]))
|
||||
|
||||
proc origUsingType(n: PNode): PSym {.inline.} =
|
||||
## Returns the type that a parameter references. Check with referencesUsing first
|
||||
## to check `n` is actually referencing a using node
|
||||
# If the node is untyped the typ field will be nil
|
||||
if n[0].sym.typ != nil:
|
||||
n[0].sym.typ.sym
|
||||
else: nil
|
||||
|
||||
proc referencesUsing(n: PNode): bool =
|
||||
## Returns true if n references a using statement.
|
||||
## e.g. proc foo(x) # x doesn't have type or def value so it references a using
|
||||
result = n.kind == nkIdentDefs and
|
||||
# Sometimes the node might not have been semmed (e.g. doc0) and will be nkIdent instead
|
||||
n[0].kind == nkSym and
|
||||
# Templates/macros can have parameters with no type (But their orig type will be nil)
|
||||
n.origUsingType != nil and
|
||||
n[1].kind == nkEmpty and n[2].kind == nkEmpty
|
||||
|
||||
proc lsub(g: TSrcGen; n: PNode): int =
|
||||
# computes the length of a tree
|
||||
if isNil(n): return 0
|
||||
@@ -492,11 +474,8 @@ proc lsub(g: TSrcGen; n: PNode): int =
|
||||
of nkDo: result = lsons(g, n) + len("do__:_")
|
||||
of nkConstDef, nkIdentDefs:
|
||||
result = lcomma(g, n, 0, - 3)
|
||||
if n.referencesUsing:
|
||||
result += lsub(g, newSymNode(n.origUsingType)) + 2
|
||||
else:
|
||||
if n[^2].kind != nkEmpty: result += lsub(g, n[^2]) + 2
|
||||
if n[^1].kind != nkEmpty: result += lsub(g, n[^1]) + 3
|
||||
if n[^2].kind != nkEmpty: result += lsub(g, n[^2]) + 2
|
||||
if n[^1].kind != nkEmpty: result += lsub(g, n[^1]) + 3
|
||||
of nkVarTuple:
|
||||
if n[^1].kind == nkEmpty:
|
||||
result = lcomma(g, n, 0, - 2) + len("()")
|
||||
@@ -619,9 +598,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 +630,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
|
||||
@@ -1283,12 +1260,8 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
||||
gsub(g, n, 0)
|
||||
of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString:
|
||||
if renderIds in g.flags:
|
||||
put(g, tkAddr, $n.kind)
|
||||
put(g, tkParLe, "(")
|
||||
putWithSpace(g, tkAddr, $n.kind)
|
||||
gsub(g, n, 0)
|
||||
if renderIds in g.flags:
|
||||
put(g, tkParRi, ")")
|
||||
|
||||
of nkLambda:
|
||||
putWithSpace(g, tkProc, "proc")
|
||||
gsub(g, n, paramsPos)
|
||||
@@ -1307,11 +1280,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
||||
gcomma(g, n, 0, -3)
|
||||
if n.len >= 2 and n[^2].kind != nkEmpty:
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gsub(g, n[^2], c)
|
||||
elif n.referencesUsing and renderExpandUsing in g.flags:
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gsub(g, newSymNode(n.origUsingType), c)
|
||||
|
||||
gsub(g, n, n.len - 2)
|
||||
if n.len >= 1 and n[^1].kind != nkEmpty:
|
||||
put(g, tkSpaces, Space)
|
||||
putWithSpace(g, tkEquals, "=")
|
||||
@@ -1482,11 +1451,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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -81,7 +81,7 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
|
||||
proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode =
|
||||
let x = arg.skipConv
|
||||
if (x.kind == nkCurly and formal.kind == tySet and formal.base.kind != tyGenericParam) or
|
||||
(x.kind in {nkPar, nkTupleConstr}) and formal.kind notin {tyUntyped, tyBuiltInTypeClass, tyAnything}:
|
||||
(x.kind in {nkPar, nkTupleConstr}) and formal.kind notin {tyUntyped, tyBuiltInTypeClass}:
|
||||
changeType(c, x, formal, check=true)
|
||||
result = arg
|
||||
result = skipHiddenSubConv(result, c.graph, c.idgen)
|
||||
@@ -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) =
|
||||
@@ -436,7 +439,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||
# does not mean we expect a tyTypeDesc.
|
||||
retType = retType[0]
|
||||
case retType.kind
|
||||
of tyUntyped, tyAnything:
|
||||
of tyUntyped:
|
||||
# Not expecting a type here allows templates like in ``tmodulealias.in``.
|
||||
result = semExpr(c, result, flags, expectedType)
|
||||
of tyTyped:
|
||||
@@ -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,7 +573,7 @@ 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 nfUseDefaultField
|
||||
@@ -588,11 +592,11 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s
|
||||
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
|
||||
@@ -606,14 +610,14 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] =
|
||||
selectedBranch = recNode.pickCaseBranchIndex defaultValue
|
||||
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 nfUseDefaultField
|
||||
@@ -621,38 +625,45 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] =
|
||||
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)
|
||||
node.intVal = toInt64(lengthOrd(c.graph.config, aTypSkip))
|
||||
result = semExpr(c, newTree(nkCall, newSymNode(getCompilerProc(c.graph, "nimArrayWith"), a.info),
|
||||
semExprWithType(c, child),
|
||||
node
|
||||
))
|
||||
result = semExpr(c, newTree(nkCall, newSymNode(getSysSym(c.graph, a.info, "arrayWith"), a.info),
|
||||
semExprWithType(c, child),
|
||||
node
|
||||
))
|
||||
result.typ = aTyp
|
||||
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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -193,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
|
||||
@@ -209,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}))
|
||||
@@ -222,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
|
||||
@@ -279,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
|
||||
@@ -328,15 +306,13 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||
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 = @[]
|
||||
|
||||
@@ -75,7 +75,6 @@ type
|
||||
# overload resolution.
|
||||
efNoDiagnostics,
|
||||
efTypeAllowed # typeAllowed will be called after
|
||||
efWantNoDefaults
|
||||
|
||||
TExprFlags* = set[TExprFlag]
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -396,8 +394,6 @@ proc semCast(c: PContext, n: PNode): PNode =
|
||||
let castedExpr = semExprWithType(c, n[1])
|
||||
if castedExpr.kind == nkClosedSymChoice:
|
||||
errorUseQualifier(c, n[1].info, castedExpr)
|
||||
if targetType == nil:
|
||||
localError(c.config, n.info, "Invalid usage of cast, cast requires a type to convert to, e.g., cast[int](0d).")
|
||||
if tfHasMeta in targetType.flags:
|
||||
localError(c.config, n[0].info, "cannot cast to a non concrete type: '$1'" % $targetType)
|
||||
if not isCastable(c, targetType, castedExpr.typ, n.info):
|
||||
@@ -695,9 +691,6 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
|
||||
proc fixAbstractType(c: PContext, n: PNode) =
|
||||
for i in 1..<n.len:
|
||||
let it = n[i]
|
||||
if it == nil:
|
||||
localError(c.config, n.info, "'$1' has nil child at index $2" % [renderTree(n, {renderNoComments}), $i])
|
||||
return
|
||||
# do not get rid of nkHiddenSubConv for OpenArrays, the codegen needs it:
|
||||
if it.kind == nkHiddenSubConv and
|
||||
skipTypes(it.typ, abstractVar).kind notin {tyOpenArray, tyVarargs}:
|
||||
@@ -743,7 +736,7 @@ proc hasUnresolvedArgs(c: PContext, n: PNode): bool =
|
||||
if hasUnresolvedArgs(c, n[i]): return true
|
||||
return false
|
||||
|
||||
proc newHiddenAddrTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
|
||||
proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
|
||||
if n.kind == nkHiddenDeref and not (c.config.backend == backendCpp or
|
||||
sfCompileToCpp in c.module.flags):
|
||||
checkSonsLen(n, 1, c.config)
|
||||
@@ -752,17 +745,13 @@ proc newHiddenAddrTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
|
||||
result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ))
|
||||
result.add n
|
||||
let aa = isAssignable(c, n)
|
||||
let sym = getRoot(n)
|
||||
if aa notin {arLValue, arLocalLValue}:
|
||||
if aa == arDiscriminant and c.inUncheckedAssignSection > 0:
|
||||
discard "allow access within a cast(unsafeAssign) section"
|
||||
elif strictDefs in c.features and aa == arAddressableConst and
|
||||
sym != nil and sym.kind == skLet and isOutParam:
|
||||
discard "allow let varaibles to be passed to out parameters"
|
||||
else:
|
||||
localError(c.config, n.info, errVarForOutParamNeededX % renderNotLValue(n))
|
||||
|
||||
proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
|
||||
proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
case n.kind
|
||||
of nkSym:
|
||||
@@ -770,7 +759,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
|
||||
if n.sym.typ != nil and
|
||||
skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
|
||||
incl(n.sym.flags, sfAddrTaken)
|
||||
result = newHiddenAddrTaken(c, n, isOutParam)
|
||||
result = newHiddenAddrTaken(c, n)
|
||||
of nkDotExpr:
|
||||
checkSonsLen(n, 2, c.config)
|
||||
if n[1].kind != nkSym:
|
||||
@@ -778,14 +767,14 @@ proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
|
||||
return
|
||||
if skipTypes(n[1].sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
|
||||
incl(n[1].sym.flags, sfAddrTaken)
|
||||
result = newHiddenAddrTaken(c, n, isOutParam)
|
||||
result = newHiddenAddrTaken(c, n)
|
||||
of nkBracketExpr:
|
||||
checkMinSonsLen(n, 1, c.config)
|
||||
if skipTypes(n[0].typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
|
||||
if n[0].kind == nkSym: incl(n[0].sym.flags, sfAddrTaken)
|
||||
result = newHiddenAddrTaken(c, n, isOutParam)
|
||||
result = newHiddenAddrTaken(c, n)
|
||||
else:
|
||||
result = newHiddenAddrTaken(c, n, isOutParam)
|
||||
result = newHiddenAddrTaken(c, n)
|
||||
|
||||
proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||
checkMinSonsLen(n, 1, c.config)
|
||||
@@ -831,7 +820,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||
if i < t.len and
|
||||
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind in {tyVar}:
|
||||
if n[i].kind != nkHiddenAddr:
|
||||
n[i] = analyseIfAddressTaken(c, n[i], isOutParam(skipTypes(t[i], abstractInst-{tyTypeDesc})))
|
||||
n[i] = analyseIfAddressTaken(c, n[i])
|
||||
|
||||
include semmagic
|
||||
|
||||
@@ -980,14 +969,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)
|
||||
@@ -1285,7 +1266,15 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
result = newSymNode(s, n.info)
|
||||
else:
|
||||
result = newSymNode(s, n.info)
|
||||
of skMacro, skTemplate:
|
||||
of skMacro:
|
||||
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
|
||||
(n.kind notin nkCallKinds and s.requiredParams > 0):
|
||||
markUsed(c, n.info, s)
|
||||
onUse(n.info, s)
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
else:
|
||||
result = semMacroExpr(c, n, n, s, flags)
|
||||
of skTemplate:
|
||||
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
|
||||
(n.kind notin nkCallKinds and s.requiredParams > 0) or
|
||||
sfCustomPragma in sym.flags:
|
||||
@@ -1294,10 +1283,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
onUse(info, s)
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
else:
|
||||
case s.kind
|
||||
of skMacro: result = semMacroExpr(c, n, n, s, flags)
|
||||
of skTemplate: result = semTemplateExpr(c, n, s, flags)
|
||||
else: discard # unreachable
|
||||
result = semTemplateExpr(c, n, s, flags)
|
||||
of skParam:
|
||||
markUsed(c, n.info, s)
|
||||
onUse(n.info, s)
|
||||
@@ -1831,16 +1817,11 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||
# a = b # both are vars, means: a[] = b[]
|
||||
# a = b # b no 'var T' means: a = addr(b)
|
||||
var le = a.typ
|
||||
let assignable = isAssignable(c, a)
|
||||
let root = getRoot(a)
|
||||
let useStrictDefLet = root != nil and root.kind == skLet and
|
||||
assignable == arAddressableConst and
|
||||
strictDefs in c.features and isLocalSym(root)
|
||||
if le == nil:
|
||||
localError(c.config, a.info, "expression has no type")
|
||||
elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind notin {tyVar} and
|
||||
assignable in {arNone, arLentValue, arAddressableConst} and not useStrictDefLet
|
||||
) or (skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs} and views notin c.features):
|
||||
isAssignable(c, a) in {arNone, arLentValue, arAddressableConst}) or (
|
||||
skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs} and views notin c.features):
|
||||
# Direct assignment to a discriminant is allowed!
|
||||
localError(c.config, a.info, errXCannotBeAssignedTo %
|
||||
renderTree(a, {renderNoComments}))
|
||||
@@ -1853,8 +1834,6 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||
var rhsTyp = rhs.typ
|
||||
if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass:
|
||||
rhsTyp = rhsTyp.lastSon
|
||||
if lhs.sym.typ.kind == tyAnything:
|
||||
rhsTyp = rhsTyp.skipIntLit(c.idgen)
|
||||
if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}:
|
||||
internalAssert c.config, c.p.resultSym != nil
|
||||
# Make sure the type is valid for the result variable
|
||||
@@ -1898,9 +1877,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):
|
||||
@@ -1931,8 +1907,8 @@ proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode =
|
||||
else:
|
||||
localError(c.config, c.p.resultSym.info, errCannotInferReturnType %
|
||||
c.p.owner.name.s)
|
||||
if isIterator(c.p.owner.typ) and c.p.owner.typ[0] != nil and
|
||||
c.p.owner.typ[0].kind == tyAnything:
|
||||
if isInlineIterator(c.p.owner.typ) and c.p.owner.typ[0] != nil and
|
||||
c.p.owner.typ[0].kind == tyUntyped:
|
||||
localError(c.config, c.p.owner.info, errCannotInferReturnType %
|
||||
c.p.owner.name.s)
|
||||
closeScope(c)
|
||||
@@ -1958,8 +1934,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.
|
||||
@@ -2906,6 +2880,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 (
|
||||
@@ -2917,19 +2892,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
|
||||
@@ -3257,8 +3219,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()
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
import
|
||||
strutils, options, ast, trees, nimsets,
|
||||
platform, math, msgs, idents, renderer, types,
|
||||
commands, magicsys, modulegraphs, strtabs, lineinfos, wordrecg
|
||||
commands, magicsys, modulegraphs, strtabs, lineinfos
|
||||
|
||||
from system/memory import nimCStrLen
|
||||
|
||||
@@ -371,11 +371,6 @@ proc rangeCheck(n: PNode, value: Int128; g: ModuleGraph) =
|
||||
localError(g.config, n.info, "cannot convert " & $value &
|
||||
" to " & typeToString(n.typ))
|
||||
|
||||
proc floatRangeCheck(n: PNode, value: BiggestFloat; g: ModuleGraph) =
|
||||
if value < firstFloat(n.typ) or value > lastFloat(n.typ):
|
||||
localError(g.config, n.info, "cannot convert " & $value &
|
||||
" to " & typeToString(n.typ))
|
||||
|
||||
proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): PNode =
|
||||
let dstTyp = skipTypes(n.typ, abstractRange - {tyTypeDesc})
|
||||
let srcTyp = skipTypes(a.typ, abstractRange - {tyTypeDesc})
|
||||
@@ -495,83 +490,6 @@ proc newSymNodeTypeDesc*(s: PSym; idgen: IdGenerator; info: TLineInfo): PNode =
|
||||
else:
|
||||
result.typ = s.typ
|
||||
|
||||
proc foldDefine(m, s: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
|
||||
var name = s.name.s
|
||||
let prag = extractPragma(s)
|
||||
if prag != nil:
|
||||
for it in prag:
|
||||
if it.kind in nkPragmaCallKinds and it.len == 2 and it[0].kind == nkIdent:
|
||||
let word = whichKeyword(it[0].ident)
|
||||
if word in {wStrDefine, wIntDefine, wBoolDefine, wDefine}:
|
||||
# should be processed in pragmas.nim already
|
||||
if it[1].kind in {nkStrLit, nkRStrLit, nkTripleStrLit}:
|
||||
name = it[1].strVal
|
||||
if isDefined(g.config, name):
|
||||
let str = g.config.symbols[name]
|
||||
case s.magic
|
||||
of mIntDefine:
|
||||
try:
|
||||
result = newIntNodeT(toInt128(str.parseInt), n, idgen, g)
|
||||
except ValueError:
|
||||
localError(g.config, s.info,
|
||||
"{.intdefine.} const was set to an invalid integer: '" &
|
||||
str & "'")
|
||||
of mStrDefine:
|
||||
result = newStrNodeT(str, n, g)
|
||||
of mBoolDefine:
|
||||
try:
|
||||
result = newIntNodeT(toInt128(str.parseBool.int), n, idgen, g)
|
||||
except ValueError:
|
||||
localError(g.config, s.info,
|
||||
"{.booldefine.} const was set to an invalid bool: '" &
|
||||
str & "'")
|
||||
of mGenericDefine:
|
||||
let rawTyp = s.typ
|
||||
# pretend we don't support distinct types
|
||||
let typ = rawTyp.skipTypes(abstractVarRange-{tyDistinct})
|
||||
try:
|
||||
template intNode(value): PNode =
|
||||
let val = toInt128(value)
|
||||
rangeCheck(n, val, g)
|
||||
newIntNodeT(val, n, idgen, g)
|
||||
case typ.kind
|
||||
of tyString, tyCstring:
|
||||
result = newStrNodeT(str, n, g)
|
||||
of tyInt..tyInt64:
|
||||
result = intNode(str.parseBiggestInt)
|
||||
of tyUInt..tyUInt64:
|
||||
result = intNode(str.parseBiggestUInt)
|
||||
of tyBool:
|
||||
result = intNode(str.parseBool.int)
|
||||
of tyEnum:
|
||||
# compile time parseEnum
|
||||
let ident = getIdent(g.cache, str)
|
||||
for e in typ.n:
|
||||
if e.kind != nkSym: internalError(g.config, "foldDefine for enum")
|
||||
let es = e.sym
|
||||
let match =
|
||||
if es.ast.isNil:
|
||||
es.name.id == ident.id
|
||||
else:
|
||||
es.ast.strVal == str
|
||||
if match:
|
||||
result = intNode(es.position)
|
||||
break
|
||||
if result.isNil:
|
||||
raise newException(ValueError, "invalid enum value: " & str)
|
||||
else:
|
||||
localError(g.config, s.info, "unsupported type $1 for define '$2'" %
|
||||
[name, typeToString(rawTyp)])
|
||||
except ValueError as e:
|
||||
localError(g.config, s.info,
|
||||
"could not process define '$1' of type $2; $3" %
|
||||
[name, typeToString(rawTyp), e.msg])
|
||||
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
|
||||
case n.kind
|
||||
@@ -591,12 +509,33 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
|
||||
of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.hostOS].name), n, g)
|
||||
of mBuildCPU: result = newStrNodeT(platform.CPU[g.config.target.hostCPU].name.toLowerAscii, n, g)
|
||||
of mAppType: result = getAppType(n, g)
|
||||
of mIntDefine, mStrDefine, mBoolDefine, mGenericDefine:
|
||||
result = foldDefine(m, s, n, idgen, g)
|
||||
of mIntDefine:
|
||||
if isDefined(g.config, s.name.s):
|
||||
try:
|
||||
result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseInt), n, idgen, g)
|
||||
except ValueError:
|
||||
localError(g.config, s.info,
|
||||
"{.intdefine.} const was set to an invalid integer: '" &
|
||||
g.config.symbols[s.name.s] & "'")
|
||||
else:
|
||||
result = copyTree(s.astdef)
|
||||
of mStrDefine:
|
||||
if isDefined(g.config, s.name.s):
|
||||
result = newStrNodeT(g.config.symbols[s.name.s], n, g)
|
||||
else:
|
||||
result = copyTree(s.astdef)
|
||||
of mBoolDefine:
|
||||
if isDefined(g.config, s.name.s):
|
||||
try:
|
||||
result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseBool.int), n, idgen, g)
|
||||
except ValueError:
|
||||
localError(g.config, s.info,
|
||||
"{.booldefine.} const was set to an invalid bool: '" &
|
||||
g.config.symbols[s.name.s] & "'")
|
||||
else:
|
||||
result = copyTree(s.astdef)
|
||||
else:
|
||||
result = copyTree(s.astdef)
|
||||
if result != nil:
|
||||
result.info = n.info
|
||||
of skProc, skFunc, skMethod:
|
||||
result = n
|
||||
of skParam:
|
||||
@@ -685,7 +624,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 +648,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 +656,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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -326,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:
|
||||
@@ -367,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) =
|
||||
@@ -377,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)])
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
import
|
||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
||||
wordrecg, strutils, options, guards, lineinfos, semfold, semdata,
|
||||
modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling, tables,
|
||||
semstrictfuncs
|
||||
modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling, tables
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -76,7 +75,7 @@ type
|
||||
guards: TModel # nested guards
|
||||
locked: seq[PNode] # locked locations
|
||||
gcUnsafe, isRecursive, isTopLevel, hasSideEffect, inEnforcedGcSafe: bool
|
||||
isInnerProc: bool
|
||||
hasDangerousAssign, isInnerProc: bool
|
||||
inEnforcedNoSideEffects: bool
|
||||
currOptions: TOptions
|
||||
config: ConfigRef
|
||||
@@ -85,10 +84,6 @@ type
|
||||
escapingParams: IntSet
|
||||
PEffects = var TEffects
|
||||
|
||||
const
|
||||
errXCannotBeAssignedTo = "'$1' cannot be assigned to"
|
||||
errLetNeedsInit = "'let' symbol requires an initialization"
|
||||
|
||||
proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
|
||||
if typ == nil: return
|
||||
when false:
|
||||
@@ -102,8 +97,8 @@ proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
|
||||
optSeqDestructors in tracked.config.globalOptions:
|
||||
tracked.owner.flags.incl sfInjectDestructors
|
||||
|
||||
proc isLocalSym(a: PEffects, s: PSym): bool =
|
||||
s.typ != nil and (s.kind in {skLet, skVar, skResult} or (s.kind == skParam and isOutParam(s.typ))) and
|
||||
proc isLocalVar(a: PEffects, s: PSym): bool =
|
||||
s.typ != nil and (s.kind in {skVar, skResult} or (s.kind == skParam and isOutParam(s.typ))) and
|
||||
sfGlobal notin s.flags and s.owner == a.owner
|
||||
|
||||
proc lockLocations(a: PEffects; pragma: PNode) =
|
||||
@@ -178,15 +173,10 @@ proc initVar(a: PEffects, n: PNode; volatileCheck: bool) =
|
||||
let n = skipHiddenDeref(n)
|
||||
if n.kind != nkSym: return
|
||||
let s = n.sym
|
||||
if isLocalSym(a, s):
|
||||
if isLocalVar(a, s):
|
||||
if volatileCheck: makeVolatile(a, s)
|
||||
for x in a.init:
|
||||
if x == s.id:
|
||||
if strictDefs in a.c.features and s.kind == skLet:
|
||||
localError(a.config, n.info, errXCannotBeAssignedTo %
|
||||
renderTree(n, {renderNoComments}
|
||||
))
|
||||
return
|
||||
if x == s.id: return
|
||||
a.init.add s.id
|
||||
if a.scopes.getOrDefault(s.id) == a.currentBlock:
|
||||
#[ Consider this case:
|
||||
@@ -214,7 +204,7 @@ proc initVarViaNew(a: PEffects, n: PNode) =
|
||||
# 'x' is not nil, but that doesn't mean its "not nil" children
|
||||
# are initialized:
|
||||
initVar(a, n, volatileCheck=true)
|
||||
elif isLocalSym(a, s):
|
||||
elif isLocalVar(a, s):
|
||||
makeVolatile(a, s)
|
||||
|
||||
proc warnAboutGcUnsafe(n: PNode; conf: ConfigRef) =
|
||||
@@ -332,7 +322,7 @@ proc useVar(a: PEffects, n: PNode) =
|
||||
let s = n.sym
|
||||
if a.inExceptOrFinallyStmt > 0:
|
||||
incl s.flags, sfUsedInFinallyOrExcept
|
||||
if isLocalSym(a, s):
|
||||
if isLocalVar(a, s):
|
||||
if sfNoInit in s.flags:
|
||||
# If the variable is explicitly marked as .noinit. do not emit any error
|
||||
a.init.add s.id
|
||||
@@ -341,10 +331,7 @@ proc useVar(a: PEffects, n: PNode) =
|
||||
message(a.config, n.info, warnProveInit, s.name.s)
|
||||
elif a.leftPartOfAsgn <= 0:
|
||||
if strictDefs in a.c.features:
|
||||
if s.kind == skLet:
|
||||
localError(a.config, n.info, errLetNeedsInit)
|
||||
else:
|
||||
message(a.config, n.info, warnUninit, s.name.s)
|
||||
message(a.config, n.info, warnUninit, s.name.s)
|
||||
# prevent superfluous warnings about the same variable:
|
||||
a.init.add s.id
|
||||
useVarNoInitCheck(a, n, s)
|
||||
@@ -491,10 +478,6 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
|
||||
let b = n[i]
|
||||
if b.kind == nkExceptBranch:
|
||||
setLen(tracked.init, oldState)
|
||||
for j in 0..<b.len - 1:
|
||||
if b[j].isInfixAs(): # skips initialization checks
|
||||
assert(b[j][2].kind == nkSym)
|
||||
tracked.init.add b[j][2].sym.id
|
||||
track(tracked, b[^1])
|
||||
for i in oldState..<tracked.init.len:
|
||||
addToIntersection(inter, tracked.init[i])
|
||||
@@ -654,7 +637,7 @@ proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, formals: PType; ar
|
||||
let paramType = if formals != nil and argIndex < formals.len: formals[argIndex] else: nil
|
||||
if paramType != nil and paramType.kind in {tyVar}:
|
||||
invalidateFacts(tracked.guards, n)
|
||||
if n.kind == nkSym and isLocalSym(tracked, n.sym):
|
||||
if n.kind == nkSym and isLocalVar(tracked, n.sym):
|
||||
makeVolatile(tracked, n.sym)
|
||||
if paramType != nil and paramType.kind == tyProc and tfGcSafe in paramType.flags:
|
||||
let argtype = skipTypes(a.typ, abstractInst)
|
||||
@@ -819,12 +802,9 @@ proc passedToEffectsDelayedParam(tracked: PEffects; n: PNode) =
|
||||
]#
|
||||
|
||||
proc checkForSink(tracked: PEffects; n: PNode) =
|
||||
if tracked.inIfStmt == 0 and optSinkInference in tracked.config.options:
|
||||
if tracked.inIfStmt == 0:
|
||||
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):
|
||||
@@ -929,15 +909,12 @@ proc trackCall(tracked: PEffects; n: PNode) =
|
||||
createTypeBoundOps(tracked, paramType[0], n.info)
|
||||
checkForSink(tracked, n[i])
|
||||
of tyVar:
|
||||
tracked.hasDangerousAssign = true
|
||||
if isOutParam(paramType):
|
||||
# consider this case: p(out x, x); we want to remark that 'x' is not
|
||||
# initialized until after the call. Since we do this after we analysed the
|
||||
# call, this is fine.
|
||||
initVar(tracked, n[i].skipAddr, false)
|
||||
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
|
||||
|
||||
type
|
||||
@@ -1048,7 +1025,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
# bug #15038: ensure consistency
|
||||
if not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ): n.typ = n.sym.typ
|
||||
of nkHiddenAddr, nkAddr:
|
||||
if n[0].kind == nkSym and isLocalSym(tracked, n[0].sym):
|
||||
if n[0].kind == nkSym and isLocalVar(tracked, n[0].sym):
|
||||
useVarNoInitCheck(tracked, n[0], n[0].sym)
|
||||
else:
|
||||
track(tracked, n[0])
|
||||
@@ -1088,12 +1065,10 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
when false: cstringCheck(tracked, n)
|
||||
if tracked.owner.kind != skMacro and n[0].typ.kind notin {tyOpenArray, tyVarargs}:
|
||||
createTypeBoundOps(tracked, n[0].typ, n.info)
|
||||
if n[0].kind != nkSym or not isLocalSym(tracked, n[0].sym):
|
||||
if n[0].kind != nkSym or not isLocalVar(tracked, n[0].sym):
|
||||
checkForSink(tracked, n[1])
|
||||
if tracked.strictFuncsActive and isDangerousLocation(n[0], tracked.owner):
|
||||
tracked.hasSideEffect = true
|
||||
localError(tracked.config, n[0].info,
|
||||
"cannot mutate location $1 within a strict func" % renderTree(n[0]))
|
||||
if not tracked.hasDangerousAssign and n[0].kind != nkSym:
|
||||
tracked.hasDangerousAssign = true
|
||||
of nkVarSection, nkLetSection:
|
||||
for child in n:
|
||||
let last = lastSon(child)
|
||||
@@ -1450,9 +1425,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?
|
||||
@@ -1491,10 +1463,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):
|
||||
@@ -1532,9 +1501,17 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
|
||||
effects[ensuresEffects] = ensuresSpec
|
||||
|
||||
var mutationInfo = MutationInfo()
|
||||
if views in c.features:
|
||||
var partitions = computeGraphPartitions(s, body, g, {borrowChecking})
|
||||
checkBorrowedLocations(partitions, body, g.config)
|
||||
var hasMutationSideEffect = false
|
||||
if {strictFuncs, views} * c.features != {}:
|
||||
var goals: set[Goal] = {}
|
||||
if strictFuncs in c.features: goals.incl constParameters
|
||||
if views in c.features: goals.incl borrowChecking
|
||||
var partitions = computeGraphPartitions(s, body, g, goals)
|
||||
if not t.hasSideEffect and t.hasDangerousAssign:
|
||||
t.hasSideEffect = varpartitions.hasSideEffect(partitions, mutationInfo)
|
||||
hasMutationSideEffect = t.hasSideEffect
|
||||
if views in c.features:
|
||||
checkBorrowedLocations(partitions, body, g.config)
|
||||
|
||||
if sfThread in s.flags and t.gcUnsafe:
|
||||
if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions:
|
||||
@@ -1547,7 +1524,9 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
|
||||
when false:
|
||||
listGcUnsafety(s, onlyWarning=false, g.config)
|
||||
else:
|
||||
if c.compilesContextId == 0: # don't render extended diagnostic messages in `system.compiles` context
|
||||
if hasMutationSideEffect:
|
||||
localError(g.config, s.info, "'$1' can have side effects$2" % [s.name.s, g.config $ mutationInfo])
|
||||
elif c.compilesContextId == 0: # don't render extended diagnostic messages in `system.compiles` context
|
||||
var msg = ""
|
||||
listSideEffects(msg, s, g.config, t.c)
|
||||
message(g.config, s.info, errGenerated, msg)
|
||||
|
||||
@@ -105,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
|
||||
|
||||
@@ -209,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)
|
||||
@@ -252,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:
|
||||
@@ -511,6 +509,13 @@ proc semVarMacroPragma(c: PContext, a: PNode, n: PNode): PNode =
|
||||
let it = pragmas[i]
|
||||
let key = if it.kind in nkPragmaCallKinds and it.len >= 1: it[0] else: it
|
||||
|
||||
when false:
|
||||
let lhs = b[0]
|
||||
let clash = strTableGet(c.currentScope.symbols, lhs.ident)
|
||||
if clash != nil:
|
||||
# refs https://github.com/nim-lang/Nim/issues/8275
|
||||
wrongRedefinition(c, lhs.info, lhs.ident.s, clash.info)
|
||||
|
||||
if isPossibleMacroPragma(c, it, key):
|
||||
# we transform ``var p {.m, rest.}`` into ``m(do: var p {.rest.})`` and
|
||||
# let the semantic checker deal with it:
|
||||
@@ -557,18 +562,38 @@ proc semVarMacroPragma(c: PContext, a: PNode, n: PNode): PNode =
|
||||
|
||||
doAssert result != nil
|
||||
|
||||
# since a macro pragma can set pragmas, we process these here again.
|
||||
# This is required for SqueakNim-like export pragmas.
|
||||
if false and result.kind in {nkVarSection, nkLetSection, nkConstSection}:
|
||||
var validPragmas: TSpecialWords
|
||||
case result.kind
|
||||
of nkVarSection:
|
||||
validPragmas = varPragmas
|
||||
of nkLetSection:
|
||||
validPragmas = letPragmas
|
||||
of nkConstSection:
|
||||
validPragmas = constPragmas
|
||||
else:
|
||||
# unreachable
|
||||
discard
|
||||
for defs in result:
|
||||
for i in 0 ..< defs.len - 2:
|
||||
let ex = defs[i]
|
||||
if ex.kind == nkPragmaExpr and
|
||||
ex[namePos].kind == nkSym and
|
||||
ex[pragmaPos].kind != nkEmpty:
|
||||
pragma(c, defs[lhsPos][namePos].sym, defs[lhsPos][pragmaPos], validPragmas)
|
||||
return result
|
||||
|
||||
template isLocalSym(sym: PSym): bool =
|
||||
sym.kind in {skVar, skLet} and not
|
||||
({sfGlobal, sfPure} * sym.flags != {} or
|
||||
sfCompileTime in sym.flags) or
|
||||
sym.kind in {skProc, skFunc, skIterator} and
|
||||
sfGlobal notin sym.flags
|
||||
|
||||
template isLocalVarSym(n: PNode): bool =
|
||||
n.kind == nkSym and isLocalSym(n.sym)
|
||||
|
||||
n.kind == nkSym and
|
||||
(n.sym.kind in {skVar, skLet} and not
|
||||
({sfGlobal, sfPure} <= n.sym.flags or
|
||||
sfCompileTime in n.sym.flags) or
|
||||
n.sym.kind in {skProc, skFunc, skIterator} and
|
||||
sfGlobal notin n.sym.flags
|
||||
)
|
||||
|
||||
proc usesLocalVar(n: PNode): bool =
|
||||
for z in 1 ..< n.len:
|
||||
if n[z].isLocalVarSym:
|
||||
@@ -721,15 +746,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
else:
|
||||
checkNilable(c, v)
|
||||
# allow let to not be initialised if imported from C:
|
||||
if v.kind == skLet and sfImportc notin v.flags and (strictDefs notin c.features or not isLocalSym(v)):
|
||||
if v.kind == skLet and sfImportc notin v.flags:
|
||||
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:
|
||||
@@ -1367,7 +1389,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||
rawAddSon(s.typ, newTypeS(tyNone, c))
|
||||
s.ast = a
|
||||
inc c.inGenericContext
|
||||
var body = semTypeNode(c, a[2], s.typ)
|
||||
var body = semTypeNode(c, a[2], nil)
|
||||
dec c.inGenericContext
|
||||
if body != nil:
|
||||
body.sym = s
|
||||
@@ -1688,6 +1710,12 @@ proc semProcAnnotation(c: PContext, prc: PNode;
|
||||
|
||||
doAssert result != nil
|
||||
|
||||
# since a proc annotation can set pragmas, we process these here again.
|
||||
# This is required for SqueakNim-like export pragmas.
|
||||
if false and result.kind in procDefs and result[namePos].kind == nkSym and
|
||||
result[pragmasPos].kind != nkEmpty:
|
||||
pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
|
||||
|
||||
return result
|
||||
|
||||
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode {.nosinks.} =
|
||||
@@ -1853,8 +1881,6 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
if s.magic == mAsgn: return
|
||||
incl(s.flags, sfUsed)
|
||||
incl(s.flags, sfOverriden)
|
||||
if name == "=":
|
||||
message(c.config, n.info, warnDeprecated, "Overriding `=` hook is deprecated; Override `=copy` hook instead")
|
||||
let t = s.typ
|
||||
if t.len == 3 and t[0] == nil and t[1].kind == tyVar:
|
||||
var obj = t[1][0]
|
||||
@@ -2156,7 +2182,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):
|
||||
@@ -2184,7 +2210,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
if hasProto: localError(c.config, n.info, errImplOfXexpected % proto.name.s)
|
||||
if {sfImportc, sfBorrow, sfError} * s.flags == {} and s.magic == mNone:
|
||||
# this is a forward declaration and we're building the prototype
|
||||
if s.kind in {skProc, skFunc} and s.typ[0] != nil and s.typ[0].kind == tyAnything:
|
||||
if s.kind in {skProc, skFunc} and s.typ[0] != nil and s.typ[0].kind == tyUntyped:
|
||||
# `auto` is represented as `tyUntyped` at this point in compilation.
|
||||
localError(c.config, n[paramsPos][0].info, "return type 'auto' cannot be used in forward declarations")
|
||||
|
||||
incl(s.flags, sfForward)
|
||||
@@ -2451,12 +2478,9 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType =
|
||||
else:
|
||||
n.typ = n[i].typ
|
||||
if not isEmptyType(n.typ): n.transitionSonsKind(nkStmtListExpr)
|
||||
var m = n[i]
|
||||
while m.kind in {nkStmtListExpr, nkStmtList} and m.len > 0: # from templates
|
||||
m = m.lastSon
|
||||
if m.kind in nkLastBlockStmts or
|
||||
m.kind in nkCallKinds and m[0].kind == nkSym and
|
||||
sfNoReturn in m[0].sym.flags:
|
||||
if n[i].kind in nkLastBlockStmts or
|
||||
n[i].kind in nkCallKinds and n[i][0].kind == nkSym and
|
||||
sfNoReturn in n[i][0].sym.flags:
|
||||
for j in i + 1..<n.len:
|
||||
case n[j].kind
|
||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkState: discard
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2022 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## New "strict funcs" checking. Much simpler and hopefully easier to teach than
|
||||
## the old but more advanced algorithm that can/could be found in `varpartitions.nim`.
|
||||
|
||||
import ast, typeallowed, renderer
|
||||
from aliasanalysis import PathKinds0, PathKinds1
|
||||
from trees import getMagic
|
||||
|
||||
proc isDangerousLocation*(n: PNode; owner: PSym): bool =
|
||||
var n = n
|
||||
var hasDeref = false
|
||||
while true:
|
||||
case n.kind
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
if n[0].typ.kind != tyVar:
|
||||
hasDeref = true
|
||||
n = n[0]
|
||||
of PathKinds0 - {nkDerefExpr, nkHiddenDeref}:
|
||||
n = n[0]
|
||||
of PathKinds1:
|
||||
n = n[1]
|
||||
of nkCallKinds:
|
||||
if n.len > 1:
|
||||
if (n.typ != nil and classifyViewType(n.typ) != noView) or getMagic(n) == mSlice:
|
||||
# borrow from first parameter:
|
||||
n = n[1]
|
||||
else:
|
||||
break
|
||||
else:
|
||||
break
|
||||
else:
|
||||
break
|
||||
if n.kind == nkSym:
|
||||
# dangerous if contains a pointer deref or if it doesn't belong to us:
|
||||
result = hasDeref or n.sym.owner != owner
|
||||
when false:
|
||||
# store to something that belongs to a `var` parameter is fine:
|
||||
let s = n.sym
|
||||
if s.kind == skParam:
|
||||
# dangerous unless a `var T` parameter:
|
||||
result = s.typ.kind != tyVar
|
||||
else:
|
||||
# dangerous if contains a pointer deref or if it doesn't belong to us:
|
||||
result = hasDeref or s.owner != owner
|
||||
else:
|
||||
# dangerous if it contains a pointer deref
|
||||
result = hasDeref
|
||||
@@ -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)
|
||||
@@ -692,7 +691,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
elif not comesFromShadowscope:
|
||||
if {sfTemplateRedefinition, sfGenSym} * s.flags == {}:
|
||||
#wrongRedefinition(c, n.info, proto.name.s, proto.info)
|
||||
message(c.config, n.info, warnImplicitTemplateRedefinition, s.name.s)
|
||||
message(c.config, n.info, warnTemplateRedefinition, s.name.s)
|
||||
symTabReplace(c.currentScope.symbols, proto, s)
|
||||
if n[patternPos].kind != nkEmpty:
|
||||
c.patterns.add(s)
|
||||
|
||||
@@ -38,7 +38,7 @@ const
|
||||
errInOutFlagNotExtern = "the '$1' modifier can be used only with imported types"
|
||||
|
||||
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
|
||||
if prev == nil or prev.kind == tyGenericBody:
|
||||
if prev == nil:
|
||||
result = newTypeS(kind, c)
|
||||
else:
|
||||
result = prev
|
||||
@@ -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:
|
||||
@@ -328,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:
|
||||
@@ -779,10 +777,9 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
if n == nil: return
|
||||
case n.kind
|
||||
of nkRecWhen:
|
||||
var a = copyTree(n)
|
||||
var branch: PNode = nil # the branch to take
|
||||
for i in 0..<a.len:
|
||||
var it = a[i]
|
||||
for i in 0..<n.len:
|
||||
var it = n[i]
|
||||
if it == nil: illFormedAst(n, c.config)
|
||||
var idx = 1
|
||||
case it.kind
|
||||
@@ -808,7 +805,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
semRecordNodeAux(c, it[idx], newCheck, newPos, newf, rectype, hasCaseFields)
|
||||
it[idx] = if newf.len == 1: newf[0] else: newf
|
||||
if c.inGenericContext > 0:
|
||||
father.add a
|
||||
father.add n
|
||||
elif branch != nil:
|
||||
semRecordNodeAux(c, branch, check, pos, father, rectype, hasCaseFields)
|
||||
elif father.kind in {nkElse, nkOfBranch}:
|
||||
@@ -980,7 +977,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||
let n = if n[0].kind == nkBracket: n[0] else: n
|
||||
checkMinSonsLen(n, 1, c.config)
|
||||
let body = n.lastSon
|
||||
var t = if prev != nil and prev.kind != tyGenericBody and body.kind == nkObjectTy:
|
||||
var t = if prev != nil and body.kind == nkObjectTy:
|
||||
semObjectNode(c, body, nil, prev.flags)
|
||||
else:
|
||||
semTypeNode(c, body, nil)
|
||||
@@ -1310,15 +1307,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
|
||||
|
||||
@@ -1374,9 +1369,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)
|
||||
@@ -1411,7 +1404,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
"' is only valid for macros and templates")
|
||||
# 'auto' as a return type does not imply a generic:
|
||||
elif r.kind == tyAnything:
|
||||
discard
|
||||
# 'p(): auto' and 'p(): untyped' are equivalent, but the rest of the
|
||||
# compiler is hardly aware of 'auto':
|
||||
r = newTypeS(tyUntyped, c)
|
||||
elif r.kind == tyStatic:
|
||||
# type allowed should forbid this type
|
||||
discard
|
||||
@@ -1580,23 +1575,21 @@ proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType =
|
||||
result = newTypeS(tyAlias, c)
|
||||
result.rawAddSon typeExpr
|
||||
result.sym = prev.sym
|
||||
if prev.kind != tyGenericBody:
|
||||
assignType(prev, result)
|
||||
assignType(prev, result)
|
||||
|
||||
proc fixupTypeOf(c: PContext, prev: PType, typExpr: PNode) =
|
||||
if prev != nil:
|
||||
let result = newTypeS(tyAlias, c)
|
||||
result.rawAddSon typExpr.typ
|
||||
result.sym = prev.sym
|
||||
if prev.kind != tyGenericBody:
|
||||
assignType(prev, result)
|
||||
assignType(prev, result)
|
||||
|
||||
proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType =
|
||||
var n = semExprWithType(c, n, {efDetermineType})
|
||||
if n.typ.kind == tyTypeDesc:
|
||||
result = n.typ.base
|
||||
# fix types constructed by macros/template:
|
||||
if prev != nil and prev.kind != tyGenericBody and prev.sym != nil:
|
||||
if prev != nil and prev.sym != nil:
|
||||
if result.sym.isNil:
|
||||
# Behold! you're witnessing enormous power yielded
|
||||
# by macros. Only macros can summon unnamed types
|
||||
@@ -1617,7 +1610,7 @@ proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType =
|
||||
result = errorType(c)
|
||||
|
||||
proc freshType(c: PContext; res, prev: PType): PType {.inline.} =
|
||||
if prev.isNil or prev.kind == tyGenericBody:
|
||||
if prev.isNil:
|
||||
result = copyType(res, nextTypeId c.idgen, res.owner)
|
||||
copyTypeProps(c.graph, c.idgen.module, result, res)
|
||||
else:
|
||||
@@ -1995,8 +1988,6 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
let alias = maybeAliasType(c, s.typ, prev)
|
||||
if alias != nil:
|
||||
result = alias
|
||||
elif prev.kind == tyGenericBody:
|
||||
result = s.typ
|
||||
else:
|
||||
assignType(prev, s.typ)
|
||||
# bugfix: keep the fresh id for aliases to integral types:
|
||||
@@ -2016,7 +2007,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
let alias = maybeAliasType(c, t, prev)
|
||||
if alias != nil:
|
||||
result = alias
|
||||
elif prev == nil or prev.kind == tyGenericBody:
|
||||
elif prev == nil:
|
||||
result = t
|
||||
else:
|
||||
assignType(prev, t)
|
||||
|
||||
@@ -499,20 +499,10 @@ proc propagateFieldFlags(t: PType, n: PNode) =
|
||||
|
||||
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
template bailout =
|
||||
if (t.sym == nil) or (t.sym != nil and sfGeneratedType in t.sym.flags):
|
||||
# In the first case 't.sym' can be 'nil' if the type is a ref/ptr, see
|
||||
# issue https://github.com/nim-lang/Nim/issues/20416 for more details.
|
||||
# Fortunately for us this works for now because partial ref/ptr types are
|
||||
# not allowed in object construction, eg.
|
||||
# type
|
||||
# Container[T] = ...
|
||||
# O = object
|
||||
# val: ref Container
|
||||
#
|
||||
# In the second case only consider the recursion limit if the symbol is a
|
||||
# type with generic parameters that have not been explicitly supplied,
|
||||
# typechecking should terminate when generic parameters are explicitly
|
||||
# supplied.
|
||||
if t.sym != nil and sfGeneratedType in t.sym.flags:
|
||||
# Only consider the recursion limit if the symbol is a type with generic
|
||||
# parameters that have not been explicitly supplied, typechecking should
|
||||
# terminate when generic parameters are explicitly supplied.
|
||||
if cl.recursionLimit > 100:
|
||||
# bail out, see bug #2509. But note this caching is in general wrong,
|
||||
# look at this example where TwoVectors should not share the generic
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## Computes hash values for routine (proc, method etc) signatures.
|
||||
|
||||
import ast, tables, ropes, md5, modulegraphs
|
||||
import ast, tables, ropes, md5_old, modulegraphs
|
||||
from hashes import Hash
|
||||
import types
|
||||
|
||||
|
||||
@@ -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 =
|
||||
@@ -379,16 +373,14 @@ proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType =
|
||||
else:
|
||||
result = t # Note: empty is valid here
|
||||
|
||||
proc handleRange(c: PContext, f, a: PType, min, max: TTypeKind): TTypeRelation =
|
||||
proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
|
||||
if a.kind == f.kind:
|
||||
result = isEqual
|
||||
else:
|
||||
let ab = skipTypes(a, {tyRange})
|
||||
let k = ab.kind
|
||||
let nf = c.config.normalizeKind(f.kind)
|
||||
let na = c.config.normalizeKind(k)
|
||||
if k == f.kind: result = isSubrange
|
||||
elif k == tyInt and f.kind in {tyRange, tyInt..tyInt64,
|
||||
elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64,
|
||||
tyUInt..tyUInt64} and
|
||||
isIntLit(ab) and getInt(ab.n) >= firstOrd(nil, f) and
|
||||
getInt(ab.n) <= lastOrd(nil, f):
|
||||
@@ -397,13 +389,9 @@ proc handleRange(c: PContext, f, a: PType, min, max: TTypeKind): TTypeRelation =
|
||||
# integer literal in the proper range; we want ``i16 + 4`` to stay an
|
||||
# ``int16`` operation so we declare the ``4`` pseudo-equal to int16
|
||||
result = isFromIntLit
|
||||
elif a.kind == tyInt and nf == c.config.targetSizeSignedToKind:
|
||||
elif f.kind == tyInt and k in {tyInt8..tyInt32}:
|
||||
result = isIntConv
|
||||
elif a.kind == tyUInt and nf == c.config.targetSizeUnsignedToKind:
|
||||
result = isIntConv
|
||||
elif f.kind == tyInt and na in {tyInt8 .. pred(c.config.targetSizeSignedToKind)}:
|
||||
result = isIntConv
|
||||
elif f.kind == tyUInt and na in {tyUInt8 .. pred(c.config.targetSizeUnsignedToKind)}:
|
||||
elif f.kind == tyUInt and k in {tyUInt8..tyUInt32}:
|
||||
result = isIntConv
|
||||
elif k >= min and k <= max:
|
||||
result = isConvertible
|
||||
@@ -417,7 +405,7 @@ proc handleRange(c: PContext, f, a: PType, min, max: TTypeKind): TTypeRelation =
|
||||
result = isConvertible
|
||||
else: result = isNone
|
||||
|
||||
proc isConvertibleToRange(c: PContext, f, a: PType): bool =
|
||||
proc isConvertibleToRange(f, a: PType): bool =
|
||||
if f.kind in {tyInt..tyInt64, tyUInt..tyUInt64} and
|
||||
a.kind in {tyInt..tyInt64, tyUInt..tyUInt64}:
|
||||
case f.kind
|
||||
@@ -425,14 +413,13 @@ proc isConvertibleToRange(c: PContext, f, a: PType): bool =
|
||||
of tyInt16: result = isIntLit(a) or a.kind in {tyInt8, tyInt16}
|
||||
of tyInt32: result = isIntLit(a) or a.kind in {tyInt8, tyInt16, tyInt32}
|
||||
# This is wrong, but seems like there's a lot of code that relies on it :(
|
||||
of tyInt, tyUInt: result = true
|
||||
# of tyInt: result = isIntLit(a) or a.kind in {tyInt8 .. c.config.targetSizeSignedToKind}
|
||||
of tyInt, tyUInt, tyUInt64: result = true
|
||||
of tyInt64: result = isIntLit(a) or a.kind in {tyInt8, tyInt16, tyInt32, tyInt, tyInt64}
|
||||
of tyUInt8: result = isIntLit(a) or a.kind in {tyUInt8}
|
||||
of tyUInt16: result = isIntLit(a) or a.kind in {tyUInt8, tyUInt16}
|
||||
of tyUInt32: result = isIntLit(a) or a.kind in {tyUInt8, tyUInt16, tyUInt32}
|
||||
# of tyUInt: result = isIntLit(a) or a.kind in {tyUInt8 .. c.config.targetSizeUnsignedToKind}
|
||||
of tyUInt64: result = isIntLit(a) or a.kind in {tyUInt8, tyUInt16, tyUInt32, tyUInt64}
|
||||
#of tyUInt: result = isIntLit(a) or a.kind in {tyUInt8, tyUInt16, tyUInt32, tyUInt}
|
||||
#of tyUInt64: result = isIntLit(a) or a.kind in {tyUInt8, tyUInt16, tyUInt32, tyUInt, tyUInt64}
|
||||
else: result = false
|
||||
elif f.kind in {tyFloat..tyFloat128}:
|
||||
# `isIntLit` is correct and should be used above as well, see PR:
|
||||
@@ -1161,18 +1148,18 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||
let f = skipTypes(f, {tyRange})
|
||||
if f.kind == a.kind and (f.kind != tyEnum or sameEnumTypes(f, a)):
|
||||
result = isIntConv
|
||||
elif isConvertibleToRange(c.c, f, a):
|
||||
elif isConvertibleToRange(f, a):
|
||||
result = isConvertible # a convertible to f
|
||||
of tyInt: result = handleRange(c.c, f, a, tyInt8, c.c.config.targetSizeSignedToKind)
|
||||
of tyInt8: result = handleRange(c.c, f, a, tyInt8, tyInt8)
|
||||
of tyInt16: result = handleRange(c.c, f, a, tyInt8, tyInt16)
|
||||
of tyInt32: result = handleRange(c.c, f, a, tyInt8, tyInt32)
|
||||
of tyInt64: result = handleRange(c.c, f, a, tyInt, tyInt64)
|
||||
of tyUInt: result = handleRange(c.c, f, a, tyUInt8, c.c.config.targetSizeUnsignedToKind)
|
||||
of tyUInt8: result = handleRange(c.c, f, a, tyUInt8, tyUInt8)
|
||||
of tyUInt16: result = handleRange(c.c, f, a, tyUInt8, tyUInt16)
|
||||
of tyUInt32: result = handleRange(c.c, f, a, tyUInt8, tyUInt32)
|
||||
of tyUInt64: result = handleRange(c.c, f, a, tyUInt, tyUInt64)
|
||||
of tyInt: result = handleRange(f, a, tyInt8, tyInt32)
|
||||
of tyInt8: result = handleRange(f, a, tyInt8, tyInt8)
|
||||
of tyInt16: result = handleRange(f, a, tyInt8, tyInt16)
|
||||
of tyInt32: result = handleRange(f, a, tyInt8, tyInt32)
|
||||
of tyInt64: result = handleRange(f, a, tyInt, tyInt64)
|
||||
of tyUInt: result = handleRange(f, a, tyUInt8, tyUInt32)
|
||||
of tyUInt8: result = handleRange(f, a, tyUInt8, tyUInt8)
|
||||
of tyUInt16: result = handleRange(f, a, tyUInt8, tyUInt16)
|
||||
of tyUInt32: result = handleRange(f, a, tyUInt8, tyUInt32)
|
||||
of tyUInt64: result = handleRange(f, a, tyUInt, tyUInt64)
|
||||
of tyFloat: result = handleFloatRange(f, a)
|
||||
of tyFloat32: result = handleFloatRange(f, a)
|
||||
of tyFloat64: result = handleFloatRange(f, a)
|
||||
@@ -1840,9 +1827,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 +1835,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
|
||||
|
||||
@@ -1929,16 +1912,13 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
|
||||
result.add c.graph.emptyNode
|
||||
result.add arg
|
||||
|
||||
proc isLValue(c: PContext; n: PNode, isOutParam = false): bool {.inline.} =
|
||||
proc isLValue(c: PContext; n: PNode): bool {.inline.} =
|
||||
let aa = isAssignable(nil, n)
|
||||
case aa
|
||||
of arLValue, arLocalLValue, arStrange:
|
||||
result = true
|
||||
of arDiscriminant:
|
||||
result = c.inUncheckedAssignSection > 0
|
||||
of arAddressableConst:
|
||||
let sym = getRoot(n)
|
||||
result = strictDefs in c.features and sym != nil and sym.kind == skLet and isOutParam
|
||||
else:
|
||||
result = false
|
||||
|
||||
@@ -2065,7 +2045,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
|
||||
@@ -2129,15 +2109,11 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||
|
||||
case r
|
||||
of isConvertible:
|
||||
if f.skipTypes({tyRange}).kind in {tyInt, tyUInt}:
|
||||
inc(m.convMatches)
|
||||
inc(m.convMatches)
|
||||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||
of isIntConv:
|
||||
# I'm too lazy to introduce another ``*matches`` field, so we conflate
|
||||
# ``isIntConv`` and ``isIntLit`` here:
|
||||
if f.skipTypes({tyRange}).kind notin {tyInt, tyUInt}:
|
||||
inc(m.intConvMatches)
|
||||
inc(m.intConvMatches)
|
||||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||
of isSubtype:
|
||||
@@ -2160,8 +2136,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:
|
||||
@@ -2204,8 +2178,6 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||
return arg
|
||||
elif a.kind == tyVoid and f.matchesVoidProc and argOrig.kind == nkStmtList:
|
||||
# lift do blocks without params to lambdas
|
||||
# now deprecated
|
||||
message(c.config, argOrig.info, warnStmtListLambda)
|
||||
let p = c.graph
|
||||
let lifted = c.semExpr(c, newProcNode(nkDo, argOrig.info, body = argOrig,
|
||||
params = nkFormalParams.newTree(p.emptyNode), name = p.emptyNode, pattern = p.emptyNode,
|
||||
@@ -2411,7 +2383,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
|
||||
if argConverter.typ.kind notin {tyVar}:
|
||||
m.firstMismatch.kind = kVarNeeded
|
||||
noMatch()
|
||||
elif not (isLValue(c, n, isOutParam(formal.typ))):
|
||||
elif not isLValue(c, n):
|
||||
m.firstMismatch.kind = kVarNeeded
|
||||
noMatch()
|
||||
|
||||
@@ -2671,6 +2643,8 @@ 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 {.nosinks.} =
|
||||
|
||||
@@ -19,6 +19,7 @@ proc checkForSink*(config: ConfigRef; idgen: IdGenerator; owner: PSym; arg: PNod
|
||||
var local = p # sink parameter?
|
||||
passToSink(local)
|
||||
]#
|
||||
if optSinkInference notin config.options: return
|
||||
case arg.kind
|
||||
of nkSym:
|
||||
if arg.sym.kind == skParam and
|
||||
|
||||
@@ -1,207 +1,383 @@
|
||||
import std/[strutils, strscans, parseutils, assertions]
|
||||
import os, strformat, strutils, tables, sets, ropes, json, algorithm
|
||||
|
||||
type
|
||||
Segment = object
|
||||
## Segment refers to a block of something in the JS output.
|
||||
## This could be a token or an entire line
|
||||
original: int # Column in the Nim source
|
||||
generated: int # Column in the generated JS
|
||||
name: int # Index into names list (-1 for no name)
|
||||
SourceNode* = ref object
|
||||
line*: int
|
||||
column*: int
|
||||
source*: string
|
||||
name*: string
|
||||
children*: seq[Child]
|
||||
|
||||
Mapping = object
|
||||
## Mapping refers to a line in the JS output.
|
||||
## It is made up of segments which refer to the tokens in the line
|
||||
case inSource: bool # Whether the line in JS has Nim equivilant
|
||||
of true:
|
||||
file: int # Index into files list
|
||||
line: int # 0 indexed line of code in the Nim source
|
||||
segments: seq[Segment]
|
||||
else: discard
|
||||
C = enum cSourceNode, cSourceString
|
||||
|
||||
SourceInfo = object
|
||||
mappings: seq[Mapping]
|
||||
names, files: seq[string]
|
||||
Child* = ref object
|
||||
case kind*: C:
|
||||
of cSourceNode:
|
||||
node*: SourceNode
|
||||
of cSourceString:
|
||||
s*: string
|
||||
|
||||
SourceMap* = object
|
||||
SourceMap* = ref object
|
||||
version*: int
|
||||
sources*: seq[string]
|
||||
names*: seq[string]
|
||||
mappings*: string
|
||||
file*: string
|
||||
# sourceRoot*: string
|
||||
# sourcesContent*: string
|
||||
|
||||
func addSegment(info: var SourceInfo, original, generated: int, name: string = "") {.raises: [].} =
|
||||
## Adds a new segment into the current line
|
||||
assert info.mappings.len > 0, "No lines have been added yet"
|
||||
var segment = Segment(original: original, generated: generated, name: -1)
|
||||
if name != "":
|
||||
# Make name be index into names list
|
||||
segment.name = info.names.find(name)
|
||||
if segment.name == -1:
|
||||
segment.name = info.names.len
|
||||
info.names &= name
|
||||
SourceMapGenerator = ref object
|
||||
file: string
|
||||
sourceRoot: string
|
||||
skipValidation: bool
|
||||
sources: seq[string]
|
||||
names: seq[string]
|
||||
mappings: seq[Mapping]
|
||||
|
||||
assert info.mappings[^1].inSource, "Current line isn't in Nim source"
|
||||
info.mappings[^1].segments &= segment
|
||||
Mapping* = ref object
|
||||
source*: string
|
||||
original*: tuple[line: int, column: int]
|
||||
generated*: tuple[line: int, column: int]
|
||||
name*: string
|
||||
noSource*: bool
|
||||
noName*: bool
|
||||
|
||||
func newLine(info: var SourceInfo) {.raises: [].} =
|
||||
## Add new mapping which doesn't appear in the Nim source
|
||||
info.mappings &= Mapping(inSource: false)
|
||||
|
||||
func newLine(info: var SourceInfo, file: string, line: int) {.raises: [].} =
|
||||
## Starts a new line in the mappings. Call addSegment after this to add
|
||||
## segments into the line
|
||||
var mapping = Mapping(inSource: true, line: line)
|
||||
# Set file to file position. Add in if needed
|
||||
mapping.file = info.files.find(file)
|
||||
if mapping.file == -1:
|
||||
mapping.file = info.files.len
|
||||
info.files &= file
|
||||
info.mappings &= mapping
|
||||
proc child*(s: string): Child =
|
||||
Child(kind: cSourceString, s: s)
|
||||
|
||||
|
||||
proc child*(node: SourceNode): Child =
|
||||
Child(kind: cSourceNode, node: node)
|
||||
|
||||
|
||||
proc newSourceNode(line: int, column: int, path: string, node: SourceNode, name: string = ""): SourceNode =
|
||||
SourceNode(line: line, column: column, source: path, name: name, children: @[child(node)])
|
||||
|
||||
|
||||
proc newSourceNode(line: int, column: int, path: string, s: string, name: string = ""): SourceNode =
|
||||
SourceNode(line: line, column: column, source: path, name: name, children: @[child(s)])
|
||||
|
||||
|
||||
proc newSourceNode(line: int, column: int, path: string, children: seq[Child], name: string = ""): SourceNode =
|
||||
SourceNode(line: line, column: column, source: path, name: name, children: children)
|
||||
|
||||
|
||||
|
||||
|
||||
# debugging
|
||||
|
||||
|
||||
proc text*(sourceNode: SourceNode, depth: int): string =
|
||||
let empty = " "
|
||||
result = &"{repeat(empty, depth)}SourceNode({sourceNode.source}:{sourceNode.line}:{sourceNode.column}):\n"
|
||||
for child in sourceNode.children:
|
||||
if child.kind == cSourceString:
|
||||
result.add(&"{repeat(empty, depth + 1)}{child.s}\n")
|
||||
else:
|
||||
result.add(child.node.text(depth + 1))
|
||||
|
||||
|
||||
proc `$`*(sourceNode: SourceNode): string = text(sourceNode, 0)
|
||||
|
||||
|
||||
# base64_VLQ
|
||||
func encode*(values: seq[int]): string {.raises: [].} =
|
||||
## Encodes a series of integers into a VLQ base64 encoded string
|
||||
# References:
|
||||
# - https://www.lucidchart.com/techblog/2019/08/22/decode-encoding-base64-vlqs-source-maps/
|
||||
# - https://github.com/rails/sprockets/blob/main/guides/source_maps.md#source-map-file
|
||||
const
|
||||
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
shift = 5
|
||||
continueBit = 1 shl 5
|
||||
mask = continueBit - 1
|
||||
for val in values:
|
||||
# Sign is stored in first bit
|
||||
var newVal = abs(val) shl 1
|
||||
if val < 0:
|
||||
newVal = newVal or 1
|
||||
# Now comes the variable length part
|
||||
# This is how we are able to store large numbers
|
||||
while true:
|
||||
# We only encode 5 bits.
|
||||
var masked = newVal and mask
|
||||
newVal = newVal shr shift
|
||||
# If there is still something left
|
||||
# then signify with the continue bit that the
|
||||
# decoder should keep decoding
|
||||
if newVal > 0:
|
||||
masked = masked or continueBit
|
||||
result &= alphabet[masked]
|
||||
# If the value is zero then we have nothing left to encode
|
||||
if newVal == 0:
|
||||
break
|
||||
|
||||
iterator tokenize*(line: string): (int, string) =
|
||||
## Goes through a line and splits it into Nim identifiers and
|
||||
## normal JS code. This allows us to map mangled names back to Nim names.
|
||||
## Yields (column, name). Doesn't yield anything but identifiers.
|
||||
## See mangleName in compiler/jsgen.nim for how name mangling is done
|
||||
var
|
||||
col = 0
|
||||
token = ""
|
||||
while col < line.len:
|
||||
var
|
||||
token: string
|
||||
name: string
|
||||
# First we find the next identifier
|
||||
col += line.skipWhitespace(col)
|
||||
col += line.skipUntil(IdentStartChars, col)
|
||||
let identStart = col
|
||||
col += line.parseIdent(token, col)
|
||||
# Idents will either be originalName_randomInt or HEXhexCode_randomInt
|
||||
if token.startsWith("HEX"):
|
||||
var hex: int
|
||||
# 3 = "HEX".len and we only want to parse the two integers after it
|
||||
discard token[3 ..< 5].parseHex(hex)
|
||||
name = $chr(hex)
|
||||
elif not token.endsWith("_Idx"): # Ignore address indexes
|
||||
# It might be in the form originalName_randomInt
|
||||
let lastUnderscore = token.rfind('_')
|
||||
if lastUnderscore != -1:
|
||||
name = token[0..<lastUnderscore]
|
||||
if name != "":
|
||||
yield (identStart, name)
|
||||
|
||||
func parse*(source: string): SourceInfo =
|
||||
## Parses the JS output for embedded line info
|
||||
## So it can convert those into a series of mappings
|
||||
var
|
||||
skipFirstLine = true
|
||||
currColumn = 0
|
||||
currLine = 0
|
||||
currFile = ""
|
||||
# Add each line as a node into the output
|
||||
for line in source.splitLines():
|
||||
var
|
||||
lineNumber: int
|
||||
linePath: string
|
||||
column: int
|
||||
if line.strip().scanf("/* line $i:$i \"$+\" */", lineNumber, column, linePath):
|
||||
# When we reach the first line mappinsegmentg then we can assume
|
||||
# we can map the rest of the JS lines to Nim lines
|
||||
currColumn = column # Column is already zero indexed
|
||||
currLine = lineNumber - 1
|
||||
currFile = linePath
|
||||
# Lines are zero indexed
|
||||
result.newLine(currFile, currLine)
|
||||
# Skip whitespace to find the starting column
|
||||
result.addSegment(currColumn, line.skipWhitespace())
|
||||
elif currFile != "":
|
||||
result.newLine(currFile, currLine)
|
||||
# There mightn't be any tokens so add a starting segment
|
||||
result.addSegment(currColumn, line.skipWhitespace())
|
||||
for jsColumn, token in line.tokenize:
|
||||
result.addSegment(currColumn, jsColumn, token)
|
||||
let integers = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
|
||||
|
||||
|
||||
proc encode*(i: int): string =
|
||||
result = ""
|
||||
var n = i
|
||||
if n < 0:
|
||||
n = (-n shl 1) or 1
|
||||
else:
|
||||
n = n shl 1
|
||||
|
||||
var z = 0
|
||||
while z == 0 or n > 0:
|
||||
var e = n and 31
|
||||
n = n shr 5
|
||||
if n > 0:
|
||||
e = e or 32
|
||||
|
||||
result.add(integers[e])
|
||||
z += 1
|
||||
|
||||
|
||||
type TokenState = enum Normal, String, Ident, Mangled
|
||||
|
||||
iterator tokenize*(line: string): (bool, string) =
|
||||
# result = @[]
|
||||
var state = Normal
|
||||
var token = ""
|
||||
var isMangled = false
|
||||
for z, ch in line:
|
||||
if ch.isAlphaAscii:
|
||||
if state == Normal:
|
||||
state = Ident
|
||||
if token.len > 0:
|
||||
yield (isMangled, token)
|
||||
token = $ch
|
||||
isMangled = false
|
||||
else:
|
||||
token.add(ch)
|
||||
elif ch == '_':
|
||||
if state == Ident:
|
||||
state = Mangled
|
||||
isMangled = true
|
||||
token.add($ch)
|
||||
elif ch != '"' and not ch.isAlphaNumeric:
|
||||
if state in {Ident, Mangled}:
|
||||
state = Normal
|
||||
if token.len > 0:
|
||||
yield (isMangled, token)
|
||||
token = $ch
|
||||
isMangled = false
|
||||
else:
|
||||
token.add($ch)
|
||||
elif ch == '"':
|
||||
if state != String:
|
||||
state = String
|
||||
if token.len > 0:
|
||||
yield (isMangled, token)
|
||||
token = $ch
|
||||
isMangled = false
|
||||
else:
|
||||
state = Normal
|
||||
token.add($ch)
|
||||
if token.len > 0:
|
||||
yield (isMangled, token)
|
||||
isMangled = false
|
||||
token = ""
|
||||
else:
|
||||
result.newLine()
|
||||
token.add($ch)
|
||||
if token.len > 0:
|
||||
yield (isMangled, token)
|
||||
|
||||
func toSourceMap*(info: SourceInfo, file: string): SourceMap {.raises: [].} =
|
||||
## Convert from high level SourceInfo into the required SourceMap object
|
||||
# Add basic info
|
||||
result.version = 3
|
||||
result.file = file
|
||||
result.sources = info.files
|
||||
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 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
|
||||
prevFile = 0
|
||||
prevLine = 0
|
||||
prevName = 0
|
||||
prevNimCol = 0
|
||||
proc parse*(source: string, path: string): SourceNode =
|
||||
let lines = source.splitLines()
|
||||
var lastLocation: SourceNode = nil
|
||||
result = newSourceNode(0, 0, path, @[])
|
||||
|
||||
# we just use one single parent and add all nim lines
|
||||
# as its children, I guess in typical codegen
|
||||
# that happens recursively on ast level
|
||||
# we also don't have column info, but I doubt more one nim lines can compile to one js
|
||||
# maybe in macros?
|
||||
|
||||
for mapping in info.mappings:
|
||||
# We know need to encode segments with the following fields
|
||||
# All these fields are relative to their previous values
|
||||
# - 0: Column in generated code
|
||||
# - 1: Index of Nim file in source list
|
||||
# - 2: Line in Nim source
|
||||
# - 3: Column in Nim source
|
||||
# - 4: Index in names list
|
||||
if mapping.inSource:
|
||||
# JS Column is special in that it is reset after every line
|
||||
var prevJSCol = 0
|
||||
for segment in mapping.segments:
|
||||
var values = @[segment.generated - prevJSCol, mapping.file - prevFile, mapping.line - prevLine, segment.original - prevNimCol]
|
||||
# Add name field if needed
|
||||
if segment.name != -1:
|
||||
values &= segment.name - prevName
|
||||
prevName = segment.name
|
||||
prevJSCol = segment.generated
|
||||
prevNimCol = segment.original
|
||||
prevFile = mapping.file
|
||||
prevLine = mapping.line
|
||||
result.mappings &= encode(values) & ","
|
||||
# Remove trailing ,
|
||||
if mapping.segments.len > 0:
|
||||
result.mappings.setLen(result.mappings.len - 1)
|
||||
for i, originalLine in lines:
|
||||
let line = originalLine.strip
|
||||
if line.len == 0:
|
||||
continue
|
||||
|
||||
# this shouldn't be a problem:
|
||||
# jsgen doesn't generate comments
|
||||
# and if you emit // line you probably know what you're doing
|
||||
if line.startsWith("// line"):
|
||||
if result.children.len > 0:
|
||||
result.children[^1].node.children.add(child(line & "\n"))
|
||||
let pos = line.find(" ", 8)
|
||||
let lineNumber = line[8 .. pos - 1].parseInt
|
||||
let linePath = line[pos + 2 .. ^2] # quotes
|
||||
|
||||
lastLocation = newSourceNode(
|
||||
lineNumber,
|
||||
0,
|
||||
linePath,
|
||||
@[])
|
||||
result.children.add(child(lastLocation))
|
||||
else:
|
||||
var last: SourceNode
|
||||
for token in line.tokenize():
|
||||
var name = ""
|
||||
if token[0]:
|
||||
name = token[1].split('_', 1)[0]
|
||||
|
||||
|
||||
if result.children.len > 0:
|
||||
result.children[^1].node.children.add(
|
||||
child(
|
||||
newSourceNode(
|
||||
result.children[^1].node.line,
|
||||
0,
|
||||
result.children[^1].node.source,
|
||||
token[1],
|
||||
name)))
|
||||
last = result.children[^1].node.children[^1].node
|
||||
else:
|
||||
result.children.add(
|
||||
child(
|
||||
newSourceNode(i + 1, 0, path, token[1], name)))
|
||||
last = result.children[^1].node
|
||||
let nl = "\n"
|
||||
if not last.isNil:
|
||||
last.source.add(nl)
|
||||
|
||||
result.mappings &= ";"
|
||||
proc cmp(a: Mapping, b: Mapping): int =
|
||||
var c = cmp(a.generated, b.generated)
|
||||
if c != 0:
|
||||
return c
|
||||
|
||||
proc genSourceMap*(source: string, outFile: string): SourceMap =
|
||||
let node = parse(source)
|
||||
result = node.toSourceMap(outFile)
|
||||
c = cmp(a.source, b.source)
|
||||
if c != 0:
|
||||
return c
|
||||
|
||||
c = cmp(a.original, b.original)
|
||||
if c != 0:
|
||||
return c
|
||||
|
||||
return cmp(a.name, b.name)
|
||||
|
||||
|
||||
proc index*[T](elements: seq[T], element: T): int =
|
||||
for z in 0 ..< elements.len:
|
||||
if elements[z] == element:
|
||||
return z
|
||||
return -1
|
||||
|
||||
|
||||
proc serializeMappings(map: SourceMapGenerator, mappings: seq[Mapping]): string =
|
||||
var previous = Mapping(generated: (line: 1, column: 0), original: (line: 0, column: 0), name: "", source: "")
|
||||
var previousSourceId = 0
|
||||
var previousNameId = 0
|
||||
var next = ""
|
||||
var nameId = 0
|
||||
var sourceId = 0
|
||||
result = ""
|
||||
|
||||
for z, mapping in mappings:
|
||||
next = ""
|
||||
|
||||
if mapping.generated.line != previous.generated.line:
|
||||
previous.generated.column = 0
|
||||
|
||||
while mapping.generated.line != previous.generated.line:
|
||||
next.add(";")
|
||||
previous.generated.line += 1
|
||||
|
||||
else:
|
||||
if z > 0:
|
||||
if cmp(mapping, mappings[z - 1]) == 0:
|
||||
continue
|
||||
next.add(",")
|
||||
|
||||
next.add(encode(mapping.generated.column - previous.generated.column))
|
||||
previous.generated.column = mapping.generated.column
|
||||
|
||||
if not mapping.noSource and mapping.source.len > 0:
|
||||
sourceId = map.sources.index(mapping.source)
|
||||
next.add(encode(sourceId - previousSourceId))
|
||||
previousSourceId = sourceId
|
||||
next.add(encode(mapping.original.line - 1 - previous.original.line))
|
||||
previous.original.line = mapping.original.line - 1
|
||||
next.add(encode(mapping.original.column - previous.original.column))
|
||||
previous.original.column = mapping.original.column
|
||||
|
||||
if not mapping.noName and mapping.name.len > 0:
|
||||
nameId = map.names.index(mapping.name)
|
||||
next.add(encode(nameId - previousNameId))
|
||||
previousNameId = nameId
|
||||
|
||||
result.add(next)
|
||||
|
||||
|
||||
proc gen*(map: SourceMapGenerator): SourceMap =
|
||||
var mappings = map.mappings.sorted do (a: Mapping, b: Mapping) -> int:
|
||||
cmp(a, b)
|
||||
result = SourceMap(
|
||||
file: map.file,
|
||||
version: 3,
|
||||
sources: map.sources[0..^1],
|
||||
names: map.names[0..^1],
|
||||
mappings: map.serializeMappings(mappings))
|
||||
|
||||
|
||||
|
||||
proc addMapping*(map: SourceMapGenerator, mapping: Mapping) =
|
||||
if not mapping.noSource and mapping.source notin map.sources:
|
||||
map.sources.add(mapping.source)
|
||||
|
||||
if not mapping.noName and mapping.name.len > 0 and mapping.name notin map.names:
|
||||
map.names.add(mapping.name)
|
||||
|
||||
# echo "map ", mapping.source, " ", mapping.original, " ", mapping.generated, " ", mapping.name
|
||||
map.mappings.add(mapping)
|
||||
|
||||
|
||||
proc walk*(node: SourceNode, fn: proc(line: string, original: SourceNode)) =
|
||||
for child in node.children:
|
||||
if child.kind == cSourceString and child.s.len > 0:
|
||||
fn(child.s, node)
|
||||
else:
|
||||
child.node.walk(fn)
|
||||
|
||||
|
||||
proc toSourceMap*(node: SourceNode, file: string): SourceMapGenerator =
|
||||
var map = SourceMapGenerator(file: file, sources: @[], names: @[], mappings: @[])
|
||||
|
||||
var generated = (line: 1, column: 0)
|
||||
var sourceMappingActive = false
|
||||
var lastOriginal = SourceNode(source: "", line: -1, column: 0, name: "", children: @[])
|
||||
|
||||
node.walk do (line: string, original: SourceNode):
|
||||
if original.source.endsWith(".js"):
|
||||
# ignore it
|
||||
discard
|
||||
else:
|
||||
if original.line != -1:
|
||||
if lastOriginal.source != original.source or
|
||||
lastOriginal.line != original.line or
|
||||
lastOriginal.column != original.column or
|
||||
lastOriginal.name != original.name:
|
||||
map.addMapping(
|
||||
Mapping(
|
||||
source: original.source,
|
||||
original: (line: original.line, column: original.column),
|
||||
generated: (line: generated.line, column: generated.column),
|
||||
name: original.name))
|
||||
|
||||
lastOriginal = SourceNode(
|
||||
source: original.source,
|
||||
line: original.line,
|
||||
column: original.column,
|
||||
name: original.name,
|
||||
children: lastOriginal.children)
|
||||
sourceMappingActive = true
|
||||
elif sourceMappingActive:
|
||||
map.addMapping(
|
||||
Mapping(
|
||||
noSource: true,
|
||||
noName: true,
|
||||
generated: (line: generated.line, column: generated.column),
|
||||
original: (line: -1, column: -1)))
|
||||
lastOriginal.line = -1
|
||||
sourceMappingActive = false
|
||||
|
||||
for z in 0 ..< line.len:
|
||||
if line[z] in Newlines:
|
||||
generated.line += 1
|
||||
generated.column = 0
|
||||
|
||||
if z == line.len - 1:
|
||||
lastOriginal.line = -1
|
||||
sourceMappingActive = false
|
||||
elif sourceMappingActive:
|
||||
map.addMapping(
|
||||
Mapping(
|
||||
source: original.source,
|
||||
original: (line: original.line, column: original.column),
|
||||
generated: (line: generated.line, column: generated.column),
|
||||
name: original.name))
|
||||
else:
|
||||
generated.column += 1
|
||||
|
||||
map
|
||||
|
||||
|
||||
proc genSourceMap*(source: string, outFile: string): (Rope, SourceMap) =
|
||||
let node = parse(source, outFile)
|
||||
let map = node.toSourceMap(file = outFile)
|
||||
((&"{source}\n//# sourceMappingURL={outFile}.map").rope, map.gen)
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -31,11 +31,9 @@ type
|
||||
TransformBodyFlag* = enum
|
||||
dontUseCache, useCache
|
||||
|
||||
proc transformBody*(g: ModuleGraph; idgen: IdGenerator, prc: PSym, flag: TransformBodyFlag, force = false): PNode
|
||||
|
||||
import closureiters
|
||||
from lambdalifting import nil
|
||||
proc transformBody*(g: ModuleGraph; idgen: IdGenerator, prc: PSym, flag: TransformBodyFlag): PNode
|
||||
|
||||
import closureiters, lambdalifting
|
||||
|
||||
type
|
||||
PTransCon = ref object # part of TContext; stackable
|
||||
@@ -70,6 +68,7 @@ proc newTransNode(kind: TNodeKind, n: PNode,
|
||||
sons: int): PNode {.inline.} =
|
||||
var x = newNodeIT(kind, n.info, n.typ)
|
||||
newSeq(x.sons, sons)
|
||||
x.typ = n.typ
|
||||
# x.flags = n.flags
|
||||
result = x
|
||||
|
||||
@@ -96,8 +95,8 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
|
||||
r.typ = typ #skipTypes(typ, {tyGenericInst, tyAlias, tySink})
|
||||
incl(r.flags, sfFromGeneric)
|
||||
let owner = getCurrOwner(c)
|
||||
if lambdalifting.isIterator(owner) and not c.tooEarly:
|
||||
result = lambdalifting.freshVarForClosureIter(c.graph, r, c.idgen, owner)
|
||||
if owner.isIterator and not c.tooEarly:
|
||||
result = freshVarForClosureIter(c.graph, r, c.idgen, owner)
|
||||
else:
|
||||
result = newSymNode(r)
|
||||
|
||||
@@ -122,10 +121,10 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||
discard transformBody(c.graph, c.idgen, s, useCache)
|
||||
if s.kind == skIterator:
|
||||
if c.tooEarly: return n
|
||||
else: return lambdalifting.liftIterSym(c.graph, n, c.idgen, getCurrOwner(c))
|
||||
else: return liftIterSym(c.graph, n, c.idgen, getCurrOwner(c))
|
||||
elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly:
|
||||
# top level .closure procs are still somewhat supported for 'Nake':
|
||||
return lambdalifting.makeClosure(c.graph, c.idgen, s, nil, n.info)
|
||||
return makeClosure(c.graph, c.idgen, s, nil, n.info)
|
||||
#elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure:
|
||||
# echo n.info, " come heer for ", c.tooEarly
|
||||
# if not c.tooEarly:
|
||||
@@ -175,8 +174,8 @@ proc transformSym(c: PTransf, n: PNode): PNode =
|
||||
|
||||
proc freshVar(c: PTransf; v: PSym): PNode =
|
||||
let owner = getCurrOwner(c)
|
||||
if lambdalifting.isIterator(owner) and not c.tooEarly:
|
||||
result = lambdalifting.freshVarForClosureIter(c.graph, v, c.idgen, owner)
|
||||
if owner.isIterator and not c.tooEarly:
|
||||
result = freshVarForClosureIter(c.graph, v, c.idgen, owner)
|
||||
else:
|
||||
var newVar = copySym(v, nextSymId(c.idgen))
|
||||
incl(newVar.flags, sfFromGeneric)
|
||||
@@ -1147,7 +1146,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:
|
||||
@@ -1157,12 +1156,12 @@ 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 = lambdalifting.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)
|
||||
|
||||
if lambdalifting.isIterator(prc):
|
||||
if prc.isIterator:
|
||||
result = g.transformClosureIterator(c.idgen, prc, result)
|
||||
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
@@ -753,13 +753,8 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 =
|
||||
assert(t.n.kind == nkRange)
|
||||
result = getOrdValue(t.n[0])
|
||||
of tyInt:
|
||||
if conf != nil:
|
||||
case conf.target.intSize
|
||||
of 8: result = toInt128(0x8000000000000000'i64)
|
||||
of 4: result = toInt128(-2147483648)
|
||||
of 2: result = toInt128(-32768)
|
||||
of 1: result = toInt128(-128)
|
||||
else: discard
|
||||
if conf != nil and conf.target.intSize == 4:
|
||||
result = toInt128(-2147483648)
|
||||
else:
|
||||
result = toInt128(0x8000000000000000'i64)
|
||||
of tyInt8: result = toInt128(-128)
|
||||
@@ -802,29 +797,6 @@ proc firstFloat*(t: PType): BiggestFloat =
|
||||
internalError(newPartialConfigRef(), "invalid kind for firstFloat(" & $t.kind & ')')
|
||||
NaN
|
||||
|
||||
proc targetSizeSignedToKind*(conf: ConfigRef): TTypeKind =
|
||||
case conf.target.intSize
|
||||
of 8: result = tyInt64
|
||||
of 4: result = tyInt32
|
||||
of 2: result = tyInt16
|
||||
else: discard
|
||||
|
||||
proc targetSizeUnsignedToKind*(conf: ConfigRef): TTypeKind =
|
||||
case conf.target.intSize
|
||||
of 8: result = tyUInt64
|
||||
of 4: result = tyUInt32
|
||||
of 2: result = tyUInt16
|
||||
else: discard
|
||||
|
||||
proc normalizeKind*(conf: ConfigRef, k: TTypeKind): TTypeKind =
|
||||
case k
|
||||
of tyInt:
|
||||
result = conf.targetSizeSignedToKind()
|
||||
of tyUInt:
|
||||
result = conf.targetSizeUnsignedToKind()
|
||||
else:
|
||||
result = k
|
||||
|
||||
proc lastOrd*(conf: ConfigRef; t: PType): Int128 =
|
||||
case t.kind
|
||||
of tyBool: result = toInt128(1'u)
|
||||
@@ -836,13 +808,7 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 =
|
||||
assert(t.n.kind == nkRange)
|
||||
result = getOrdValue(t.n[1])
|
||||
of tyInt:
|
||||
if conf != nil:
|
||||
case conf.target.intSize
|
||||
of 8: result = toInt128(0x7FFFFFFFFFFFFFFF'u64)
|
||||
of 4: result = toInt128(0x7FFFFFFF)
|
||||
of 2: result = toInt128(0x00007FFF)
|
||||
of 1: result = toInt128(0x0000007F)
|
||||
else: discard
|
||||
if conf != nil and conf.target.intSize == 4: result = toInt128(0x7FFFFFFF)
|
||||
else: result = toInt128(0x7FFFFFFFFFFFFFFF'u64)
|
||||
of tyInt8: result = toInt128(0x0000007F)
|
||||
of tyInt16: result = toInt128(0x00007FFF)
|
||||
@@ -1721,18 +1687,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:
|
||||
|
||||
@@ -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])
|
||||
@@ -1603,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)
|
||||
@@ -1674,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])
|
||||
@@ -1929,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
|
||||
@@ -2071,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
|
||||
@@ -2333,9 +2334,6 @@ 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)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import ast, idents, lineinfos, astalgo
|
||||
import vmdef
|
||||
import std/times
|
||||
import ast
|
||||
|
||||
template elementType*(T: typedesc): typedesc =
|
||||
typeof(block:
|
||||
@@ -45,12 +43,3 @@ proc toLit*[T](a: T): PNode =
|
||||
else:
|
||||
static: doAssert false, "not yet supported: " & $T # add as needed
|
||||
|
||||
proc toTimeLit*(a: Time, c: PCtx, obj: PNode, info: TLineInfo): PNode =
|
||||
# probably refactor it into `toLit` in the future
|
||||
result = newTree(nkObjConstr)
|
||||
result.add(newNode(nkEmpty)) # can be changed to a symbol according to PType
|
||||
for k, ai in fieldPairs(a):
|
||||
let reti = newNode(nkExprColonExpr)
|
||||
reti.add newSymNode(lookupInRecord(obj, getIdent(c.cache, k)), info)
|
||||
reti.add ai.toLit
|
||||
result.add reti
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -2011,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):
|
||||
@@ -2054,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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -336,9 +328,8 @@ proc registerAdditionalOps*(c: PCtx) =
|
||||
registerCallback c, "stdlib.osproc.execCmdEx", proc (a: VmArgs) {.nimcall.} =
|
||||
let options = getNode(a, 1).fromLit(set[osproc.ProcessOption])
|
||||
a.setResult osproc.execCmdEx(getString(a, 0), options).toLit
|
||||
registerCallback c, "stdlib.times.getTimeImpl", proc (a: VmArgs) =
|
||||
let obj = a.getNode(0).typ.n
|
||||
setResult(a, times.getTime().toTimeLit(c, obj, a.currentLineInfo))
|
||||
registerCallback c, "stdlib.times.getTime", proc (a: VmArgs) {.nimcall.} =
|
||||
setResult(a, times.getTime().toLit)
|
||||
|
||||
proc getEffectList(c: PCtx; a: VmArgs; effectIndex: int) =
|
||||
let fn = getNode(a, 0)
|
||||
@@ -382,10 +373,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) =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -181,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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
310
doc/docgen.md
310
doc/docgen.md
@@ -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.
|
||||
|
||||
@@ -28,9 +28,7 @@ operatorB = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 |
|
||||
symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
|
||||
| IDENT | KEYW
|
||||
exprColonEqExpr = expr (':'|'=' expr)?
|
||||
exprEqExpr = expr ('=' expr)?
|
||||
exprList = expr ^+ comma
|
||||
optionalExprList = expr ^* comma
|
||||
exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
|
||||
qualifiedIdent = symbol ('.' optInd symbol)?
|
||||
setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
|
||||
@@ -62,26 +60,25 @@ primarySuffix = '(' (exprColonEqExpr comma?)* ')'
|
||||
| DOTLIKEOP optInd symbol generalizedLit?
|
||||
| '[' optInd exprColonEqExprList optPar ']'
|
||||
| '{' optInd exprColonEqExprList optPar '}'
|
||||
| &( '`'|IDENT|literal|'cast'|'addr'|'type') expr (comma expr)* # command syntax
|
||||
pragma = '{.' optInd (exprColonEqExpr comma?)* optPar ('.}' | '}')
|
||||
identVis = symbol OPR? # postfix position
|
||||
identVisDot = symbol '.' optInd symbol OPR?
|
||||
identWithPragma = identVis pragma?
|
||||
identWithPragmaDot = identVisDot pragma?
|
||||
declColonEquals = identWithPragma (comma identWithPragma)* comma?
|
||||
(':' optInd typeDescExpr)? ('=' optInd expr)?
|
||||
(':' optInd typeDesc)? ('=' optInd expr)?
|
||||
identColonEquals = IDENT (comma IDENT)* comma?
|
||||
(':' optInd typeDescExpr)? ('=' optInd expr)?)
|
||||
tupleTypeBracket = '[' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
|
||||
tupleType = 'tuple' tupleTypeBracket
|
||||
tupleDecl = 'tuple' (tupleTypeBracket /
|
||||
COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?)
|
||||
(':' optInd typeDesc)? ('=' optInd expr)?)
|
||||
tupleDecl = 'tuple'
|
||||
'[' optInd (identColonEquals (comma/semicolon)?)* optPar ']' |
|
||||
COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
|
||||
paramList = '(' declColonEquals ^* (comma/semicolon) ')'
|
||||
paramListArrow = paramList? ('->' optInd typeDesc)?
|
||||
paramListColon = paramList? (':' optInd typeDesc)?
|
||||
doBlock = 'do' paramListArrow pragma? colcom stmt
|
||||
routineExpr = ('proc' | 'func' | 'iterator') paramListColon pragma? ('=' COMMENT? stmt)?
|
||||
routineType = ('proc' | 'iterator') paramListColon pragma?
|
||||
forStmt = 'for' ((varTuple / identWithPragma) ^+ comma) 'in' expr colcom stmt
|
||||
forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
|
||||
forExpr = forStmt
|
||||
expr = (blockExpr
|
||||
| ifExpr
|
||||
@@ -90,32 +87,25 @@ expr = (blockExpr
|
||||
| forExpr
|
||||
| tryExpr)
|
||||
/ simpleExpr
|
||||
simplePrimary = SIGILLIKEOP? identOrLiteral primarySuffix*
|
||||
commandStart = &('`'|IDENT|literal|'cast'|'addr'|'type'|'var'|'out'|
|
||||
'static'|'enum'|'tuple'|'object'|'proc')
|
||||
primary = simplePrimary (commandStart expr)
|
||||
/ operatorB primary
|
||||
/ routineExpr
|
||||
/ rawTypeDesc
|
||||
/ prefixOperator primary
|
||||
rawTypeDesc = (tupleType | routineType | 'enum' | 'object' |
|
||||
('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?)
|
||||
('not' expr)?
|
||||
typeDescExpr = (routineType / simpleExpr) ('not' expr)?
|
||||
typeDesc = rawTypeDesc / typeDescExpr
|
||||
typeDefValue = ((tupleDecl | enumDecl | objectDecl | conceptDecl |
|
||||
('ref' | 'ptr' | 'distinct') (tupleDecl | objectDecl))
|
||||
/ (simpleExpr (exprEqExpr ^+ comma postExprBlocks)?))
|
||||
('not' expr)?
|
||||
primary = operatorB primary primarySuffix* |
|
||||
tupleDecl | routineExpr | enumDecl
|
||||
objectDecl | conceptDecl | ('bind' primary)
|
||||
('var' | 'out' | 'ref' | 'ptr' | 'distinct') primary
|
||||
/ prefixOperator* identOrLiteral primarySuffix*
|
||||
typeDesc = simpleExpr ('not' expr)?
|
||||
typeDefAux = simpleExpr ('not' expr
|
||||
| postExprBlocks)?
|
||||
postExprBlocks = ':' stmt? ( IND{=} doBlock
|
||||
| IND{=} 'of' exprList ':' stmt
|
||||
| IND{=} 'elif' expr ':' stmt
|
||||
| IND{=} 'except' optionalExprList ':' stmt
|
||||
| IND{=} 'except' exprList ':' stmt
|
||||
| IND{=} 'finally' ':' stmt
|
||||
| IND{=} 'else' ':' stmt )*
|
||||
exprStmt = simpleExpr postExprBlocks?
|
||||
/ simplePrimary (exprEqExpr ^+ comma) postExprBlocks?
|
||||
/ simpleExpr '=' optInd (expr postExprBlocks?)
|
||||
exprStmt = simpleExpr
|
||||
(( '=' optInd expr colonBody? )
|
||||
/ ( expr ^+ comma
|
||||
postExprBlocks
|
||||
))?
|
||||
importStmt = 'import' optInd expr
|
||||
((comma expr)*
|
||||
/ 'except' optInd (expr ^+ comma))
|
||||
@@ -149,10 +139,10 @@ caseStmt = 'case' expr ':'? COMMENT?
|
||||
(IND{>} ofBranches DED
|
||||
| IND{=} ofBranches)
|
||||
tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
|
||||
(IND{=}? 'except' optionalExprList colcom stmt)*
|
||||
(IND{=}? 'except' exprList colcom stmt)*
|
||||
(IND{=}? 'finally' colcom stmt)?
|
||||
tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
|
||||
(optInd 'except' optionalExprList colcom stmt)*
|
||||
(optInd 'except' exprList colcom stmt)*
|
||||
(optInd 'finally' colcom stmt)?
|
||||
blockStmt = 'block' symbol? colcom stmt
|
||||
blockExpr = 'block' symbol? colcom stmt
|
||||
@@ -185,7 +175,7 @@ objectDecl = 'object' ('of' typeDesc)? COMMENT? objectPart
|
||||
conceptParam = ('var' | 'out')? symbol
|
||||
conceptDecl = 'concept' conceptParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
|
||||
&IND{>} stmt
|
||||
typeDef = identVisDot genericParamList? pragma '=' optInd typeDefValue
|
||||
typeDef = identVisDot genericParamList? pragma '=' optInd typeDefAux
|
||||
indAndComment?
|
||||
varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
|
||||
colonBody = colcom stmt postExprBlocks?
|
||||
|
||||
179
doc/lib.md
179
doc/lib.md
@@ -46,19 +46,15 @@ Core
|
||||
* [bitops](bitops.html)
|
||||
Provides a series of low-level methods for bit manipulation.
|
||||
|
||||
* [compilesettings](compilesettings.html)
|
||||
This module allows querying the compiler about diverse configuration settings.
|
||||
|
||||
* [cpuinfo](cpuinfo.html)
|
||||
This module implements procs to determine the number of CPUs / cores.
|
||||
|
||||
* [effecttraits](effecttraits.html)
|
||||
This module provides access to the inferred .raises effects
|
||||
for Nim's macro system.
|
||||
|
||||
* [endians](endians.html)
|
||||
This module contains helpers that deal with different byte orders.
|
||||
|
||||
* [lenientops](lenientops.html)
|
||||
Provides binary operators for mixed integer/float expressions for convenience.
|
||||
|
||||
* [locks](locks.html)
|
||||
Locks and condition variables for Nim.
|
||||
|
||||
@@ -126,19 +122,9 @@ Collections
|
||||
* [packedsets](packedsets.html)
|
||||
Efficient implementation of a set of ordinals as a sparse bit set.
|
||||
|
||||
* [ropes](ropes.html)
|
||||
This module contains support for a *rope* data type.
|
||||
Ropes can represent very long strings efficiently;
|
||||
in particular, concatenation is done in O(1) instead of O(n).
|
||||
|
||||
* [sets](sets.html)
|
||||
Nim hash set support.
|
||||
|
||||
* [strtabs](strtabs.html)
|
||||
The `strtabs` module implements an efficient hash table that is a mapping
|
||||
from strings to strings. Supports a case-sensitive, case-insensitive and
|
||||
style-insensitive modes.
|
||||
|
||||
* [tables](tables.html)
|
||||
Nim hash table support. Contains tables, ordered tables, and count tables.
|
||||
|
||||
@@ -157,15 +143,20 @@ String handling
|
||||
Converts between different character encodings. On UNIX, this uses
|
||||
the `iconv` library, on Windows the Windows API.
|
||||
|
||||
* [formatfloat](formatfloat.html)
|
||||
This module implements formatting floats as strings.
|
||||
* [parseutils](parseutils.html)
|
||||
This module contains helpers for parsing tokens, numbers, identifiers, etc.
|
||||
|
||||
* [objectdollar](objectdollar.html)
|
||||
This module implements a generic `$` operator to convert objects to strings.
|
||||
* [pegs](pegs.html)
|
||||
This module contains procedures and operators for handling PEGs.
|
||||
|
||||
* [punycode](punycode.html)
|
||||
Implements a representation of Unicode with the limited ASCII character subset.
|
||||
|
||||
* [ropes](ropes.html)
|
||||
This module contains support for a *rope* data type.
|
||||
Ropes can represent very long strings efficiently;
|
||||
in particular, concatenation is done in O(1) instead of O(n).
|
||||
|
||||
* [strbasics](strbasics.html)
|
||||
This module provides some high performance string operations.
|
||||
|
||||
@@ -180,6 +171,11 @@ String handling
|
||||
* [strscans](strscans.html)
|
||||
This module contains a `scanf` macro for convenient parsing of mini languages.
|
||||
|
||||
* [strtabs](strtabs.html)
|
||||
The `strtabs` module implements an efficient hash table that is a mapping
|
||||
from strings to strings. Supports a case-sensitive, case-insensitive and
|
||||
style-insensitive modes.
|
||||
|
||||
* [strutils](strutils.html)
|
||||
This module contains common string handling operations like changing
|
||||
case of a string, splitting a string into substrings, searching for
|
||||
@@ -192,9 +188,6 @@ String handling
|
||||
It provides a single proc that does Unicode to ASCII transliterations.
|
||||
Based on Python's Unidecode module.
|
||||
|
||||
* [widestrs](widestrs.html)
|
||||
Nim support for C/C++'s wide strings.
|
||||
|
||||
* [wordwrap](wordwrap.html)
|
||||
This module contains an algorithm to wordwrap a Unicode string.
|
||||
|
||||
@@ -212,16 +205,6 @@ Time handling
|
||||
Generic Operating System Services
|
||||
---------------------------------
|
||||
|
||||
* [appdirs](appdirs.html)
|
||||
This module implements helpers for determining special directories used by apps.
|
||||
|
||||
* [cmdline](cmdline.html)
|
||||
This module contains system facilities for reading command
|
||||
line parameters.
|
||||
|
||||
* [dirs](dirs.html)
|
||||
This module implements directory handling.
|
||||
|
||||
* [distros](distros.html)
|
||||
This module implements the basics for OS distribution ("distro") detection
|
||||
and the OS's native package manager.
|
||||
@@ -233,14 +216,9 @@ Generic Operating System Services
|
||||
* [dynlib](dynlib.html)
|
||||
This module implements the ability to access symbols from shared libraries.
|
||||
|
||||
* [envvars](envvars.html)
|
||||
This module implements environment variable handling.
|
||||
|
||||
* [exitprocs](exitprocs.html)
|
||||
This module allows adding hooks to program exit.
|
||||
|
||||
* [files](files.html)
|
||||
This module implements file handling.
|
||||
* [marshal](marshal.html)
|
||||
Contains procs for serialization and deserialization of arbitrary Nim
|
||||
data structures.
|
||||
|
||||
* [memfiles](memfiles.html)
|
||||
This module provides support for memory-mapped files (Posix's `mmap`)
|
||||
@@ -251,31 +229,15 @@ Generic Operating System Services
|
||||
reading command line arguments, working with directories, running shell
|
||||
commands, etc.
|
||||
|
||||
* [oserrors](oserrors.html)
|
||||
This module implements OS error reporting.
|
||||
|
||||
* [osproc](osproc.html)
|
||||
Module for process communication beyond `os.execShellCmd`.
|
||||
|
||||
* [paths](paths.html)
|
||||
This module implements path handling.
|
||||
|
||||
* [reservedmem](reservedmem.html)
|
||||
This module provides utilities for reserving portions of the
|
||||
address space of a program without consuming physical memory.
|
||||
|
||||
* [streams](streams.html)
|
||||
This module provides a stream interface and two implementations thereof:
|
||||
the `FileStream` and the `StringStream` which implement the stream
|
||||
interface for Nim file objects (`File`) and strings. Other modules
|
||||
may provide other implementations for this standard stream interface.
|
||||
|
||||
* [symlinks](symlinks.html)
|
||||
This module implements symlink handling.
|
||||
|
||||
* [syncio](syncio.html)
|
||||
This module implements various synchronized I/O operations.
|
||||
|
||||
* [terminal](terminal.html)
|
||||
This module contains a few procedures to control the *terminal*
|
||||
(also called *console*). The implementation simply uses ANSI escape
|
||||
@@ -296,9 +258,6 @@ Math libraries
|
||||
Floating-point environment. Handling of floating-point rounding and
|
||||
exceptions (overflow, zero-divide, etc.).
|
||||
|
||||
* [lenientops](lenientops.html)
|
||||
Provides binary operators for mixed integer/float expressions for convenience.
|
||||
|
||||
* [math](math.html)
|
||||
Mathematical operations like cosine, square root.
|
||||
|
||||
@@ -311,6 +270,9 @@ Math libraries
|
||||
* [stats](stats.html)
|
||||
Statistical analysis.
|
||||
|
||||
* [sums](sums.html)
|
||||
Accurate summation functions.
|
||||
|
||||
* [sysrand](sysrand.html)
|
||||
Cryptographically secure pseudorandom number generator.
|
||||
|
||||
@@ -318,9 +280,6 @@ Math libraries
|
||||
Internet Protocols and Support
|
||||
------------------------------
|
||||
|
||||
* [async](async.html)
|
||||
Exports `asyncmacro` and `asyncfutures` for native backends, and `asyncjs` on the JS backend.
|
||||
|
||||
* [asyncdispatch](asyncdispatch.html)
|
||||
This module implements an asynchronous dispatcher for IO operations.
|
||||
|
||||
@@ -336,9 +295,6 @@ Internet Protocols and Support
|
||||
This module implements an asynchronous HTTP server using the `asyncnet`
|
||||
module.
|
||||
|
||||
* [asyncmacro](asyncmacro.html)
|
||||
Implements the `async` and `multisync` macros for `asyncdispatch`.
|
||||
|
||||
* [asyncnet](asyncnet.html)
|
||||
This module implements asynchronous sockets based on the `asyncdispatch`
|
||||
module.
|
||||
@@ -370,13 +326,6 @@ Internet Protocols and Support
|
||||
This module implements a selector API with backends specific to each OS.
|
||||
Currently, epoll on Linux and select on other operating systems.
|
||||
|
||||
* [smtp](smtp.html)
|
||||
This module implements a simple SMTP client.
|
||||
|
||||
* [socketstreams](socketstreams.html)
|
||||
This module provides an implementation of the streams interface for sockets.
|
||||
|
||||
|
||||
* [uri](uri.html)
|
||||
This module provides functions for working with URIs.
|
||||
|
||||
@@ -384,20 +333,12 @@ Internet Protocols and Support
|
||||
Threading
|
||||
---------
|
||||
|
||||
* [isolation](isolation.html)
|
||||
This module implements the `Isolated[T]` type for
|
||||
safe construction of isolated subgraphs that can be
|
||||
passed efficiently to different channels and threads.
|
||||
|
||||
* [tasks](tasks.html)
|
||||
This module provides basic primitives for creating parallel programs.
|
||||
* [threads](threads.html)
|
||||
Basic Nim thread support.
|
||||
|
||||
* [threadpool](threadpool.html)
|
||||
Implements Nim's [spawn](manual_experimental.html#parallel-amp-spawn).
|
||||
|
||||
* [typedthreads](typedthreads.html)
|
||||
Basic Nim thread support.
|
||||
|
||||
|
||||
Parsers
|
||||
-------
|
||||
@@ -408,6 +349,9 @@ Parsers
|
||||
* [json](json.html)
|
||||
High-performance JSON parser.
|
||||
|
||||
* [jsonutils](jsonutils.html)
|
||||
This module implements a hookable (de)serialization for arbitrary types.
|
||||
|
||||
* [lexbase](lexbase.html)
|
||||
This is a low-level module that implements an extremely efficient buffering
|
||||
scheme for lexers and parsers. This is used by the diverse parsing modules.
|
||||
@@ -431,18 +375,12 @@ Parsers
|
||||
* [parsesql](parsesql.html)
|
||||
The `parsesql` module implements a simple high-performance SQL parser.
|
||||
|
||||
* [parseutils](parseutils.html)
|
||||
This module contains helpers for parsing tokens, numbers, identifiers, etc.
|
||||
|
||||
* [parsexml](parsexml.html)
|
||||
The `parsexml` module implements a simple high performance XML/HTML parser.
|
||||
The only encoding that is supported is UTF-8. The parser has been designed
|
||||
to be somewhat error-correcting, so that even some "wild HTML" found on the
|
||||
web can be parsed with it.
|
||||
|
||||
* [pegs](pegs.html)
|
||||
This module contains procedures and operators for handling PEGs.
|
||||
|
||||
|
||||
Docutils
|
||||
--------
|
||||
@@ -477,9 +415,6 @@ XML Processing
|
||||
Generators
|
||||
----------
|
||||
|
||||
* [genasts](genasts.html)
|
||||
This module implements AST generation using captured variables for macros.
|
||||
|
||||
* [htmlgen](htmlgen.html)
|
||||
This module implements a simple XML and HTML code
|
||||
generator. Each commonly used HTML tag has a corresponding macro
|
||||
@@ -508,24 +443,9 @@ Hashing
|
||||
This module implements the SHA-1 checksum algorithm.
|
||||
|
||||
|
||||
Serialization
|
||||
-------------
|
||||
|
||||
* [jsonutils](jsonutils.html)
|
||||
This module implements a hookable (de)serialization for arbitrary types
|
||||
using JSON.
|
||||
|
||||
* [marshal](marshal.html)
|
||||
Contains procs for serialization and deserialization of arbitrary Nim
|
||||
data structures.
|
||||
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
* [assertions](assertions.html)
|
||||
This module implements assertion handling.
|
||||
|
||||
* [browsers](browsers.html)
|
||||
This module implements procs for opening URLs with the user's default
|
||||
browser.
|
||||
@@ -536,15 +456,9 @@ Miscellaneous
|
||||
* [coro](coro.html)
|
||||
This module implements experimental coroutines in Nim.
|
||||
|
||||
* [decls](decls.html)
|
||||
This module implements syntax sugar for some declarations.
|
||||
|
||||
* [enumerate](enumerate.html)
|
||||
This module implements `enumerate` syntactic sugar based on Nim's macro system.
|
||||
|
||||
* [importutils](importutils.html)
|
||||
Utilities related to import and symbol resolution.
|
||||
|
||||
* [logging](logging.html)
|
||||
This module implements a simple logger.
|
||||
|
||||
@@ -563,12 +477,9 @@ Miscellaneous
|
||||
* [with](with.html)
|
||||
This module implements the `with` macro for easy function chaining.
|
||||
|
||||
* [wrapnils](wrapnils.html)
|
||||
This module allows evaluating expressions safely against nil dereferences.
|
||||
|
||||
|
||||
Modules for the JavaScript backend
|
||||
----------------------------------
|
||||
Modules for the JS backend
|
||||
--------------------------
|
||||
|
||||
* [asyncjs](asyncjs.html)
|
||||
Types and macros for writing asynchronous procedures in JavaScript.
|
||||
@@ -586,15 +497,9 @@ Modules for the JavaScript backend
|
||||
The wrapper of core JavaScript functions. For most purposes, you should be using
|
||||
the `math`, `json`, and `times` stdlib modules instead of this module.
|
||||
|
||||
* [jsfetch](jshttp.html)
|
||||
Wrapper for `fetch`.
|
||||
|
||||
* [jsffi](jsffi.html)
|
||||
Types and macros for easier interaction with JavaScript.
|
||||
|
||||
* [jsre](jsre.html)
|
||||
Regular Expressions for the JavaScript target.
|
||||
|
||||
|
||||
Impure libraries
|
||||
================
|
||||
@@ -606,26 +511,18 @@ Regular expressions
|
||||
This module contains procedures and operators for handling regular
|
||||
expressions. The current implementation uses PCRE.
|
||||
|
||||
* [nre](nre.html)
|
||||
|
||||
This module contains many help functions for handling regular expressions.
|
||||
The current implementation uses PCRE.
|
||||
|
||||
Database support
|
||||
----------------
|
||||
|
||||
* [db_mysql](db_mysql.html)
|
||||
A higher level MySQL database wrapper. The same interface is implemented
|
||||
for other databases too.
|
||||
|
||||
* [db_odbc](db_odbc.html)
|
||||
A higher level ODBC database wrapper. The same interface is implemented
|
||||
for other databases too.
|
||||
|
||||
* [db_postgres](db_postgres.html)
|
||||
A higher level PostgreSQL database wrapper. The same interface is implemented
|
||||
for other databases too.
|
||||
|
||||
* [db_mysql](db_mysql.html)
|
||||
A higher level MySQL database wrapper. The same interface is implemented
|
||||
for other databases too.
|
||||
|
||||
* [db_sqlite](db_sqlite.html)
|
||||
A higher level SQLite database wrapper. The same interface is implemented
|
||||
for other databases too.
|
||||
@@ -673,14 +570,14 @@ Regular expressions
|
||||
Database support
|
||||
----------------
|
||||
|
||||
* [mysql](mysql.html)
|
||||
Contains a wrapper for the mySQL API.
|
||||
* [odbcsql](odbcsql.html)
|
||||
interface to the ODBC driver.
|
||||
* [postgres](postgres.html)
|
||||
Contains a wrapper for the PostgreSQL API.
|
||||
* [mysql](mysql.html)
|
||||
Contains a wrapper for the mySQL API.
|
||||
* [sqlite3](sqlite3.html)
|
||||
Contains a wrapper for the SQLite 3 API.
|
||||
* [odbcsql](odbcsql.html)
|
||||
interface to the ODBC driver.
|
||||
|
||||
|
||||
Network Programming and Internet Protocols
|
||||
|
||||
@@ -4773,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)
|
||||
```
|
||||
@@ -4786,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.
|
||||
|
||||
@@ -4803,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"
|
||||
```
|
||||
|
||||
@@ -4815,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)
|
||||
```
|
||||
|
||||
|
||||
@@ -4865,7 +4867,7 @@ error message from `e`, and for such situations, it is enough to use
|
||||
```nim
|
||||
try:
|
||||
# ...
|
||||
except CatchableError:
|
||||
except:
|
||||
echo getCurrentExceptionMsg()
|
||||
```
|
||||
|
||||
@@ -5053,7 +5055,7 @@ An empty `raises` list (`raises: []`) means that no exception may be raised:
|
||||
try:
|
||||
unsafeCall()
|
||||
result = true
|
||||
except CatchableError:
|
||||
except:
|
||||
result = false
|
||||
```
|
||||
|
||||
@@ -8047,24 +8049,6 @@ used. To see if a value was provided, `defined(FooBar)` can be used.
|
||||
The syntax `-d:flag`:option: is actually just a shortcut for
|
||||
`-d:flag=true`:option:.
|
||||
|
||||
These pragmas also accept an optional string argument for qualified
|
||||
define names.
|
||||
|
||||
```nim
|
||||
const FooBar {.intdefine: "package.FooBar".}: int = 5
|
||||
echo FooBar
|
||||
```
|
||||
|
||||
```cmd
|
||||
nim c -d:package.FooBar=42 foobar.nim
|
||||
```
|
||||
|
||||
This helps disambiguate define names in different packages.
|
||||
|
||||
See also the [generic `define` pragma](manual_experimental.html#generic-define-pragma)
|
||||
for a version of these pragmas that detects the type of the define based on
|
||||
the constant value.
|
||||
|
||||
User-defined pragmas
|
||||
====================
|
||||
|
||||
@@ -8440,12 +8424,23 @@ This is only useful if the program is compiled as a dynamic library via the
|
||||
`--app:lib`:option: command-line option.
|
||||
|
||||
|
||||
|
||||
Threads
|
||||
=======
|
||||
|
||||
The `--threads:on`:option: command-line switch is enabled by default. The [typedthreads module](typedthreads.html) module then contains several threading primitives. See [spawn](manual_experimental.html#parallel-amp-spawn) for
|
||||
To enable thread support the `--threads:on`:option: command-line switch needs to
|
||||
be used. The [system module](system.html) module then contains several threading primitives.
|
||||
See the [channels](channels_builtin.html) modules
|
||||
for the low-level thread API. There are also high-level parallelism constructs
|
||||
available. See [spawn](manual_experimental.html#parallel-amp-spawn) for
|
||||
further details.
|
||||
|
||||
Nim's memory model for threads is quite different than that of other common
|
||||
programming languages (C, Pascal, Java): Each thread has its own (garbage
|
||||
collected) heap, and sharing of memory is restricted to global variables. This
|
||||
helps to prevent race conditions. GC efficiency is improved quite a lot,
|
||||
because the GC never has to stop other threads and see what they reference.
|
||||
|
||||
The only way to create a thread is via `spawn` or
|
||||
`createThread`. The invoked proc must not use `var` parameters nor must
|
||||
any of its parameters contain a `ref` or `closure` type. This enforces
|
||||
|
||||
@@ -65,29 +65,6 @@ However, a `void` type cannot be inferred in generic code:
|
||||
The `void` type is only valid for parameters and return types; other symbols
|
||||
cannot have the type `void`.
|
||||
|
||||
Generic `define` pragma
|
||||
=======================
|
||||
|
||||
Aside the [typed define pragmas for constants](manual.html#implementation-specific-pragmas-compileminustime-define-pragmas),
|
||||
there is a generic `{.define.}` pragma that interprets the value of the define
|
||||
based on the type of the constant value.
|
||||
|
||||
```nim
|
||||
const foo {.define: "package.foo".} = 123
|
||||
const bar {.define: "package.bar".} = false
|
||||
```
|
||||
|
||||
```cmd
|
||||
nim c -d:package.foo=456 -d:package.bar foobar.nim
|
||||
```
|
||||
|
||||
The following types are supported:
|
||||
|
||||
* `string` and `cstring`
|
||||
* Signed and unsigned integer types
|
||||
* `bool`
|
||||
* Enums
|
||||
|
||||
Top-down type inference
|
||||
=======================
|
||||
|
||||
@@ -542,7 +519,8 @@ Since version 1.4, a stricter definition of "side effect" is available.
|
||||
In addition to the existing rule that a side effect is calling a function
|
||||
with side effects, the following rule is also enforced:
|
||||
|
||||
A store to the heap via a `ref` or `ptr` indirection is not allowed.
|
||||
Any mutation to an object does count as a side effect if that object is reachable
|
||||
via a parameter that is not declared as a `var` parameter.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -562,14 +540,17 @@ For example:
|
||||
it = it.ri
|
||||
|
||||
func mut(n: Node) =
|
||||
var it = n
|
||||
while it != nil:
|
||||
it.data = "yeah" # forbidden mutation
|
||||
it = it.ri
|
||||
|
||||
let m = n # is the statement that connected the mutation to the parameter
|
||||
m.data = "yeah" # the mutation is here
|
||||
# Error: 'mut' can have side effects
|
||||
# an object reachable from 'n' is potentially mutated
|
||||
```
|
||||
|
||||
|
||||
The algorithm behind this analysis is described in
|
||||
the [view types algorithm][Algorithm].
|
||||
|
||||
|
||||
View types
|
||||
==========
|
||||
|
||||
@@ -1878,20 +1859,6 @@ before it is used. Thus the following is valid:
|
||||
|
||||
In this example every path does set `s` to a value before it is used.
|
||||
|
||||
```nim
|
||||
{.experimental: "strictDefs".}
|
||||
|
||||
proc test(cond: bool) =
|
||||
let s: seq[string]
|
||||
if cond:
|
||||
s = @["y"]
|
||||
else:
|
||||
s = @[]
|
||||
```
|
||||
|
||||
With `experimental: "strictDefs"`, `let` statements are allowed to not have an initial value, but every path should set `s` to a value before it is used.
|
||||
|
||||
|
||||
`out` parameters
|
||||
----------------
|
||||
|
||||
|
||||
@@ -74,9 +74,7 @@ local turn on/off
|
||||
---------------------
|
||||
|
||||
You can still turn off nil checking on function/module level by using a `{.strictNotNil: off.}` pragma.
|
||||
|
||||
..
|
||||
Note: test that/TODO for code/manual.
|
||||
Note: test that/TODO for code/manual.
|
||||
|
||||
nilability state
|
||||
-----------------
|
||||
@@ -103,8 +101,7 @@ Types are either nilable or non-nilable.
|
||||
When you pass a param or a default value, we use the type : for nilable types we return `MaybeNil`
|
||||
and for non-nilable `Safe`.
|
||||
|
||||
..
|
||||
TODO: fix the manual here. (This is not great, as default values for non-nilables and nilables are usually actually `nil` , so we should think a bit more about this section.)
|
||||
TODO: fix the manual here. (This is not great, as default values for non-nilables and nilables are usually actually `nil` , so we should think a bit more about this section.)
|
||||
|
||||
params rules
|
||||
------------
|
||||
@@ -239,11 +236,11 @@ e.g.
|
||||
left = nil # moving out
|
||||
```
|
||||
|
||||
..
|
||||
initialization of non nilable and nilable values
|
||||
-------------------------------------------------
|
||||
|
||||
TODO
|
||||
initialization of non nilable and nilable values
|
||||
-------------------------------------------------
|
||||
|
||||
TODO
|
||||
|
||||
warnings and errors
|
||||
---------------------
|
||||
|
||||
@@ -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
|
||||
--------------
|
||||
|
||||
|
||||
@@ -440,7 +440,6 @@ or setup a ``nim.cfg`` file like so:
|
||||
#nim.cfg
|
||||
--mm:orc
|
||||
--d:nimAllocPagesViaMalloc
|
||||
--define:nimInheritHandles
|
||||
--passC="-I$DEVKITPRO/libnx/include"
|
||||
--passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx"
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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)'
|
||||
|
||||
@@ -76,6 +76,7 @@ At least the following standard library modules are available:
|
||||
* [htmlgen](htmlgen.html)
|
||||
* [httpcore](httpcore.html)
|
||||
* [lenientops](lenientops.html)
|
||||
* [mersenne](mersenne.html)
|
||||
* [options](options.html)
|
||||
* [parseutils](parseutils.html)
|
||||
* [punycode](punycode.html)
|
||||
@@ -88,6 +89,7 @@ At least the following standard library modules are available:
|
||||
* [uri](uri.html)
|
||||
* [std/editdistance](editdistance.html)
|
||||
* [std/wordwrap](wordwrap.html)
|
||||
* [std/sums](sums.html)
|
||||
* [parsecsv](parsecsv.html)
|
||||
* [parsecfg](parsecfg.html)
|
||||
* [parsesql](parsesql.html)
|
||||
@@ -211,7 +213,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
|
||||
|
||||
@@ -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/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
|
||||
|
||||
@@ -38,14 +38,6 @@ can also be used to include elements (and ranges of elements):
|
||||
# from '0' to '9'
|
||||
```
|
||||
|
||||
The module [`std/setutils`](https://nim-lang.org/docs/setutils.html) provides a way to initialize a set from an iterable:
|
||||
|
||||
```nim
|
||||
import std/setutils
|
||||
|
||||
let uniqueChars = myString.toSet
|
||||
```
|
||||
|
||||
These operations are supported by sets:
|
||||
|
||||
================== ========================================================
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
2
koch.nim
2
koch.nim
@@ -10,7 +10,7 @@
|
||||
#
|
||||
|
||||
const
|
||||
NimbleStableCommit = "7efb226ef908297e8791cade20d991784b4e8bfc" # master
|
||||
NimbleStableCommit = "d13f3b8ce288b4dc8c34c219a4e050aaeaf43fc9" # master
|
||||
# examples of possible values: #head, #ea82b54, 1.2.3
|
||||
FusionStableHash = "#372ee4313827ef9f2ea388840f7d6b46c2b1b014"
|
||||
HeadHash = "#head"
|
||||
|
||||
@@ -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".}
|
||||
|
||||
|
||||
@@ -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:
|
||||
@@ -1599,9 +1582,11 @@ proc customPragmaNode(n: NimNode): NimNode =
|
||||
|
||||
if n.kind in {nnkDotExpr, nnkCheckedFieldExpr}:
|
||||
let name = $(if n.kind == nnkCheckedFieldExpr: n[0][1] else: n[1])
|
||||
var typInst = getTypeInst(if n.kind == nnkCheckedFieldExpr or n[0].kind == nnkHiddenDeref: n[0][0] else: n[0])
|
||||
while typInst.kind in {nnkVarTy, nnkBracketExpr}: typInst = typInst[0]
|
||||
var typDef = getImpl(typInst)
|
||||
let typInst = getTypeInst(if n.kind == nnkCheckedFieldExpr or n[0].kind == nnkHiddenDeref: n[0][0] else: n[0])
|
||||
var typDef = getImpl(
|
||||
if typInst.kind in {nnkVarTy, nnkBracketExpr}: typInst[0]
|
||||
else: typInst
|
||||
)
|
||||
while typDef != nil:
|
||||
typDef.expectKind(nnkTypeDef)
|
||||
let typ = typDef[2].extractTypeImpl()
|
||||
|
||||
@@ -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)[])
|
||||
|
||||
@@ -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
|
||||
## ---------
|
||||
##
|
||||
|
||||
@@ -22,6 +22,8 @@ runnableExamples("-r:off"):
|
||||
if line.len > 0: echo line
|
||||
echo "exiting"
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/syncio
|
||||
|
||||
when defined(windows):
|
||||
when defined(nimPreviewSlimSystem):
|
||||
|
||||
@@ -17,10 +17,6 @@ when defined(js):
|
||||
## C library. This means that your application will depend on the PCRE
|
||||
## library's licence when using this module, which should not be a problem
|
||||
## though.
|
||||
##
|
||||
## .. note:: There are also alternative nimble packages such as [tinyre](https://github.com/khchen/tinyre)
|
||||
## and [regex](https://github.com/nitely/nim-regex).
|
||||
##
|
||||
## PCRE's licence follows:
|
||||
##
|
||||
## .. include:: ../../doc/regexprs.txt
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
## `type LangSymbol`_ in ``rst.nim``, while `match(generated, docLink)`_
|
||||
## matches it with `generated`, produced from `PNode` by ``docgen.rst``.
|
||||
|
||||
import rstast, strutils
|
||||
import rstast
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[assertions, syncio]
|
||||
@@ -35,12 +35,6 @@ type
|
||||
## name-type seq, e.g. for proc
|
||||
outType*: string ## result type, e.g. for proc
|
||||
|
||||
proc `$`*(s: LangSymbol): string = # for debug
|
||||
("(symkind=$1, symTypeKind=$2, name=$3, generics=$4, isGroup=$5, " &
|
||||
"parametersProvided=$6, parameters=$7, outType=$8)") % [
|
||||
s.symKind, s.symTypeKind , s.name, s.generics, $s.isGroup,
|
||||
$s.parametersProvided, $s.parameters, s.outType]
|
||||
|
||||
func nimIdentBackticksNormalize*(s: string): string =
|
||||
## Normalizes the string `s` as a Nim identifier.
|
||||
##
|
||||
@@ -77,12 +71,6 @@ func nimIdentBackticksNormalize*(s: string): string =
|
||||
else: discard # just omit '`' or ' '
|
||||
if j != s.len: setLen(result, j)
|
||||
|
||||
proc langSymbolGroup*(kind: string, name: string): LangSymbol =
|
||||
if kind notin ["proc", "func", "macro", "method", "iterator",
|
||||
"template", "converter"]:
|
||||
raise newException(ValueError, "unknown symbol kind $1" % [kind])
|
||||
result = LangSymbol(symKind: kind, name: name, isGroup: true)
|
||||
|
||||
proc toLangSymbol*(linkText: PRstNode): LangSymbol =
|
||||
## Parses `linkText` into a more structured form using a state machine.
|
||||
##
|
||||
@@ -94,14 +82,11 @@ proc toLangSymbol*(linkText: PRstNode): LangSymbol =
|
||||
##
|
||||
## This proc should be kept in sync with the `renderTypes` proc from
|
||||
## ``compiler/typesrenderer.nim``.
|
||||
template fail(msg: string) =
|
||||
raise newException(ValueError, msg)
|
||||
if linkText.kind notin {rnRstRef, rnInner}:
|
||||
fail("toLangSymbol: wrong input kind " & $linkText.kind)
|
||||
assert linkText.kind in {rnRstRef, rnInner}
|
||||
|
||||
const NimDefs = ["proc", "func", "macro", "method", "iterator",
|
||||
"template", "converter", "const", "type", "var",
|
||||
"enum", "object", "tuple", "module"]
|
||||
"enum", "object", "tuple"]
|
||||
template resolveSymKind(x: string) =
|
||||
if x in ["enum", "object", "tuple"]:
|
||||
result.symKind = "type"
|
||||
@@ -124,11 +109,11 @@ proc toLangSymbol*(linkText: PRstNode): LangSymbol =
|
||||
template flushIdent() =
|
||||
if curIdent != "":
|
||||
case state
|
||||
of inBeginning: fail("incorrect state inBeginning")
|
||||
of inBeginning: doAssert false, "incorrect state inBeginning"
|
||||
of afterSymKind: resolveSymKind curIdent
|
||||
of beforeSymbolName: fail("incorrect state beforeSymbolName")
|
||||
of beforeSymbolName: doAssert false, "incorrect state beforeSymbolName"
|
||||
of atSymbolName: result.name = curIdent.nimIdentBackticksNormalize
|
||||
of afterSymbolName: fail("incorrect state afterSymbolName")
|
||||
of afterSymbolName: doAssert false, "incorrect state afterSymbolName"
|
||||
of genericsPar: result.generics = curIdent
|
||||
of parameterName: result.parameters.add (curIdent, "")
|
||||
of parameterType:
|
||||
|
||||
@@ -498,9 +498,6 @@ proc clikeNextToken(g: var GeneralTokenizer, keywords: openArray[string],
|
||||
of '\0':
|
||||
break
|
||||
else: inc(pos)
|
||||
else:
|
||||
g.kind = gtOperator
|
||||
while g.buf[pos] in OpChars: inc(pos)
|
||||
of '#':
|
||||
inc(pos)
|
||||
if hasPreprocessor in flags:
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
import
|
||||
os, strutils, rstast, dochelpers, std/enumutils, algorithm, lists, sequtils,
|
||||
std/private/miscdollars, tables, strscans, rstidx
|
||||
std/private/miscdollars, tables, strscans
|
||||
from highlite import SourceLanguage, getSourceLanguage
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
@@ -40,7 +40,7 @@ type
|
||||
roNimFile ## set for Nim files where default interpreted
|
||||
## text role should be :nim:
|
||||
roSandboxDisabled ## this option enables certain options
|
||||
## (e.g. raw, include, importdoc)
|
||||
## (e.g. raw, include)
|
||||
## which are disabled by default as they can
|
||||
## enable users to read arbitrary data and
|
||||
## perform XSS if the parser is used in a web
|
||||
@@ -73,17 +73,11 @@ type
|
||||
mwUnsupportedLanguage = "language '$1' not supported",
|
||||
mwUnsupportedField = "field '$1' not supported",
|
||||
mwRstStyle = "RST style: $1",
|
||||
mwUnusedImportdoc = "importdoc for '$1' is not used",
|
||||
meSandboxedDirective = "disabled directive: '$1'",
|
||||
|
||||
MsgHandler* = proc (filename: string, line, col: int, msgKind: MsgKind,
|
||||
arg: string) {.closure, gcsafe.} ## what to do in case of an error
|
||||
FindFileHandler* = proc (filename: string): string {.closure, gcsafe.}
|
||||
FindRefFileHandler* =
|
||||
proc (targetRelPath: string):
|
||||
tuple[targetPath: string, linkRelPath: string] {.closure, gcsafe.}
|
||||
## returns where .html or .idx file should be found by its relative path;
|
||||
## `linkRelPath` is a prefix to be added before a link anchor from such file
|
||||
|
||||
proc rstnodeToRefname*(n: PRstNode): string
|
||||
proc addNodes*(n: PRstNode): string
|
||||
@@ -339,8 +333,7 @@ type
|
||||
arInternalRst, ## For automatically generated RST anchors (from
|
||||
## headings, footnotes, inline internal targets):
|
||||
## case-insensitive, 1-space-significant (by RST spec)
|
||||
arExternalRst, ## For external .nim doc comments or .rst/.md
|
||||
arNim ## For anchors generated by ``docgen.nim``: Nim-style case
|
||||
arNim ## For anchors generated by ``docgen.rst``: Nim-style case
|
||||
## sensitivity, etc. (see `proc normalizeNimName`_ for details)
|
||||
arHyperlink, ## For links with manually set anchors in
|
||||
## form `text <pagename.html#anchor>`_
|
||||
@@ -356,15 +349,11 @@ type
|
||||
of arInternalRst:
|
||||
anchorType: RstAnchorKind
|
||||
target: PRstNode
|
||||
of arExternalRst:
|
||||
anchorTypeExt: RstAnchorKind
|
||||
refnameExt: string
|
||||
of arNim:
|
||||
tooltip: string # displayed tooltip for Nim-generated anchors
|
||||
langSym: LangSymbol
|
||||
refname: string # A reference name that will be inserted directly
|
||||
# into HTML/Latex.
|
||||
external: bool
|
||||
AnchorSubstTable = Table[string, seq[AnchorSubst]]
|
||||
# use `seq` to account for duplicate anchors
|
||||
FootnoteType = enum
|
||||
@@ -383,12 +372,6 @@ type
|
||||
RstFileTable* = object
|
||||
filenameToIdx*: Table[string, FileIndex]
|
||||
idxToFilename*: seq[string]
|
||||
ImportdocInfo = object
|
||||
used: bool # was this import used?
|
||||
fromInfo: TLineInfo # place of `.. importdoc::` directive
|
||||
idxPath: string # full path to ``.idx`` file
|
||||
linkRelPath: string # prefix before target anchor
|
||||
title: string # document title obtained from ``.idx``
|
||||
RstSharedState = object
|
||||
options*: RstParseOptions # parsing options
|
||||
hLevels: LevelMap # hierarchy of heading styles
|
||||
@@ -410,17 +393,12 @@ type
|
||||
footnotes: seq[FootnoteSubst] # correspondence b/w footnote label,
|
||||
# number, order of occurrence
|
||||
msgHandler: MsgHandler # How to handle errors.
|
||||
findFile: FindFileHandler # How to find files for include.
|
||||
findRefFile: FindRefFileHandler
|
||||
# How to find files imported by importdoc.
|
||||
findFile: FindFileHandler # How to find files.
|
||||
filenames*: RstFileTable # map file name <-> FileIndex (for storing
|
||||
# file names for warnings after 1st stage)
|
||||
currFileIdx*: FileIndex # current index in `filenames`
|
||||
tocPart*: seq[PRstNode] # all the headings of a document
|
||||
hasToc*: bool
|
||||
idxImports*: Table[string, ImportdocInfo]
|
||||
# map `importdoc`ed filename -> it's info
|
||||
nimFileImported*: bool # Was any ``.nim`` module `importdoc`ed ?
|
||||
|
||||
PRstSharedState* = ref RstSharedState
|
||||
ManualAnchor = object
|
||||
@@ -474,9 +452,6 @@ proc defaultFindFile*(filename: string): string =
|
||||
if fileExists(filename): result = filename
|
||||
else: result = ""
|
||||
|
||||
proc defaultFindRefFile*(filename: string): (string, string) =
|
||||
(filename, "")
|
||||
|
||||
proc defaultRole(options: RstParseOptions): string =
|
||||
if roNimFile in options: "nim" else: "literal"
|
||||
|
||||
@@ -517,16 +492,12 @@ proc getFilename(filenames: RstFileTable, fid: FileIndex): string =
|
||||
$fid.int, $(filenames.len - 1)])
|
||||
result = filenames.idxToFilename[fid.int]
|
||||
|
||||
proc getFilename(s: PRstSharedState, subst: AnchorSubst): string =
|
||||
getFilename(s.filenames, subst.info.fileIndex)
|
||||
|
||||
proc currFilename(s: PRstSharedState): string =
|
||||
getFilename(s.filenames, s.currFileIdx)
|
||||
|
||||
proc newRstSharedState*(options: RstParseOptions,
|
||||
filename: string,
|
||||
findFile: FindFileHandler,
|
||||
findRefFile: FindRefFileHandler,
|
||||
msgHandler: MsgHandler,
|
||||
hasToc: bool): PRstSharedState =
|
||||
let r = defaultRole(options)
|
||||
@@ -536,9 +507,6 @@ proc newRstSharedState*(options: RstParseOptions,
|
||||
options: options,
|
||||
msgHandler: if not isNil(msgHandler): msgHandler else: defaultMsgHandler,
|
||||
findFile: if not isNil(findFile): findFile else: defaultFindFile,
|
||||
findRefFile:
|
||||
if not isNil(findRefFile): findRefFile
|
||||
else: defaultFindRefFile,
|
||||
hasToc: hasToc
|
||||
)
|
||||
setCurrFilename(result, filename)
|
||||
@@ -557,14 +525,6 @@ proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string) =
|
||||
proc rstMessage(s: PRstSharedState, msgKind: MsgKind, arg: string) =
|
||||
s.msgHandler(s.currFilename, LineRstInit, ColRstInit, msgKind, arg)
|
||||
|
||||
proc rstMessage(s: PRstSharedState, msgKind: MsgKind, arg: string;
|
||||
line, col: int) =
|
||||
s.msgHandler(s.currFilename, line, col, msgKind, arg)
|
||||
|
||||
proc rstMessage(s: PRstSharedState, filename: string, msgKind: MsgKind,
|
||||
arg: string) =
|
||||
s.msgHandler(filename, LineRstInit, ColRstInit, msgKind, arg)
|
||||
|
||||
proc rstMessage*(filenames: RstFileTable, f: MsgHandler,
|
||||
info: TLineInfo, msgKind: MsgKind, arg: string) =
|
||||
## Print warnings using `info`, i.e. in 2nd-pass warnings for
|
||||
@@ -796,14 +756,6 @@ proc internalRefPriority(k: RstAnchorKind): int =
|
||||
of footnoteAnchor: result = 4
|
||||
of headlineAnchor: result = 3
|
||||
|
||||
proc `$`(subst: AnchorSubst): string = # for debug
|
||||
let s =
|
||||
case subst.kind
|
||||
of arInternalRst: "type=" & $subst.anchorType
|
||||
of arExternalRst: "type=" & $subst.anchorTypeExt
|
||||
of arNim: "langsym=" & $subst.langSym
|
||||
result = "(kind=$1, priority=$2, $3)" % [$subst.kind, $subst.priority, s]
|
||||
|
||||
proc addAnchorRst(p: var RstParser, name: string, target: PRstNode,
|
||||
anchorType: RstAnchorKind) =
|
||||
## Associates node `target` (which has field `anchor`) with an
|
||||
@@ -819,49 +771,31 @@ proc addAnchorRst(p: var RstParser, name: string, target: PRstNode,
|
||||
info: prevLineInfo(p), anchorType: anchorType))
|
||||
p.curAnchors.setLen 0
|
||||
|
||||
proc addAnchorExtRst(s: var PRstSharedState, key: string, refn: string,
|
||||
anchorType: RstAnchorKind, info: TLineInfo) =
|
||||
let name = key.toLowerAscii
|
||||
let prio = internalRefPriority(anchorType)
|
||||
s.anchors.mgetOrPut(name, newSeq[AnchorSubst]()).add(
|
||||
AnchorSubst(kind: arExternalRst, refnameExt: refn, priority: prio,
|
||||
info: info,
|
||||
anchorTypeExt: anchorType))
|
||||
|
||||
proc addAnchorNim*(s: var PRstSharedState, external: bool, refn: string, tooltip: string,
|
||||
proc addAnchorNim*(s: var PRstSharedState, refn: string, tooltip: string,
|
||||
langSym: LangSymbol, priority: int,
|
||||
info: TLineInfo) =
|
||||
## Adds an anchor `refn`, which follows
|
||||
## the rule `arNim` (i.e. a symbol in ``*.nim`` file)
|
||||
s.anchors.mgetOrPut(langSym.name, newSeq[AnchorSubst]()).add(
|
||||
AnchorSubst(kind: arNim, external: external, refname: refn, langSym: langSym,
|
||||
AnchorSubst(kind: arNim, refname: refn, langSym: langSym,
|
||||
tooltip: tooltip, priority: priority,
|
||||
info: info))
|
||||
|
||||
proc findMainAnchorNim(s: PRstSharedState, signature: PRstNode,
|
||||
info: TLineInfo):
|
||||
seq[AnchorSubst] =
|
||||
var langSym: LangSymbol
|
||||
try:
|
||||
langSym = toLangSymbol(signature)
|
||||
except ValueError: # parsing failed, not a Nim symbol
|
||||
return
|
||||
let langSym = toLangSymbol(signature)
|
||||
let substitutions = s.anchors.getOrDefault(langSym.name,
|
||||
newSeq[AnchorSubst]())
|
||||
if substitutions.len == 0:
|
||||
return
|
||||
# logic to select only groups instead of concrete symbols
|
||||
# with overloads, note that the same symbol can be defined
|
||||
# in multiple modules and `importdoc`ed:
|
||||
type GroupKey = tuple[symKind: string, origModule: string]
|
||||
# map (symKind, file) (like "proc", "os.nim") -> found symbols/groups:
|
||||
var found: Table[GroupKey, seq[AnchorSubst]]
|
||||
for subst in substitutions:
|
||||
if subst.kind == arNim:
|
||||
if match(subst.langSym, langSym):
|
||||
let key: GroupKey = (subst.langSym.symKind, getFilename(s, subst))
|
||||
found.mgetOrPut(key, newSeq[AnchorSubst]()).add subst
|
||||
for key, sList in found:
|
||||
# map symKind (like "proc") -> found symbols/groups:
|
||||
var found: Table[string, seq[AnchorSubst]]
|
||||
for s in substitutions:
|
||||
if s.kind == arNim:
|
||||
if match(s.langSym, langSym):
|
||||
found.mgetOrPut(s.langSym.symKind, newSeq[AnchorSubst]()).add s
|
||||
for symKind, sList in found:
|
||||
if sList.len == 1:
|
||||
result.add sList[0]
|
||||
else: # > 1, there are overloads, potential ambiguity in this `symKind`
|
||||
@@ -878,16 +812,14 @@ proc findMainAnchorNim(s: PRstSharedState, signature: PRstNode,
|
||||
result.add s
|
||||
foundGroup = true
|
||||
break
|
||||
doAssert(foundGroup,
|
||||
"docgen has not generated the group for $1 (file $2)" % [
|
||||
langSym.name, getFilename(s, sList[0]) ])
|
||||
doAssert foundGroup, "docgen has not generated the group"
|
||||
|
||||
proc findMainAnchorRst(s: PRstSharedState, linkText: string, info: TLineInfo):
|
||||
seq[AnchorSubst] =
|
||||
let name = linkText.toLowerAscii
|
||||
let substitutions = s.anchors.getOrDefault(name, newSeq[AnchorSubst]())
|
||||
for s in substitutions:
|
||||
if s.kind in {arInternalRst, arExternalRst}:
|
||||
if s.kind == arInternalRst:
|
||||
result.add s
|
||||
|
||||
proc addFootnoteNumManual(p: var RstParser, num: int) =
|
||||
@@ -1678,7 +1610,7 @@ proc getFootnoteType(label: PRstNode): (FootnoteType, int) =
|
||||
elif label.len == 1 and label.sons[0].kind == rnLeaf:
|
||||
try:
|
||||
result = (fnManualNumber, parseInt(label.sons[0].text))
|
||||
except ValueError:
|
||||
except:
|
||||
result = (fnCitation, -1)
|
||||
else:
|
||||
result = (fnCitation, -1)
|
||||
@@ -2967,13 +2899,13 @@ proc parseEnumList(p: var RstParser): PRstNode =
|
||||
let enumerator = p.tok[p.idx + 1 + wildIndex[w]].symbol
|
||||
# check that it's in sequence: enumerator == next(prevEnum)
|
||||
if "n" in wildcards[w]: # arabic numeral
|
||||
let prevEnumI = try: parseInt(prevEnum) except ValueError: 1
|
||||
let prevEnumI = try: parseInt(prevEnum) except: 1
|
||||
if enumerator in autoEnums:
|
||||
if prevAE != "" and enumerator != prevAE:
|
||||
break
|
||||
prevAE = enumerator
|
||||
curEnum = prevEnumI + 1
|
||||
else: curEnum = (try: parseInt(enumerator) except ValueError: 1)
|
||||
else: curEnum = (try: parseInt(enumerator) except: 1)
|
||||
if curEnum - prevEnumI != 1:
|
||||
break
|
||||
prevEnum = enumerator
|
||||
@@ -3319,15 +3251,6 @@ proc dirRaw(p: var RstParser): PRstNode =
|
||||
else:
|
||||
dirRawAux(p, result, rnRaw, parseSectionWrapper)
|
||||
|
||||
proc dirImportdoc(p: var RstParser): PRstNode =
|
||||
result = parseDirective(p, rnDirective, {}, parseLiteralBlock)
|
||||
assert result.sons[2].kind == rnLiteralBlock
|
||||
assert result.sons[2].sons[0].kind == rnLeaf
|
||||
let filenames: seq[string] = split(result.sons[2].sons[0].text, seps = {','})
|
||||
proc rmSpaces(s: string): string = s.split.join("")
|
||||
for origFilename in filenames:
|
||||
p.s.idxImports[origFilename.rmSpaces] = ImportdocInfo(fromInfo: lineInfo(p))
|
||||
|
||||
proc selectDir(p: var RstParser, d: string): PRstNode =
|
||||
result = nil
|
||||
let tok = p.tok[p.idx-2] # report on directive in ".. directive::"
|
||||
@@ -3348,7 +3271,6 @@ proc selectDir(p: var RstParser, d: string): PRstNode =
|
||||
of "hint": result = dirAdmonition(p, d)
|
||||
of "image": result = dirImage(p)
|
||||
of "important": result = dirAdmonition(p, d)
|
||||
of "importdoc": result = dirImportdoc(p)
|
||||
of "include": result = dirInclude(p)
|
||||
of "index": result = dirIndex(p)
|
||||
of "note": result = dirAdmonition(p, d)
|
||||
@@ -3479,90 +3401,11 @@ proc rstParsePass1*(fragment: string,
|
||||
getTokens(fragment, p.tok)
|
||||
result = parseDoc(p)
|
||||
|
||||
proc extractLinkEnd(x: string): string =
|
||||
## From links like `path/to/file.html#/%` extract `file.html#/%`.
|
||||
let i = find(x, '#')
|
||||
let last =
|
||||
if i >= 0: i
|
||||
else: x.len - 1
|
||||
let j = rfind(x, '/', start=0, last=last)
|
||||
if j >= 0:
|
||||
result = x[j+1 .. ^1]
|
||||
else:
|
||||
result = x
|
||||
|
||||
proc loadIdxFile(s: var PRstSharedState, origFilename: string) =
|
||||
doAssert roSandboxDisabled in s.options
|
||||
var info: TLineInfo
|
||||
info.fileIndex = addFilename(s, origFilename)
|
||||
var (dir, basename, ext) = origFilename.splitFile
|
||||
if ext notin [".md", ".rst", ".nim", ""]:
|
||||
rstMessage(s.filenames, s.msgHandler, s.idxImports[origFilename].fromInfo,
|
||||
meCannotOpenFile, origFilename & ": unknown extension")
|
||||
let idxFilename = dir / basename & ".idx"
|
||||
let (idxPath, linkRelPath) = s.findRefFile(idxFilename)
|
||||
s.idxImports[origFilename].linkRelPath = linkRelPath
|
||||
var
|
||||
fileEntries: seq[IndexEntry]
|
||||
title: IndexEntry
|
||||
try:
|
||||
(fileEntries, title) = parseIdxFile(idxPath)
|
||||
except IOError:
|
||||
rstMessage(s.filenames, s.msgHandler, s.idxImports[origFilename].fromInfo,
|
||||
meCannotOpenFile, idxPath)
|
||||
except ValueError as e:
|
||||
s.msgHandler(idxPath, LineRstInit, ColRstInit, meInvalidField, e.msg)
|
||||
|
||||
var isMarkup = false # for sanity check to avoid mixing .md <-> .nim
|
||||
for entry in fileEntries:
|
||||
# Though target .idx already has inside it the path to HTML relative
|
||||
# project's root, we won't rely on it and use `linkRelPath` instead.
|
||||
let refn = extractLinkEnd(entry.link)
|
||||
# select either markup (rst/md) or Nim cases:
|
||||
if entry.kind in {ieMarkupTitle, ieNimTitle}:
|
||||
s.idxImports[origFilename].title = entry.keyword
|
||||
case entry.kind
|
||||
of ieIdxRole, ieHeading, ieMarkupTitle:
|
||||
if ext == ".nim" and entry.kind == ieMarkupTitle:
|
||||
rstMessage(s, idxPath, meInvalidField,
|
||||
$ieMarkupTitle & " in supposedly .nim-derived file")
|
||||
if entry.kind == ieMarkupTitle:
|
||||
isMarkup = true
|
||||
info.line = entry.line.uint16
|
||||
addAnchorExtRst(s, key = entry.keyword, refn = refn,
|
||||
anchorType = headlineAnchor, info=info)
|
||||
of ieNim, ieNimGroup, ieNimTitle:
|
||||
if ext in [".md", ".rst"] or isMarkup:
|
||||
rstMessage(s, idxPath, meInvalidField,
|
||||
$entry.kind & " in supposedly markup-derived file")
|
||||
s.nimFileImported = true
|
||||
var langSym: LangSymbol
|
||||
if entry.kind in {ieNim, ieNimTitle}:
|
||||
var q: RstParser
|
||||
initParser(q, s)
|
||||
info.line = entry.line.uint16
|
||||
setLen(q.tok, 0)
|
||||
q.idx = 0
|
||||
getTokens(entry.linkTitle, q.tok)
|
||||
var sons = newSeq[PRstNode](q.tok.len)
|
||||
for i in 0 ..< q.tok.len: sons[i] = newLeaf(q.tok[i].symbol)
|
||||
let linkTitle = newRstNode(rnInner, sons)
|
||||
langSym = linkTitle.toLangSymbol
|
||||
else: # entry.kind == ieNimGroup
|
||||
langSym = langSymbolGroup(kind=entry.linkTitle, name=entry.keyword)
|
||||
addAnchorNim(s, external = true, refn = refn, tooltip = entry.linkDesc,
|
||||
langSym = langSym, priority = -4, # lowest
|
||||
info=info)
|
||||
doAssert s.idxImports[origFilename].title != ""
|
||||
|
||||
proc preparePass2*(s: var PRstSharedState, mainNode: PRstNode, importdoc = true) =
|
||||
proc preparePass2*(s: PRstSharedState, mainNode: PRstNode) =
|
||||
## Records titles in node `mainNode` and orders footnotes.
|
||||
countTitles(s, mainNode)
|
||||
fixHeadlines(s)
|
||||
orderFootnotes(s)
|
||||
if importdoc:
|
||||
for origFilename in s.idxImports.keys:
|
||||
loadIdxFile(s, origFilename)
|
||||
|
||||
proc resolveLink(s: PRstSharedState, n: PRstNode) : PRstNode =
|
||||
# Associate this link alias with its target and change node kind to
|
||||
@@ -3580,9 +3423,6 @@ proc resolveLink(s: PRstSharedState, n: PRstNode) : PRstNode =
|
||||
tooltip: string
|
||||
target: PRstNode
|
||||
info: TLineInfo
|
||||
externFilename: string
|
||||
# when external anchor: origin filename where anchor was defined
|
||||
isTitle: bool
|
||||
proc cmp(x, y: LinkDef): int =
|
||||
result = cmp(x.priority, y.priority)
|
||||
if result == 0:
|
||||
@@ -3595,67 +3435,26 @@ proc resolveLink(s: PRstSharedState, n: PRstNode) : PRstNode =
|
||||
target: y.value, info: y.info,
|
||||
tooltip: "(" & $y.kind & ")")
|
||||
let substRst = findMainAnchorRst(s, alias.addNodes, n.info)
|
||||
template getExternFilename(subst: AnchorSubst): string =
|
||||
if subst.kind == arExternalRst or
|
||||
(subst.kind == arNim and subst.external):
|
||||
getFilename(s, subst)
|
||||
else: ""
|
||||
for subst in substRst:
|
||||
var refname, fullRefname: string
|
||||
if subst.kind == arInternalRst:
|
||||
refname = subst.target.anchor
|
||||
fullRefname = refname
|
||||
else: # arExternalRst
|
||||
refname = subst.refnameExt
|
||||
fullRefname = s.idxImports[getFilename(s, subst)].linkRelPath &
|
||||
"/" & refname
|
||||
let anchorType =
|
||||
if subst.kind == arInternalRst: subst.anchorType
|
||||
else: subst.anchorTypeExt # arExternalRst
|
||||
foundLinks.add LinkDef(ar: subst.kind, priority: subst.priority,
|
||||
target: newLeaf(fullRefname),
|
||||
foundLinks.add LinkDef(ar: arInternalRst, priority: subst.priority,
|
||||
target: newLeaf(subst.target.anchor),
|
||||
info: subst.info,
|
||||
externFilename: getExternFilename(subst),
|
||||
isTitle: isDocumentationTitle(refname),
|
||||
tooltip: "(" & $anchorType & ")")
|
||||
tooltip: "(" & $subst.anchorType & ")")
|
||||
# find anchors automatically generated from Nim symbols
|
||||
if roNimFile in s.options or s.nimFileImported:
|
||||
if roNimFile in s.options:
|
||||
let substNim = findMainAnchorNim(s, signature=alias, n.info)
|
||||
for subst in substNim:
|
||||
let fullRefname =
|
||||
if subst.external:
|
||||
s.idxImports[getFilename(s, subst)].linkRelPath &
|
||||
"/" & subst.refname
|
||||
else: subst.refname
|
||||
foundLinks.add LinkDef(ar: subst.kind, priority: subst.priority,
|
||||
target: newLeaf(fullRefname),
|
||||
externFilename: getExternFilename(subst),
|
||||
isTitle: isDocumentationTitle(subst.refname),
|
||||
foundLinks.add LinkDef(ar: arNim, priority: subst.priority,
|
||||
target: newLeaf(subst.refname),
|
||||
info: subst.info, tooltip: subst.tooltip)
|
||||
foundLinks.sort(cmp = cmp, order = Descending)
|
||||
let aliasStr = addNodes(alias)
|
||||
if foundLinks.len >= 1:
|
||||
if foundLinks[0].externFilename != "":
|
||||
s.idxImports[foundLinks[0].externFilename].used = true
|
||||
let kind = if foundLinks[0].ar in {arHyperlink, arExternalRst}: rnHyperlink
|
||||
elif foundLinks[0].ar == arNim:
|
||||
if foundLinks[0].externFilename == "": rnNimdocRef
|
||||
else: rnHyperlink
|
||||
let kind = if foundLinks[0].ar == arHyperlink: rnHyperlink
|
||||
elif foundLinks[0].ar == arNim: rnNimdocRef
|
||||
else: rnInternalRef
|
||||
result = newRstNode(kind)
|
||||
let documentName = # filename without ext for `.nim`, title for `.md`
|
||||
if foundLinks[0].ar == arNim:
|
||||
changeFileExt(foundLinks[0].externFilename.extractFilename, "")
|
||||
elif foundLinks[0].externFilename != "":
|
||||
s.idxImports[foundLinks[0].externFilename].title
|
||||
else: foundLinks[0].externFilename.extractFilename
|
||||
let linkText =
|
||||
if foundLinks[0].externFilename != "":
|
||||
if foundLinks[0].isTitle: newLeaf(addNodes(desc))
|
||||
else: newLeaf(documentName & ": " & addNodes(desc))
|
||||
else:
|
||||
newRstNode(rnInner, desc.sons)
|
||||
result.sons = @[linkText, foundLinks[0].target]
|
||||
result.sons = @[newRstNode(rnInner, desc.sons), foundLinks[0].target]
|
||||
if kind == rnNimdocRef: result.tooltip = foundLinks[0].tooltip
|
||||
if foundLinks.len > 1: # report ambiguous link
|
||||
var targets = newSeq[string]()
|
||||
@@ -3769,28 +3568,20 @@ proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode =
|
||||
inc i
|
||||
result.sons = newSons
|
||||
|
||||
proc completePass2*(s: PRstSharedState) =
|
||||
for (filename, importdocInfo) in s.idxImports.pairs:
|
||||
if not importdocInfo.used:
|
||||
rstMessage(s.filenames, s.msgHandler, importdocInfo.fromInfo,
|
||||
mwUnusedImportdoc, filename)
|
||||
|
||||
proc rstParse*(text, filename: string,
|
||||
line, column: int,
|
||||
options: RstParseOptions,
|
||||
findFile: FindFileHandler = nil,
|
||||
findRefFile: FindRefFileHandler = nil,
|
||||
msgHandler: MsgHandler = nil):
|
||||
tuple[node: PRstNode, filenames: RstFileTable, hasToc: bool] =
|
||||
## Parses the whole `text`. The result is ready for `rstgen.renderRstToOut`,
|
||||
## note that 2nd tuple element should be fed to `initRstGenerator`
|
||||
## argument `filenames` (it is being filled here at least with `filename`
|
||||
## and possibly with other files from RST ``.. include::`` statement).
|
||||
var sharedState = newRstSharedState(options, filename, findFile, findRefFile,
|
||||
var sharedState = newRstSharedState(options, filename, findFile,
|
||||
msgHandler, hasToc=false)
|
||||
let unresolved = rstParsePass1(text, line, column, sharedState)
|
||||
preparePass2(sharedState, unresolved)
|
||||
result.node = resolveSubs(sharedState, unresolved)
|
||||
completePass2(sharedState)
|
||||
result.filenames = sharedState.filenames
|
||||
result.hasToc = sharedState.hasToc
|
||||
|
||||
@@ -39,8 +39,7 @@
|
||||
## No backreferences are generated since finding all references of a footnote
|
||||
## can be done by simply searching for ``[footnoteName]``.
|
||||
|
||||
import strutils, os, hashes, strtabs, rstast, rst, rstidx,
|
||||
highlite, tables, sequtils,
|
||||
import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils,
|
||||
algorithm, parseutils, std/strbasics
|
||||
|
||||
|
||||
@@ -60,7 +59,7 @@ type
|
||||
outLatex # output is Latex
|
||||
|
||||
MetaEnum* = enum
|
||||
metaNone, metaTitleRaw, metaTitle, metaSubtitle, metaAuthor, metaVersion
|
||||
metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
|
||||
|
||||
EscapeMode* = enum # in Latex text inside options [] and URLs is
|
||||
# escaped slightly differently than in normal text
|
||||
@@ -322,8 +321,31 @@ proc renderAux(d: PDoc, n: PRstNode, html, tex: string, result: var string) =
|
||||
|
||||
# ---------------- index handling --------------------------------------------
|
||||
|
||||
proc setIndexTerm*(d: var RstGenerator; k: IndexEntryKind, htmlFile, id, term: string,
|
||||
linkTitle, linkDesc = "", line = 0) =
|
||||
proc quoteIndexColumn(text: string): string =
|
||||
## Returns a safe version of `text` for serialization to the ``.idx`` file.
|
||||
##
|
||||
## The returned version can be put without worries in a line based tab
|
||||
## separated column text file. The following character sequence replacements
|
||||
## will be performed for that goal:
|
||||
##
|
||||
## * ``"\\"`` => ``"\\\\"``
|
||||
## * ``"\n"`` => ``"\\n"``
|
||||
## * ``"\t"`` => ``"\\t"``
|
||||
result = newStringOfCap(text.len + 3)
|
||||
for c in text:
|
||||
case c
|
||||
of '\\': result.add "\\"
|
||||
of '\L': result.add "\\n"
|
||||
of '\C': discard
|
||||
of '\t': result.add "\\t"
|
||||
else: result.add c
|
||||
|
||||
proc unquoteIndexColumn(text: string): string =
|
||||
## Returns the unquoted version generated by ``quoteIndexColumn``.
|
||||
result = text.multiReplace(("\\t", "\t"), ("\\n", "\n"), ("\\\\", "\\"))
|
||||
|
||||
proc setIndexTerm*(d: var RstGenerator, htmlFile, id, term: string,
|
||||
linkTitle, linkDesc = "") =
|
||||
## Adds a `term` to the index using the specified hyperlink identifier.
|
||||
##
|
||||
## A new entry will be added to the index using the format
|
||||
@@ -346,8 +368,21 @@ proc setIndexTerm*(d: var RstGenerator; k: IndexEntryKind, htmlFile, id, term: s
|
||||
## <#writeIndexFile,RstGenerator,string>`_. The purpose of the index is
|
||||
## documented in the `docgen tools guide
|
||||
## <docgen.html#related-options-index-switch>`_.
|
||||
let (entry, isTitle) = formatIndexEntry(k, htmlFile, id, term,
|
||||
linkTitle, linkDesc, line)
|
||||
var
|
||||
entry = term
|
||||
isTitle = false
|
||||
entry.add('\t')
|
||||
entry.add(htmlFile)
|
||||
if id.len > 0:
|
||||
entry.add('#')
|
||||
entry.add(id)
|
||||
else:
|
||||
isTitle = true
|
||||
if linkTitle.len > 0 or linkDesc.len > 0:
|
||||
entry.add('\t' & linkTitle.quoteIndexColumn)
|
||||
entry.add('\t' & linkDesc.quoteIndexColumn)
|
||||
entry.add("\n")
|
||||
|
||||
if isTitle: d.theIndex.insert(entry)
|
||||
else: d.theIndex.add(entry)
|
||||
|
||||
@@ -360,15 +395,6 @@ proc hash(n: PRstNode): int =
|
||||
result = result !& hash(n.sons[i])
|
||||
result = !$result
|
||||
|
||||
proc htmlFileRelPath(d: PDoc): string =
|
||||
if d.outDir.len == 0:
|
||||
# /foo/bar/zoo.nim -> zoo.html
|
||||
changeFileExt(extractFilename(d.filename), HtmlExt)
|
||||
else: # d is initialized in docgen.nim
|
||||
# outDir = /foo -\
|
||||
# destFile = /foo/bar/zoo.html -|-> bar/zoo.html
|
||||
d.destFile.relativePath(d.outDir, '/')
|
||||
|
||||
proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
|
||||
## Renders the string decorated within \`foobar\`\:idx\: markers.
|
||||
##
|
||||
@@ -385,12 +411,17 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
|
||||
|
||||
var term = ""
|
||||
renderAux(d, n, term)
|
||||
setIndexTerm(d, ieIdxRole,
|
||||
htmlFileRelPath(d), id, term, d.currentSection)
|
||||
setIndexTerm(d, changeFileExt(extractFilename(d.filename), HtmlExt), id, term, d.currentSection)
|
||||
dispA(d.target, result, "<span id=\"$1\">$2</span>", "\\nimindexterm{$1}{$2}",
|
||||
[id, term])
|
||||
|
||||
type
|
||||
IndexEntry* = object
|
||||
keyword*: string
|
||||
link*: string
|
||||
linkTitle*: string ## contains a prettier text for the href
|
||||
linkDesc*: string ## the title attribute of the final href
|
||||
|
||||
IndexedDocs* = Table[IndexEntry, seq[IndexEntry]] ## \
|
||||
## Contains the index sequences for doc types.
|
||||
##
|
||||
@@ -401,6 +432,21 @@ type
|
||||
## The value indexed by this IndexEntry is a sequence with the real index
|
||||
## entries found in the ``.idx`` file.
|
||||
|
||||
proc cmp(a, b: IndexEntry): int =
|
||||
## Sorts two ``IndexEntry`` first by `keyword` field, then by `link`.
|
||||
result = cmpIgnoreStyle(a.keyword, b.keyword)
|
||||
if result == 0:
|
||||
result = cmpIgnoreStyle(a.link, b.link)
|
||||
|
||||
proc hash(x: IndexEntry): Hash =
|
||||
## Returns the hash for the combined fields of the type.
|
||||
##
|
||||
## The hash is computed as the chained hash of the individual string hashes.
|
||||
result = x.keyword.hash !& x.link.hash
|
||||
result = result !& x.linkTitle.hash
|
||||
result = result !& x.linkDesc.hash
|
||||
result = !$result
|
||||
|
||||
when defined(gcDestructors):
|
||||
template `<-`(a, b: var IndexEntry) = a = move(b)
|
||||
else:
|
||||
@@ -409,7 +455,6 @@ else:
|
||||
shallowCopy a.link, b.link
|
||||
shallowCopy a.linkTitle, b.linkTitle
|
||||
shallowCopy a.linkDesc, b.linkDesc
|
||||
shallowCopy a.module, b.module
|
||||
|
||||
proc sortIndex(a: var openArray[IndexEntry]) =
|
||||
# we use shellsort here; fast and simple
|
||||
@@ -449,20 +494,16 @@ proc generateSymbolIndex(symbols: seq[IndexEntry]): string =
|
||||
result = "<dl>"
|
||||
var i = 0
|
||||
while i < symbols.len:
|
||||
let keyword = esc(outHtml, symbols[i].keyword)
|
||||
let keyword = symbols[i].keyword
|
||||
let cleanedKeyword = keyword.escapeLink
|
||||
result.addf("<dt><a name=\"$2\" href=\"#$2\"><span>$1:</span></a></dt><dd><ul class=\"simple\">\n",
|
||||
[keyword, cleanedKeyword])
|
||||
var j = i
|
||||
while j < symbols.len and symbols[i].keyword == symbols[j].keyword:
|
||||
while j < symbols.len and keyword == symbols[j].keyword:
|
||||
let
|
||||
url = symbols[j].link.escapeLink
|
||||
module = symbols[j].module
|
||||
text =
|
||||
if symbols[j].linkTitle.len > 0:
|
||||
esc(outHtml, module & ": " & symbols[j].linkTitle)
|
||||
else: url
|
||||
desc = symbols[j].linkDesc
|
||||
text = if symbols[j].linkTitle.len > 0: symbols[j].linkTitle else: url
|
||||
desc = if symbols[j].linkDesc.len > 0: symbols[j].linkDesc else: ""
|
||||
if desc.len > 0:
|
||||
result.addf("""<li><a class="reference external"
|
||||
title="$3" data-doc-search-tag="$2" href="$1">$2</a></li>
|
||||
@@ -476,6 +517,13 @@ proc generateSymbolIndex(symbols: seq[IndexEntry]): string =
|
||||
i = j
|
||||
result.add("</dl>")
|
||||
|
||||
proc isDocumentationTitle(hyperlink: string): bool =
|
||||
## Returns true if the hyperlink is actually a documentation title.
|
||||
##
|
||||
## Documentation titles lack the hash. See `mergeIndexes()
|
||||
## <#mergeIndexes,string>`_ for a more detailed explanation.
|
||||
result = hyperlink.find('#') < 0
|
||||
|
||||
proc stripTocLevel(s: string): tuple[level: int, text: string] =
|
||||
## Returns the *level* of the toc along with the text without it.
|
||||
for c in 0 ..< s.len:
|
||||
@@ -509,15 +557,17 @@ proc generateDocumentationToc(entries: seq[IndexEntry]): string =
|
||||
level = 1
|
||||
levels.newSeq(entries.len)
|
||||
for entry in entries:
|
||||
let (rawLevel, rawText) = stripTocLevel(entry.linkTitle)
|
||||
let (rawLevel, rawText) = stripTocLevel(entry.linkTitle or entry.keyword)
|
||||
if rawLevel < 1:
|
||||
# This is a normal symbol, push it *inside* one level from the last one.
|
||||
levels[L].level = level + 1
|
||||
# Also, ignore the linkTitle and use directly the keyword.
|
||||
levels[L].text = entry.keyword
|
||||
else:
|
||||
# The level did change, update the level indicator.
|
||||
level = rawLevel
|
||||
levels[L].level = rawLevel
|
||||
levels[L].text = rawText
|
||||
levels[L].text = rawText
|
||||
inc L
|
||||
|
||||
# Now generate hierarchical lists based on the precalculated levels.
|
||||
@@ -548,7 +598,7 @@ proc generateDocumentationIndex(docs: IndexedDocs): string =
|
||||
for title in titles:
|
||||
let tocList = generateDocumentationToc(docs.getOrDefault(title))
|
||||
result.add("<ul><li><a href=\"" &
|
||||
title.link & "\">" & title.linkTitle & "</a>\n" & tocList & "</li></ul>\n")
|
||||
title.link & "\">" & title.keyword & "</a>\n" & tocList & "</li></ul>\n")
|
||||
|
||||
proc generateDocumentationJumps(docs: IndexedDocs): string =
|
||||
## Returns a plain list of hyperlinks to documentation TOCs in HTML.
|
||||
@@ -560,7 +610,7 @@ proc generateDocumentationJumps(docs: IndexedDocs): string =
|
||||
|
||||
var chunks: seq[string] = @[]
|
||||
for title in titles:
|
||||
chunks.add("<a href=\"" & title.link & "\">" & title.linkTitle & "</a>")
|
||||
chunks.add("<a href=\"" & title.link & "\">" & title.keyword & "</a>")
|
||||
|
||||
result.add(chunks.join(", ") & ".<br/>")
|
||||
|
||||
@@ -589,11 +639,39 @@ proc readIndexDir*(dir: string):
|
||||
# Scan index files and build the list of symbols.
|
||||
for path in walkDirRec(dir):
|
||||
if path.endsWith(IndexExt):
|
||||
var (fileEntries, title) = parseIdxFile(path)
|
||||
var
|
||||
fileEntries: seq[IndexEntry]
|
||||
title: IndexEntry
|
||||
f = 0
|
||||
newSeq(fileEntries, 500)
|
||||
setLen(fileEntries, 0)
|
||||
for line in lines(path):
|
||||
let s = line.find('\t')
|
||||
if s < 0: continue
|
||||
setLen(fileEntries, f+1)
|
||||
fileEntries[f].keyword = line.substr(0, s-1)
|
||||
fileEntries[f].link = line.substr(s+1)
|
||||
# See if we detect a title, a link without a `#foobar` trailing part.
|
||||
if title.keyword.len == 0 and fileEntries[f].link.isDocumentationTitle:
|
||||
title.keyword = fileEntries[f].keyword
|
||||
title.link = fileEntries[f].link
|
||||
|
||||
if fileEntries[f].link.find('\t') > 0:
|
||||
let extraCols = fileEntries[f].link.split('\t')
|
||||
fileEntries[f].link = extraCols[0]
|
||||
assert extraCols.len == 3
|
||||
fileEntries[f].linkTitle = extraCols[1].unquoteIndexColumn
|
||||
fileEntries[f].linkDesc = extraCols[2].unquoteIndexColumn
|
||||
else:
|
||||
fileEntries[f].linkTitle = ""
|
||||
fileEntries[f].linkDesc = ""
|
||||
inc f
|
||||
# Depending on type add this to the list of symbols or table of APIs.
|
||||
if title.kind == ieNimTitle:
|
||||
for i in 0 ..< fileEntries.len:
|
||||
if fileEntries[i].kind != ieNim:
|
||||
if title.keyword.len == 0:
|
||||
for i in 0 ..< f:
|
||||
# Don't add to symbols TOC entries (they start with a whitespace).
|
||||
let toc = fileEntries[i].linkTitle
|
||||
if toc.len > 0 and toc[0] == ' ':
|
||||
continue
|
||||
# Ok, non TOC entry, add it.
|
||||
setLen(result.symbols, L + 1)
|
||||
@@ -609,7 +687,7 @@ proc readIndexDir*(dir: string):
|
||||
result.modules.add(x.changeFileExt(""))
|
||||
else:
|
||||
# Generate the symbolic anchor for index quickjumps.
|
||||
title.aux = "doc_toc_" & $result.docs.len
|
||||
title.linkTitle = "doc_toc_" & $result.docs.len
|
||||
result.docs[title] = fileEntries
|
||||
|
||||
proc mergeIndexes*(dir: string): string =
|
||||
@@ -669,6 +747,24 @@ proc mergeIndexes*(dir: string): string =
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
proc stripTocHtml(s: string): string =
|
||||
## Ugly quick hack to remove HTML tags from TOC titles.
|
||||
##
|
||||
## A TocEntry.header field already contains rendered HTML tags. Instead of
|
||||
## implementing a proper version of renderRstToOut() which recursively
|
||||
## renders an rst tree to plain text, we simply remove text found between
|
||||
## angled brackets. Given the limited possibilities of rst inside TOC titles
|
||||
## this should be enough.
|
||||
result = s
|
||||
var first = result.find('<')
|
||||
while first >= 0:
|
||||
let last = result.find('>', first)
|
||||
if last < 0:
|
||||
# Abort, since we didn't found a closing angled bracket.
|
||||
return
|
||||
result.delete(first..last)
|
||||
first = result.find('<', first)
|
||||
|
||||
proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
|
||||
var tmp = ""
|
||||
for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
|
||||
@@ -689,12 +785,19 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
|
||||
|
||||
# Generate index entry using spaces to indicate TOC level for the output HTML.
|
||||
assert n.level >= 0
|
||||
setIndexTerm(d, ieHeading, htmlFile = d.htmlFileRelPath, id = n.anchor,
|
||||
term = n.addNodes, linkTitle = spaces(max(0, n.level)) & tmp)
|
||||
let
|
||||
htmlFileRelPath = if d.outDir.len == 0:
|
||||
# /foo/bar/zoo.nim -> zoo.html
|
||||
changeFileExt(extractFilename(d.filename), HtmlExt)
|
||||
else: # d is initialized in docgen.nim
|
||||
# outDir = /foo -\
|
||||
# destFile = /foo/bar/zoo.html -|-> bar/zoo.html
|
||||
d.destFile.relativePath(d.outDir, '/')
|
||||
setIndexTerm(d, htmlFileRelPath, n.anchor, tmp.stripTocHtml,
|
||||
spaces(max(0, n.level)) & tmp)
|
||||
|
||||
proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
||||
if n.level == 0 and d.meta[metaTitle].len == 0:
|
||||
d.meta[metaTitleRaw] = n.addNodes
|
||||
for i in countup(0, len(n)-1):
|
||||
renderRstToOut(d, n.sons[i], d.meta[metaTitle])
|
||||
d.currentSection = d.meta[metaTitle]
|
||||
@@ -710,8 +813,6 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
||||
dispA(d.target, result, "<h$1$2><center>$3</center></h$1>",
|
||||
"\\rstov$4[$5]{$3}$2\n", [$n.level,
|
||||
n.anchor.idS, tmp, $chr(n.level - 1 + ord('A')), tocName])
|
||||
setIndexTerm(d, ieHeading, htmlFile = d.htmlFileRelPath, id = n.anchor,
|
||||
term = n.addNodes, linkTitle = spaces(max(0, n.level)) & tmp)
|
||||
|
||||
proc renderTocEntry(d: PDoc, n: PRstNode, result: var string) =
|
||||
var header = ""
|
||||
@@ -1096,18 +1197,6 @@ proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string,
|
||||
"\\hyperlink{$2}{$1} (p.~\\pageref{$2})",
|
||||
[textStr, linkStr, nimDocStr, tooltipStr])
|
||||
|
||||
proc traverseForIndex*(d: PDoc, n: PRstNode) =
|
||||
## A version of [renderRstToOut] that only fills entries for ``.idx`` files.
|
||||
var discarded: string
|
||||
if n == nil: return
|
||||
case n.kind
|
||||
of rnIdx: renderIndexTerm(d, n, discarded)
|
||||
of rnHeadline, rnMarkdownHeadline: renderHeadline(d, n, discarded)
|
||||
of rnOverline: renderOverline(d, n, discarded)
|
||||
else:
|
||||
for i in 0 ..< len(n):
|
||||
traverseForIndex(d, n.sons[i])
|
||||
|
||||
proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||
if n == nil: return
|
||||
case n.kind
|
||||
@@ -1362,7 +1451,6 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||
of rnTitle:
|
||||
d.meta[metaTitle] = ""
|
||||
renderRstToOut(d, n.sons[0], d.meta[metaTitle])
|
||||
d.meta[metaTitleRaw] = n.sons[0].addNodes
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@@ -1528,13 +1616,11 @@ proc rstToHtml*(s: string, options: RstParseOptions,
|
||||
proc myFindFile(filename: string): string =
|
||||
# we don't find any files in online mode:
|
||||
result = ""
|
||||
proc myFindRefFile(filename: string): (string, string) =
|
||||
result = ("", "")
|
||||
|
||||
const filen = "input"
|
||||
let (rst, filenames, t) = rstParse(s, filen,
|
||||
line=LineRstInit, column=ColRstInit,
|
||||
options, myFindFile, myFindRefFile, msgHandler)
|
||||
options, myFindFile, msgHandler)
|
||||
var d: RstGenerator
|
||||
initRstGenerator(d, outHtml, config, filen, myFindFile, msgHandler,
|
||||
filenames, hasToc = t)
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2022 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
||||
## Nim `idx`:idx: file format related definitions.
|
||||
|
||||
import strutils, std/syncio, hashes
|
||||
from os import splitFile
|
||||
|
||||
type
|
||||
IndexEntryKind* = enum ## discriminator tag
|
||||
ieMarkupTitle = "markupTitle"
|
||||
## RST/Markdown title, text in `keyword` +
|
||||
## HTML text in `linkTitle`
|
||||
ieNimTitle = "nimTitle"
|
||||
## Nim title
|
||||
ieHeading = "heading" ## RST/Markdown markup heading, escaped
|
||||
ieIdxRole = "idx" ## RST :idx: definition, escaped
|
||||
ieNim = "nim" ## Nim symbol, unescaped
|
||||
ieNimGroup = "nimgrp" ## Nim overload group, unescaped
|
||||
IndexEntry* = object
|
||||
kind*: IndexEntryKind ## 0.
|
||||
keyword*: string ## 1.
|
||||
link*: string ## 2.
|
||||
linkTitle*: string ## 3. contains a prettier text for the href
|
||||
linkDesc*: string ## 4. the title attribute of the final href
|
||||
line*: int ## 5.
|
||||
module*: string ## origin file, NOT a field in ``.idx`` file
|
||||
aux*: string ## auxuliary field, NOT a field in ``.idx`` file
|
||||
|
||||
proc isDocumentationTitle*(hyperlink: string): bool =
|
||||
## Returns true if the hyperlink is actually a documentation title.
|
||||
##
|
||||
## Documentation titles lack the hash. See `mergeIndexes()
|
||||
## <#mergeIndexes,string>`_ for a more detailed explanation.
|
||||
result = hyperlink.find('#') < 0
|
||||
|
||||
proc `$`*(e: IndexEntry): string =
|
||||
"""("$1", "$2", "$3", "$4", $5)""" % [
|
||||
e.keyword, e.link, e.linkTitle, e.linkDesc, $e.line]
|
||||
|
||||
proc quoteIndexColumn(text: string): string =
|
||||
## Returns a safe version of `text` for serialization to the ``.idx`` file.
|
||||
##
|
||||
## The returned version can be put without worries in a line based tab
|
||||
## separated column text file. The following character sequence replacements
|
||||
## will be performed for that goal:
|
||||
##
|
||||
## * ``"\\"`` => ``"\\\\"``
|
||||
## * ``"\n"`` => ``"\\n"``
|
||||
## * ``"\t"`` => ``"\\t"``
|
||||
result = newStringOfCap(text.len + 3)
|
||||
for c in text:
|
||||
case c
|
||||
of '\\': result.add "\\"
|
||||
of '\L': result.add "\\n"
|
||||
of '\C': discard
|
||||
of '\t': result.add "\\t"
|
||||
else: result.add c
|
||||
|
||||
proc unquoteIndexColumn*(text: string): string =
|
||||
## Returns the unquoted version generated by ``quoteIndexColumn``.
|
||||
result = text.multiReplace(("\\t", "\t"), ("\\n", "\n"), ("\\\\", "\\"))
|
||||
|
||||
proc formatIndexEntry*(kind: IndexEntryKind; htmlFile, id, term, linkTitle,
|
||||
linkDesc: string, line: int):
|
||||
tuple[entry: string, isTitle: bool] =
|
||||
result.entry = $kind
|
||||
result.entry.add('\t')
|
||||
result.entry.add term
|
||||
result.entry.add('\t')
|
||||
result.entry.add(htmlFile)
|
||||
if id.len > 0:
|
||||
result.entry.add('#')
|
||||
result.entry.add(id)
|
||||
result.isTitle = false
|
||||
else:
|
||||
result.isTitle = true
|
||||
result.entry.add('\t' & linkTitle.quoteIndexColumn)
|
||||
result.entry.add('\t' & linkDesc.quoteIndexColumn)
|
||||
result.entry.add('\t' & $line)
|
||||
result.entry.add("\n")
|
||||
|
||||
proc parseIndexEntryKind(s: string): IndexEntryKind =
|
||||
result = case s:
|
||||
of "nim": ieNim
|
||||
of "nimgrp": ieNimGroup
|
||||
of "heading": ieHeading
|
||||
of "idx": ieIdxRole
|
||||
of "nimTitle": ieNimTitle
|
||||
of "markupTitle": ieMarkupTitle
|
||||
else: raise newException(ValueError, "unknown index entry value $1" % [s])
|
||||
|
||||
proc parseIdxFile*(path: string):
|
||||
tuple[fileEntries: seq[IndexEntry], title: IndexEntry] =
|
||||
var
|
||||
f = 0
|
||||
newSeq(result.fileEntries, 500)
|
||||
setLen(result.fileEntries, 0)
|
||||
let (_, base, _) = path.splitFile
|
||||
for line in lines(path):
|
||||
let s = line.find('\t')
|
||||
if s < 0: continue
|
||||
setLen(result.fileEntries, f+1)
|
||||
let cols = line.split('\t')
|
||||
result.fileEntries[f].kind = parseIndexEntryKind(cols[0])
|
||||
result.fileEntries[f].keyword = cols[1]
|
||||
result.fileEntries[f].link = cols[2]
|
||||
if result.title.keyword.len == 0:
|
||||
result.fileEntries[f].module = base
|
||||
else:
|
||||
result.fileEntries[f].module = result.title.keyword
|
||||
|
||||
result.fileEntries[f].linkTitle = cols[3].unquoteIndexColumn
|
||||
result.fileEntries[f].linkDesc = cols[4].unquoteIndexColumn
|
||||
result.fileEntries[f].line = parseInt(cols[5])
|
||||
|
||||
if result.fileEntries[f].kind in {ieNimTitle, ieMarkupTitle}:
|
||||
result.title = result.fileEntries[f]
|
||||
inc f
|
||||
|
||||
proc cmp*(a, b: IndexEntry): int =
|
||||
## Sorts two ``IndexEntry`` first by `keyword` field, then by `link`.
|
||||
result = cmpIgnoreStyle(a.keyword, b.keyword)
|
||||
if result == 0:
|
||||
result = cmpIgnoreStyle(a.link, b.link)
|
||||
|
||||
proc hash*(x: IndexEntry): Hash =
|
||||
## Returns the hash for the combined fields of the type.
|
||||
##
|
||||
## The hash is computed as the chained hash of the individual string hashes.
|
||||
result = x.keyword.hash !& x.link.hash
|
||||
result = result !& x.linkTitle.hash
|
||||
result = result !& x.linkDesc.hash
|
||||
result = !$result
|
||||
@@ -29,7 +29,7 @@ const
|
||||
CLONE_NEWPID* = 0x20000000'i32
|
||||
CLONE_NEWNET* = 0x40000000'i32
|
||||
CLONE_IO* = 0x80000000'i32
|
||||
|
||||
CLONE_STOPPED* {.deprecated.} = 0x02000000'i32
|
||||
|
||||
# fn should be of type proc (a2: pointer) {.cdecl.}
|
||||
proc clone*(fn: pointer; child_stack: pointer; flags: cint;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user