Compare commits

..

368 Commits

Author SHA1 Message Date
ringabout
112e274804 switch on 2023-12-11 14:12:55 +00:00
ringabout
f1a7bfce47 switch on 2023-12-11 14:12:47 +00:00
ringabout
68bf6c7f93 what's problem os cancelled CI 2023-12-11 11:00:02 +00:00
ringabout
7cd431804b test CI 2023-12-11 09:07:41 +00:00
ringabout
01388dc816 Merge branch 'devel' into pr_string_v3 2023-12-11 13:16:03 +08:00
ringabout
bee9baa8bf reprieve IC 2023-12-09 11:56:17 +00:00
ringabout
147621ec21 fixes a critical issue 2023-12-09 02:41:05 +00:00
ringabout
5bde480596 workaround a cstring conversion bug 2023-12-09 02:34:22 +00:00
ringabout
33f911e691 fixes C++ compilation 2023-12-08 14:13:21 +00:00
ringabout
ec03e476d5 fixes more problems 2023-12-08 08:41:16 +00:00
ringabout
4adb79f7cb a small fix 2023-12-08 07:29:36 +00:00
ringabout
1da417b818 tests nimSeqsV3 2023-12-08 07:26:32 +00:00
ringabout
7ef0f43f35 basic examples work now 2023-12-08 07:04:15 +00:00
Jake Leahy
0a7094450e Only suggest symbols that could be pragmas when typing a pragma (#23040)
Currently pragmas just fall through to `suggestSentinel` and show
everything which isn't very useful. Now it filters for symbols that
could be pragmas (templates with `{.pragma.}`, macros, user pragmas) and
only shows them
2023-12-07 23:05:41 +01:00
ringabout
da277cf1b8 more fixes 2023-12-07 14:47:51 +00:00
ringabout
cb172328ba simple cases compile 2023-12-07 13:56:33 +00:00
ringabout
9af21cf719 progress 2023-12-07 12:53:06 +00:00
Jake Leahy
4fdc6c49bd Don't process a user pragma if its invalid (#23041)
When running `check`/`suggest` in a file with an invalid user pragma
like
```nim
{.pragma foo: test.}
```
It will continue to try and process it which leads to the compiler
running into a `FieldDefect`
```
fatal.nim(53)            sysFatal
Error: unhandled exception: field 'sons' is not accessible for type 'TNode' using 'kind = nkIdent' [FieldDefect]
```
This makes it instead bail out trying to process the user pragma if its
invalid
2023-12-07 08:14:23 +01:00
Jacek Sieka
e1a0ff1b8a lexer cleanups (#23037)
* remove some dead code and leftovers from past features
* fix yaml printing of uint64 literals
2023-12-06 18:17:57 +01:00
ringabout
f7bdec6f0d progress 2023-12-06 14:25:34 +00:00
ringabout
88c0ac44fc simple additions 2023-12-06 06:09:25 +00:00
Jake Leahy
44b64e726e Don't recurse into inner functions during asyncjs transform (#23036)
Closes #13341
2023-12-06 04:59:38 +01:00
ringabout
119cfe8bc8 some improvements 2023-12-06 02:27:05 +00:00
ringabout
d20b4d5168 fixes #23019; Regression from 2.0 to devel with raise an unlisted exc… (#23034)
…eption: Exception

fixes #23019

I suppose `implicitPragmas` is called somewhere which converts
`otherPragmas`.
2023-12-05 21:04:41 +01:00
ringabout
ae99903236 wip: intern strings 2023-12-05 14:51:24 +00:00
ringabout
202e21daba forbides adding sons for PType (#23030)
I image `add` for `PType` to be used everythere
2023-12-04 16:20:19 +01:00
Nikolay Nikolov
618ccb6b6a Also show the raises pragma when converting proc types to string (#23026)
This affects also nimsuggest hints (e.g. on mouse hover), as well as
compiler messages.
2023-12-04 07:17:42 +01:00
Jake Leahy
b8fa789393 Fix nimsuggest def being different on proc definition/use (#23025)
Currently the documentation isn't shown when running `def` on the
definition of a proc (Which works for things like variables).
`gcsafe`/`noSideEffects` status also isn't showing up when running `def`
on the definition

Images of current behavior. After PR both look like "Usage"
**Definition**

![image](https://github.com/nim-lang/Nim/assets/19339842/bf75ff0b-9a96-49e5-bf8a-d2c503efa784)
**Usage**

![image](https://github.com/nim-lang/Nim/assets/19339842/15ea3ebf-64e1-48f5-9233-22605183825f)


Issue was the symbol getting passed too early to nimsuggest so it didn't
have all that info, now gets passed once proc is fully semmed
2023-12-04 07:15:16 +01:00
Joachim Hereth
d5780a3e4e strutils.multiReplace: Making order of replacement explicit (#23022)
In the docs for strutils.multiReplace:

Making it more explicit that left to right comes before the order in the
replacements arg (but that the latter matters too).

E.g.

```
echo "ab".multiReplace(@[("a", "1"), ("ax", "2")])
echo "ab".multiReplace(@[("ab", "2"), ("a", "1")])
```

gives

```
1b
2
```

resolves #23016
2023-12-02 22:41:53 +01:00
Jake Leahy
a25843cf80 Show proper error message if trying to run a Nim file in a directory that doesn't exist (#23017)
For example with the command `nim r foo/bar.nim`, if `foo/` doesn't
exist then it shows this message
```
oserrors.nim(92)         raiseOSError
Error: unhandled exception: No such file or directory
Additional info: foo [OSError]
```

After PR it shows
```
Error: cannot open 'foo/bar.nim'
```
Which makes it line up with the error message if `foo/` did exist but
`bar.nim` didn't. Does this by using the same logic for [handling if the
file doesn't
exist](0dc12ec24b/compiler/options.nim (L785-L788))
2023-12-02 05:29:10 +01:00
Andreas Rumpf
0d24f76546 fixes #22552 (#23014) 2023-12-02 05:28:24 +01:00
Erich Reitz
5dfa1345fa related #22534; fixes documentation rendering of custom number literal routine declaration (#23015)
I'm not sure if this is a complete fix, as it does not match the
expected output given in the issue. The expected output given in the
issue highlights the identifier after the `'` the same color as numeric
literals (blue), and this change does not address that. I think that
would involve simplifying `nimNumberPostfix`.

However, this fixes the issue where the routine declaration was rendered
as a string.
New rendering: 
![Screenshot from 2023-11-30
22-17-17](https://github.com/nim-lang/Nim/assets/80008541/b604ce27-a4ad-496b-82c3-0b568d99a8bf)
2023-12-01 07:21:42 +01:00
Andreas Rumpf
ab7faa73ef fixes #22852; real bugfix is tied to bug #22672 (#23013) 2023-11-30 17:59:16 +01:00
ringabout
7ea5aaaebb fixes #23001; give a better warning for PtrToCstringConv (#23005)
fixes #23001
2023-11-30 14:12:12 +01:00
ringabout
bc24340d55 fixes #23006; newSeqUninit -> CT Error; imitate newStringUninit (#23007)
fixes #23006
2023-11-30 14:08:49 +01:00
ringabout
b5f5b74fc8 enable vtable implementation for C++ and make it an experimental feature (#23004)
follow up https://github.com/nim-lang/Nim/pull/22991

- [x] turning it into an experimental feature

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-11-30 14:05:45 +01:00
SirOlaf
9140f8e221 Fix endsInNoReturn for case statements (#23009)
While looking at the CI I noticed that there's a couple false positives
for `case` statements that cannot be checked for exhaustiveness since my
changes, this should resolve them.

---------

Co-authored-by: SirOlaf <>
2023-11-30 11:01:42 +01:00
inv2004
0f7ebb490c table.mgetOrPut without default val (#22994)
RFC: https://github.com/nim-lang/RFCs/issues/539

- ~~mgetOrPutDefaultImpl template into `tableimpl.nim` to avoid macros~~
- mgetOrPut for `Table`, `TableRef`, `OrderedTable`, `OrderedTableRef`
- `tests/stdlib/tmget.nim` tests update

---------

Co-authored-by: inv2004 <>
2023-11-30 11:00:33 +01:00
c-blake
beeacc86ff Silence several Hint[Performance] warnings (#23003)
With `--mm:arc` one gets the "implicit copy; if possible, rearrange your
program's control flow" `Performance` warnings without these `move`s.
2023-11-29 22:36:47 +01:00
ringabout
96513b2506 fixes #22926; Different type inferred when setting a default value for an array field (#22999)
fixes #22926
2023-11-29 10:36:20 +01:00
ringabout
795aad4f2a fixes #22996; typeAllowedCheck for default fields (#22998)
fixes #22996
2023-11-29 10:35:50 +01:00
ringabout
30cf33f04d rework the vtable implementation embedding the vtable array directly with new strictions on methods (#22991)
**TODO**
- [x] fixes changelog
With the new option `nimPreviewVtables`, `methods` are confined in the
same module where the type of the first parameter is defined

- [x] make it opt in after CI checks its feasibility

## In the following-up PRs

- [ ] in the following PRs, refactor code into a more efficient one

- [ ] cpp needs special treatments since it cannot embed array in light
of the preceding limits: ref
https://github.com/nim-lang/Nim/pull/20977#discussion_r1035528927; we
can support cpp backends with vtable implementations later on the
comprise that uses indirect vtable access

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-11-28 15:11:43 +01:00
Jake Leahy
8cad6ac048 Don't try and get enum value if its invalid (#22997)
Currently running `nimsuggest`/`check` on this code causes the compiler
to raise an exception

```nim
type
  Test = enum
    A = 9.0 
```

```
assertions.nim(34)       raiseAssert
Error: unhandled exception: int128.nim(69, 11) `arg.sdata(3) == 0` out of range [AssertionDefect]
```

Issue was the compiler still trying to get the ordinal value even if it
wasn't an ordinal
2023-11-28 09:38:10 +01:00
Jake Leahy
c31bbb07fb Register declaration of enum field has a use (#22990)
Currently when using `use` with nimsuggest on an enum field, it doesn't
return the definition of the field.

Breaks renaming in IDEs since it will replace all the usages, but not
the declaration
2023-11-27 22:08:05 +01:00
John Viega
5b2fcabff5 fix: std/marshal unmarshaling of ref objects (#22983)
Fixes #16496 

![Marshal doesn't properly unmarshal *most* ref objects; the exceptions
being nil
ones](https://github-production-user-asset-6210df.s3.amazonaws.com/4764481/285471431-a39ee2c5-5670-4b12-aa10-7a10ba6b5b96.gif)
Test case added.

Note that this test (t9754) does pass locally, but there are tons of
failures by default on OS X arm64, mostly around the bohem GC, so it's
pretty spammy, and could easily have missed something. If there are
better instructions please do let me know.

---------

Co-authored-by: John Viega <viega@Johns-MacBook-Pro.local>
Co-authored-by: John Viega <viega@Johns-MBP.localdomain>
Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-11-26 06:32:32 +01:00
tersec
26f2ea149c remove unnecessary side-effects from base64.encode(mime) (#22986)
Fixes https://github.com/nim-lang/Nim/issues/22985
2023-11-25 20:52:42 +01:00
ringabout
379299a5ac fixes #22286; enforce Non-var T destructors by nimPreviewNonVarDestructor (#22975)
fixes #22286
ref https://forum.nim-lang.org/t/10642

For backwards compatibilities, we might need to keep the changes under a
preview compiler flag. Let's see how many packags it break.

**TODO** in the following PRs

- [ ] Turn the `var T` destructors warning into an error with
`nimPreviewNonVarDestructor`

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-11-25 18:27:27 +01:00
Nikolay Nikolov
502a4486ae nimsuggest: Added optional command line option '--clientProcessId:XXX' (#22969)
When it is specified, the nimsuggest instance monitors whether this
process is still alive. In case it's found to be dead, nimsuggest shuts
itself down. Currently only implemented on POSIX and Windows platforms.
The switch is silently ignored on other platforms. Note that the Nim
language server should still try to shut down its child nimsuggest
processes. This switch just adds extra protection against crashing Nim
language server and gets rid of the remaining nimsuggest processes,
which consume memory and system resources.
2023-11-24 19:55:53 +01:00
ringabout
816ddd8be7 build nimble with ORC and bump nimble version (#22978)
ref https://github.com/nim-lang/nimble/pull/1074
2023-11-24 15:41:57 +01:00
Andreas Rumpf
ce1a5cb165 progress: 'm' command line switch (#22976) 2023-11-22 09:58:17 +01:00
Pylgos
eba87c7e97 fixes #22971; inferGenericTypes does not work with method call syntax (#22972)
fixes #22971
2023-11-22 07:50:38 +01:00
ringabout
8c56e806ae closes #12464; adds a test case (#22967)
closes #12464
2023-11-20 21:17:20 +01:00
Jake Leahy
81c0513644 Don't provide suggestions for enum fields (#22959)
Currently the suggestions create a lot of noise when creating enum
fields. I don't see any way of a macro creating fields (when called
inside an enum) so it should be safe to not show suggestions

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-11-20 21:12:54 +01:00
Andreas Rumpf
02be027e9b IC: progress and refactorings (#22961) 2023-11-20 21:12:13 +01:00
ringabout
cecaf9c56b fixes #22939; fixes #16890; push should but doesn't apply to importc … (#22944)
…var/let symbols


fixes #22939
fixes #16890

Besides, it was applied to let/const/var with pragmas, now it is
universally applied.

```nim
{.push exportc.}
proc foo =
  let bar = 12
  echo bar
{.pop.}
```

For example, the `bar` variable will be affected by `exportc`.
2023-11-19 17:53:25 +01:00
ringabout
5dafcf4957 fixes #22913; fixes #12985 differently push-ing pragma exportc genera… (#22941)
…tes invalid C identifiers

fixes #22913
fixes #12985 differently


`{.push.} now does not apply to generic instantiations`
2023-11-19 17:52:42 +01:00
ringabout
6c5283b194 enable nimwc testing (#22960)
ref https://github.com/ThomasTJdev/nim_websitecreator/pull/145
2023-11-19 16:23:03 +08:00
Nikolay Nikolov
4fc0027b57 Introduced version 4 of the NimSuggest protocol. The InlayHints feature made V4 or later only. (#22953)
Since nimsuggest now has a protocol version support detection via
`--info:protocolVer`, the InlayHints feature can be moved to protocol
V4. This way, the Nim language server can detect the nimsuggest version
and avoid sending unsupported `InlayHints` commands to older nimsuggest
versions. Related nim language server PR:
https://github.com/nim-lang/langserver/pull/60
2023-11-18 16:21:59 +01:00
Derek
0f7488e20f let InotifyEvent type sizeof-able (#22958)
Since the `InotifyEvent`s are receive through `read()`, user need the
size of the type.
2023-11-18 16:21:01 +01:00
ringabout
09ea1b168f fixes #22947; static integers in quote do [backport] (#22948)
fixes #22947
2023-11-18 09:40:28 +01:00
握猫猫
39fbd30513 Fix OSError errorCode field is not assigned a value (#22954)
In this PR, the following changes were made:
1. Replaced `raise newException(OSError, osErrorMsg(errno))` in batches
with `raiseOSError(errcode)`.
2. Replaced `newException(OSError, osErrorMsg(errno))` in batches with
`newOSError(errcode)`.

There are still some places that have not been replaced. After checking,
they are not system errors in the traditional sense.

```nim
proc dlclose(lib: LibHandle) =
  raise newException(OSError, "dlclose not implemented on Nintendo Switch!")
```

```nim
if not fileExists(result) and not dirExists(result):
  # consider using: `raiseOSError(osLastError(), result)`
  raise newException(OSError, "file '" & result & "' does not exist")
```

```nim
proc paramStr*(i: int): string =
  raise newException(OSError, "paramStr is not implemented on Genode")
```
2023-11-17 22:06:46 +01:00
Angel Ezquerra
fbfd4decca 'j' format specifier docs (#22928)
This is a small improvement on top of PR #22924, which documents the new
'j' format specifier for Complex numbers. In addition to that it moves
the handling of the j specifier into the function that actually
implements it (formatValueAsComplexNumber), which seems a little
cleaner.

---------

Co-authored-by: Angel Ezquerra <angel_ezquerra@keysight.com>
Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
2023-11-17 10:22:57 +01:00
Marko Schütz-Schmuck
80ffbd4571 Minor documentation change (#22951)
I've made a small change in the explanation of `void` types.
2023-11-17 10:21:21 +01:00
Ikko Eltociear Ashimine
cd84cd45ea doc: update manual_experimental.md (#22949)
sematics -> semantics
2023-11-16 22:30:08 +08:00
Nikolay Nikolov
3680200df4 nimsuggest: Instead of checking for protocol version 3 exactly, check for version 3 or later. (#22945)
Refactored the way nimsuggest checks for protocol version 3. Instead of
checking for version 3 exactly, it now checks for version 3 or later.
This way, once a version 4 is introduced, it will use version 3 as a
base line, and then extra changes to the protocol can be added on top.
No functional changes are introduced in this commit.
2023-11-15 18:41:58 +01:00
Nikolay Nikolov
d0cc02dfc4 Added new command line option --info:X to nimsuggest for obtaining information. (#22940)
`--info:protocolVer` returns the highest nimsuggest protocol version
that is supported (currently, it's version 3).
`--info:nimVer` returns the Nim compiler version that nimsuggest uses
internally.

Note that you can obtain the Nim compiler version via `nimsuggest -v`,
but that requires parsing the output, which looks like this:

```
Nim Compiler Version 2.1.1 [Linux: amd64]
Compiled at 2023-11-14
Copyright (c) 2006-2023 by Andreas Rumpf

git hash: 47ddfeca5247dce992becd734d1ae44e621207b8
active boot switches: -d:release -d:danger --gc:markAndSweep
```

`--info:nimVer` will return just:

```
2.1.1
```
2023-11-15 15:10:10 +01:00
ringabout
57ffeafda0 minor fixes for changelog (#22938)
ref
1bb117cd7a (r132468022)
2023-11-14 18:57:23 +08:00
ringabout
0dc3513613 fixes #22932; treats closure iterators as pointers (#22934)
fixes #22932
follow up https://github.com/nim-lang/Nim/pull/21629

---------

Co-authored-by: Nickolay Bukreyev <SirNickolas@users.noreply.github.com>
2023-11-14 07:15:44 +01:00
Angel Ezquerra
52784f32bb Add strformat support for Complex numbers (#22924)
Before this change strformat used the generic formatValue function for
Complex numbers. This meant that it was not possible to control the
format of the real and imaginary components of the complex numbers.

With this change this now works:
```nim
import std/[complex, strformat]
let c = complex(1.05000001, -2.000003)
echo &"{c:g}"
# You now get: (1.05, -2)
# while before you'd get a ValueError exception (invalid type in format string for string, expected 's', but got g)
```

The only small drawback of this change is that I had to import complex
from strformat. I hope that is not a problem.

---------

Co-authored-by: Angel Ezquerra <angel_ezquerra@keysight.com>
2023-11-10 05:29:55 +01:00
Jake Leahy
60597adb10 Fix using --stdout with jsondoc (#22925)
Fixes the assertion defect that happens when using `jsondoc --stdout`
(There is no outfile since its just stdout)

```
Error: unhandled exception: options.nim(732, 3) `not conf.outFile.isEmpty`  [AssertionDefect]
```

Also makes the output easier to parse by ending each module output with
a new line.
2023-11-09 07:33:57 +01:00
Andreas Rumpf
e081f565cb IC: use better packed line information format (#22917) 2023-11-07 11:25:57 +01:00
Nikolay Nikolov
f5bbdaf906 Inlay hints for types of consts (#22916)
This adds inlay hint support for the types of consts.
2023-11-07 11:25:13 +01:00
ringabout
2e070dfc76 fixes #22673; Cannot prove that result is initialized for a placehold… (#22915)
…er base method returning a lent


fixes #22673
2023-11-06 19:36:26 +01:00
Andreas Rumpf
b79b39128e NIR: C codegen additions (#22914) 2023-11-06 18:33:28 +01:00
Jacek Sieka
58c44312af reserve sysFatal for Defect (#22158)
Per manual, `panics:on` affects _only_ `Defect`:s - thus `sysFatal`
should not redirect any other exceptions.

Also, when `sysFatal` is used in `nimPanics` mode, it should use regular
exception handling pipeline to ensure exception hooks are called
consistently for all raised defects.
2023-11-06 07:57:29 +01:00
Andreas Rumpf
eb8824d71c NIR: C codegen, WIP (#22903) 2023-11-05 20:25:25 +01:00
ringabout
f0e5bdd7d8 fixes #22898; fix #22883 differently (#22900)
fixes #22898
In these cases, the tables/sets are clears or elements are deleted from
them. It's reasonable to suppress warnings because the value is not
accessed anymore, which means it's safe to ignore the warnings.
2023-11-05 09:12:53 +01:00
Solitude
ec37b59a65 Add missing std prefix (#22910)
without it, devels fails to build with `-d:useLinenoise`
2023-11-04 17:46:59 +08:00
ringabout
af556841ac fixes #22860; suppress AnyEnumConv warning when iterating over set (#22904)
fixes #22860
2023-11-04 08:52:30 +01:00
Nikolay Nikolov
3f2b9c8bcf Inlay hints support (#22896)
This adds inlay hints support to nimsuggest. It adds a new command to
nimsuggest, called 'inlayHints'.

Currently, it provides type information to 'var' and 'let' variables. In
the future, inlay hints can also be added for 'const' and for function
parameters. The protocol also reserves space for a tooltip field, which
is not used, yet, but support for it can be added in the future, without
further changing the protocol.

The change includes refactoring to allow the 'inlayHints' command to
return a completely different structure, compared to the other
nimsuggest commands. This will allow other future commands to have
custom return types as well. All the previous commands return the same
structure as before, so perfect backwards compatibility is maintained.

To use this feature, an update to the nim language server, as well as
the VS code extension is needed.

Related PRs:
nimlangserver: https://github.com/nim-lang/langserver/pull/53
VS code extension: https://github.com/saem/vscode-nim/pull/134

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-11-04 08:51:09 +01:00
ringabout
95e5ad6927 fixes #22902; borrow from proc return type mismatch (#22908)
fixes #22902
2023-11-04 08:50:30 +01:00
Juan M Gómez
d70a9957e2 adds C++ features to change log (#22906)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
Co-authored-by: Juan Carlos <juancarlospaco@gmail.com>
2023-11-03 13:54:35 -04:00
ringabout
b68e0aab4c fixes #22866; fixes #19998; ensure destruction for Object construction with custom destructors (#22901)
fixes #22866;
fixes #19998
2023-11-02 11:14:50 +01:00
Yardanico
40e33dec45 Fix IndexDefect errors in httpclient on invalid/weird headers (#22886)
Continuation of https://github.com/nim-lang/Nim/pull/19262

Fixes https://github.com/nim-lang/Nim/issues/19261

The parsing code is still too lenient (e.g. it will happily parse header
names with spaces in them, which is outright invalid by the spec), but I
didn't want to touch it beyond the simple changes to make sure that
`std/httpclient` won't throw `IndexDefect`s like it does now on those
cases:
- Multiline header values
- No colon after the header name
- No value after the header name + colon

One question remains - should I keep `toCaseInsensitive` exported in
`httpcore` or just copy-paste the implementation?

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-11-01 08:01:31 +01:00
ringabout
92141e82ed fixes #22883; replace default(typeof( with reset; suppress `Unsaf… (#22895)
fixes #22883

…eDefault` warnings

avoid issues mentioned by https://forum.nim-lang.org namely, it
allocated unnecessary stack objects in the loop

```c
while (1)
{
tyObject_N__8DSNqSGSHBKOhI8CqSgAow T5_;
nimZeroMem((void *)(&T5_), sizeof(tyObject_N__8DSNqSGSHBKOhI8CqSgAow));
eqsink___test4954_u450((&(*t_p0).data.p->data[i].Field1), T5_);
}
```

It might be more efficient in some cases

follow up https://github.com/nim-lang/Nim/pull/21821
2023-11-01 07:54:47 +01:00
Andreas Rumpf
801c02bf48 so close... (#22885) 2023-10-31 21:32:09 +01:00
ringabout
2ae344f1c2 minor fixes for node20 (#22894) 2023-10-31 18:49:23 +01:00
ringabout
f61311f7a0 bump node to 20.x; since 16.x is End-of-Life (#22892) 2023-10-30 17:05:03 +01:00
ringabout
afa2f2ebf6 fixes nightlies; fixes incompatible types with csource_v2 (#22889)
ref
https://github.com/nim-lang/nightlies/actions/runs/6686795512/job/18166625042#logs

> /home/runner/work/nightlies/nightlies/nim/compiler/nir/nirvm.nim(163,
35) Error: type mismatch: got 'BiggestInt' for
'b.m.lit.numbers[litId(b.m.types.nodes[int(y)])]' but expected 'int'

Or unifies the type in one way or another
2023-10-30 17:03:19 +01:00
ringabout
4d11d0619d complete std prefixes for stdlib (#22887)
follow up https://github.com/nim-lang/Nim/pull/22851
follow up https://github.com/nim-lang/Nim/pull/22873
2023-10-30 17:03:04 +01:00
Andreas Rumpf
403e0118ae NIR: progress (#22884) 2023-10-29 21:53:28 +01:00
ringabout
e17237ce9d prepare for the enforcement of std prefix (#22873)
follow up https://github.com/nim-lang/Nim/pull/22851
2023-10-29 14:48:11 +01:00
Andreas Rumpf
0c26d19e22 NIR: VM + refactorings (#22835) 2023-10-29 14:47:22 +01:00
Yardanico
94ffc18332 Fix #22862 - change the httpclient user-agent to be valid spec-wise (#22882)
Per https://datatracker.ietf.org/doc/html/rfc9110#name-user-agent a
User-Agent is defined as follows:
```
  User-Agent = product *( RWS ( product / comment ) )
```
Where
```
  product         = token ["/" product-version]
  product-version = token
```
In this case, `token` is defined in RFC 7230 -
https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6:
```
     token          = 1*tchar

     tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
                    / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
                    / DIGIT / ALPHA
                    ; any VCHAR, except delimiters
```
or, in the original RFC 2616 -
https://datatracker.ietf.org/doc/html/rfc2616#section-2.2 (next page):
```
       token          = 1*<any CHAR except CTLs or separators>
       separators     = "(" | ")" | "<" | ">" | "@"
                      | "," | ";" | ":" | "\" | <">
                      | "/" | "[" | "]" | "?" | "="
                      | "{" | "}" | SP | HT
```
which means that a `token` cannot have whitespace. Not sure if this
should be in the breaking changelog section - theoretically, some
clients might've relied on the old Nim user-agent?

For some extra info, some other languages seem to have adopted the same
hyphen user agent to specify the language + module, e.g.:
-
https://github.com/python/cpython/blob/main/Lib/urllib/request.py#L1679
(`Python-urllib/<version>`)

Fixes #22862.
2023-10-29 06:21:32 +01:00
ringabout
fbc801d1d1 build documentation for htmlparser (#22879)
I have added a note for installment
https://github.com/nim-lang/htmlparser/pull/5

> In order to use this module, run `nimble install htmlparser`.
2023-10-27 18:34:53 -04:00
ringabout
d66f3febd1 fixes #22868; fixes std/nre leaks under ARC/ORC (#22872)
fixes #22868
2023-10-27 07:32:10 +02:00
ringabout
0e45b01b21 deprecate htmlparser (#22870)
ref https://github.com/nim-lang/Nim/pull/22848
see also https://github.com/nim-lang/htmlparser
will build the documentation later when everything else is settled

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-10-26 13:07:50 +02:00
ringabout
cef5e57eb5 fixes #22867; fixes cstring modification example on Nim Manual (#22871)
fixes #22867
2023-10-26 10:06:44 +02:00
shuoer86
7c3917d1dd doc: fix typos (#22869)
doc: fix typos
2023-10-25 20:53:15 +08:00
ringabout
3fd4e68433 fixes #22856; enables -d:nimStrictDelete (#22858)
fixes #22856

`-d:nimStrictDelete` is introduced in 1.6.0, which promised to be
enabled in the coming versions. To keep backwards incompatibilities, it
also extends the feature of `-d:nimAuditDelete`, which now mimics the
old behaviors.
2023-10-24 05:13:14 +02:00
ringabout
3095048d67 fixes system.delete that raises defects (#22857) 2023-10-23 22:56:52 +08:00
握猫猫
562a5fb8f9 fix use after free (#22854)
1. `freeAddrInfo` is called prematurely, the variable `myAddr` is still
in use
2. Use defer syntax to ensure that `freeAddrInfo` is also called on
exceptions
2023-10-23 09:11:13 +02:00
Juan M Gómez
ca577dbab1 C++: ptr fields now pulls the whole type if it's a member in nkDotExpr (#22855) 2023-10-23 08:59:14 +02:00
SirOlaf
c13c48500b Fix #22826: Don't skip generic instances in type comparison (#22828)
Close #22826

I am not sure why this code skips generic insts, so letting CI tell me.
Update: It has told me nothing. Maybe someone knows during review.

Issue itself seems to be that the generic instance is skipped thus it
ends up being just `float` which makes it use the wrong generic instance
of the proc because it matches the one in cache

---------

Co-authored-by: SirOlaf <>
2023-10-21 22:00:16 +02:00
Vindaar
2b1a671f1c explicitly import using std/ in tempfiles.nim (#22851)
At least on modern Nim `tempfiles` is not usable if the user has
https://github.com/oprypin/nim-random installed, because the compiler
picks the nimble path over the stdlib path (apparently).
2023-10-20 19:04:01 +02:00
ringabout
e10878085e fixes #22844; uses arrays to store holeyenums for iterations; much more efficient than sets and reasonable for holeyenums (#22845)
fixes #22844
2023-10-20 18:38:42 +02:00
rockcavera
27deacecaa fix #22834 (#22843)
fix #22834

Edit: also fixes `result.addrList` when IPv6, which previously only
performed a `result.addrList = cstringArrayToSeq(s.h_addr_list)` which
does not provide the textual representation of an IPv6
2023-10-20 09:43:53 +02:00
Juan Carlos
05a7c0fdd0 Bisect default Linux (#22840)
- Bisect default to Linux only. Tiny diff, YAML only.

| OS | How to? |
|----|---------|
| Linux | `-d:linux` |
| Windows | `-d:windows` |
| OS X | `-d:osx` |

If no `-d:linux` nor `-d:windows` nor `-d:osx` is used then defaults to
Linux.
2023-10-18 20:12:50 -04:00
ringabout
0d4b3ed18e fixes #22836; Unnecessary warning on 'options.none' with 'strictDefs'… (#22837)
… enabled

fixes #22836
2023-10-18 22:44:13 +08:00
Andreas Rumpf
3c48af7ebe NIR: temporary ID generation bugfix (#22830) 2023-10-16 15:47:13 +02:00
Juan M Gómez
a9bc6779e1 the compiler can be compiled with vcc (#22832) 2023-10-16 15:36:39 +02:00
ringabout
078495c793 closes #16919; followup #16820, test tsugar on all backends (#22829)
closes #16919
followup #16820
2023-10-16 12:44:55 +08:00
Andreas Rumpf
10c3ab6269 NIR: store sizes, alignments and offsets in the type graph; beginning… (#22822)
…s of a patent-pending new VM
2023-10-16 00:01:33 +02:00
Himaj Patil
5f400983d5 Update readme.md (#22827)
Added table view in Compiling section of documentation
2023-10-15 21:29:16 +02:00
ringabout
f5d70e7fa7 fixes #19250; fixes #22259; ORC AssertionDefect not containsManagedMemory(n.typ) (#22823)
fixes #19250
fixes #22259

The strings, seqs, refs types all have this flag, why should closures be
treated differently?

follow up https://github.com/nim-lang/Nim/pull/14336
2023-10-13 21:34:13 +02:00
ringabout
61145b1d4b fixes #22354; Wrong C++ codegen for default parameter values in ORC (#22819)
fixes #22354

It skips `nkHiddenAddr`. No need to hoist `var parameters` without side
effects. Besides, it saves lots of temporary variables in ORC.
2023-10-13 10:58:43 +02:00
Andreas Rumpf
8990626ca9 NIR: progress (#22817)
Done:

- [x] Implement conversions to openArray/varargs.
- [x] Implement index/range checking.
2023-10-12 23:33:38 +02:00
ringabout
d790112ea4 update nimble (#22814)
Issues like https://github.com/nim-lang/nimble/issues/1149 keep popping
up. One way or another, we should alleviate the pain.

Finally, we should consider
https://github.com/nim-lang/nimble/pull/1141#discussion_r1316829521 as
an option using some kind of cron script to update
https://nim-lang.org/nimble/packages.json. It's turning into a really
annoying problem.
2023-10-11 21:06:25 +02:00
SirOlaf
68ba45cc04 Import std/stackframes in ast2ir.nim (#22815)
Ref https://github.com/nim-lang/Nim/pull/22777#issuecomment-1758090410

Co-authored-by: SirOlaf <>
2023-10-11 21:05:51 +02:00
Andreas Rumpf
816589b667 NIR: Nim intermediate representation (#22777)
Theoretical Benefits / Plans: 

- Typed assembler-like language.
- Allows for a CPS transformation.
- Can replace the existing C backend by a new C backend.
- Can replace the VM.
- Can do more effective "not nil" checking and static array bounds
checking.
- Can be used instead of the DFA.
- Easily translatable to LLVM.
- Reasonably easy to produce native code from.
- Tiny memory consumption. No pointers, no cry.

**In very early stages of development.**

Todo:
- [x] Map Nim types to IR types.
- [ ] Map Nim AST to IR instructions:
  - [x] Map bitsets to bitops.
  - [ ] Implement string cases.
  - [ ] Implement range and index checks.
  - [x] Implement `default(T)` builtin.
  - [x] Implement multi string concat.
- [ ] Write some analysis passes.
- [ ] Write a backend.
- [x] Integrate into the compilation pipeline.
2023-10-11 17:44:14 +02:00
ringabout
ecaccafa6c fixes #22790; use cast suppress AnyEnumConv warnings for enums withou… (#22813)
…t holes

fixes #22790
2023-10-11 17:18:54 +02:00
ringabout
9d7acd001f use lent for the return value of index accesses of tables (#22812)
ref https://forum.nim-lang.org/t/10525
2023-10-11 15:14:12 +02:00
ringabout
14d25eedfd suppress incorrect var T destructor warnings for newFinalizer in stdlib (#22810)
in `std/nre`
```nim
proc initRegex(pattern: string, flags: int, study = true): Regex =
  new(result, destroyRegex)
```
gives incorrect warnings like

```
C:\Users\blue\Documents\Nim\lib\impure\nre.nim(252, 6) Error: A custom '=destroy' hook which takes a 'var T' parameter is deprecated; it should take a 'T' parameter [Deprecated
```
2023-10-11 13:27:22 +02:00
ringabout
2cf214d6d4 allows cast int to bool/enum in VM (#22809)
Since they are integer types, by mean of allowing cast integer to enums
in VM, we can suppress some enum warnings in the stdlib in the unified
form, namely using a cast expression.
2023-10-11 12:06:42 +02:00
Juan M Gómez
bf72d87f24 adds support for noDecl in constructor (#22811)
Notice the test wouldnt link before
2023-10-11 08:28:00 +02:00
ringabout
81b2ae747e fixes #8893; guard against array access in renderer (#22807)
fixes #8893
2023-10-09 15:36:56 +02:00
Juan M Gómez
8ac466980f marking a field with noInit allows to skip constructor initialiser (#22802)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-10-08 23:51:44 +02:00
Juan M Gómez
c3774c8821 fixes nimsuggest false error on lifetime tracking hook fixes #22794 (#22805)
fixes #22794

Not sure if it's too much.
2023-10-08 20:22:35 +02:00
Matt Rixman
5bcea05caf Add getCursorPos() to std/terminal (#22749)
This would be handy for making terminal apps which display content below
the prompt (e.g. `fzf` does this).

Need to test it on windows before I remove "draft" status.

---------

Co-authored-by: Matt Rixman <MatrixManAtYrService@users.noreply.github.com>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-10-08 18:56:18 +02:00
ringabout
efa64aa49b fixes #22787; marks var section in the loop as reassign preventing cursor (#22800)
fixes #22787

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-10-07 07:43:39 +02:00
Levi Notik
f111009e5d Fix typo/grammar in exception tracking section (#22801)
I came across this sentence in the Nim Manual and couldn't make sense of
it. I believe this is the correct fix for the sentence.

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-10-07 07:43:17 +02:00
ringabout
476492583b remove the O(n*n) addUnique one from std (#22799)
It's not used in the compiler, besides, it doesn't seem to be a common
operation. Follows the discussion on the Discord.
2023-10-06 22:39:32 +02:00
ringabout
f2f0b3e25d fixes #22711; Check atomicArc for atomic destroy race condition (#22788)
fixes #22711

Per @elcritch's awesome solution
2023-10-04 19:41:39 +02:00
ringabout
f4a623dadf document atomicInc and atomicDec (#22789) 2023-10-04 16:00:41 +02:00
ringabout
1a6ca0c604 arraymancer switches to the offical URL (#22782) 2023-10-03 18:46:41 +08:00
Pylgos
db36765afd nimsuggest: Clear generic inst cache before partial recompilation (#22783)
fixes #19371
fixes #21093
fixes #22119
2023-10-03 10:22:31 +02:00
ringabout
5d5c39e745 fixes #22778 regression: contentLength implementation type mismatched (#22780)
fixes #22778
follow up https://github.com/nim-lang/Nim/pull/19835
2023-10-03 11:00:24 +08:00
ringabout
642ac0c1c3 fixes #22753; Nimsuggest segfault with invalid assignment to table (#22781)
fixes #22753

## Future work
We should turn all the error nodes into nodes of a nkError kind, which
could be a industrious task. But perhaps we can add a special treatment
for error nodes to make the transition smooth.
2023-10-02 14:45:04 -04:00
CMD
49df69334e Fix IndexDefect in asyncfile.readLine (#22774)
`readLine` proc in asyncfile module caused IndexDefect when it reached
EoF. Now it returns empty string instead.
2023-10-01 07:20:43 +02:00
Juan Carlos
b60f15e0dc copyFile with POSIX_FADV_SEQUENTIAL (#22776)
- Continuation of https://github.com/nim-lang/Nim/pull/22769
- See
https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fadvise.html
- The code was already there in `std/posix` since years ago. 3 line
diff.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-10-01 07:19:37 +02:00
daylin
c3b95cbd2c docs: add another switch example for nimscript (#22772)
I couldn't find any documentation on the syntax for --hint:X:on|off with
`nimscript` except in [this old forum
post](https://forum.nim-lang.org/t/8526#55236).
2023-09-30 14:53:09 +02:00
Ryan McConnell
b2ca6bedae Make typeRel behave to spec (#22261)
The goal of this PR is to make `typeRel` accurate to it's definition for
generics:
```
# 3) When used with two type classes, it will check whether the types
# matching the first type class (aOrig) are a strict subset of the types matching
# the other (f). This allows us to compare the signatures of generic procs in
# order to give preferrence to the most specific one:
```

I don't want this PR to break any code, and I want to preserve all of
Nims current behaviors. I think that making this more accurate will help
serve as ground work for the future. It may not be possible to not break
anything but this is my attempt.

So that it is understood, this code was part of another PR (#22143) but
that problem statement only needed this change by extension. It's more
organized to split two problems into two PRs and this issue, being
non-breaking, should be a more immediate improvement.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-30 06:34:14 +02:00
ringabout
7146307823 fixes #22554; makes newSeqWith use newSeqUninit (#22771)
fixes #22554
2023-09-30 06:32:27 +02:00
Juan Carlos
a38e3dcb1f copyFile with bufferSize instead of hardcoded value (#22769)
- `copyFile` allows to specify `bufferSize` instead of hardcoded wrong
value. Tiny diff.


# Performance

- 1200% Performance improvement.


# Check it yourself

Execute:

```bash
for i in $(seq 0 10); do
  bs=$((1024*2**$i))
  printf "%7s Kb\t" $bs
  timeout --foreground -sINT 2 dd bs=$bs if=/dev/zero of=/dev/null 2>&1 | sed -n 's/.* \([0-9.,]* [GM]B\/s\)/\1/p'
done
```

(This script can be ported to PowerShell for Windows I guess, it works
in Windows MinGW Bash anyways).


# Stats

- Hardcoded `8192` or `8000` Kb bufferSize gives `5` GB/s.
- Setting `262144` Kb bufferSize gives `65` GB/s (script suggestion).

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-30 06:31:28 +02:00
ringabout
5eeafbf550 fixes #22696; func strutils.join for non-strings uses proc $ which can have side effects (#22770)
fixes #22696
partially revert https://github.com/nim-lang/Nim/pull/16281

`join` calls `$` interally, which might introduce a sideeffect call.
2023-09-30 06:27:27 +02:00
Juan M Gómez
0c179db657 case macro now can be used inside generic. Fixes #20435 (#22752)
fixes #20435

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
Co-authored-by: Jake Leahy <jake@leahy.dev>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-30 06:27:02 +02:00
ringabout
a8d55fdec7 deprecates newSeqUninitialized replaced by newSeqUninit (#22739)
ref #19727
closes #22586

https://github.com/nim-lang/Nim/issues/22554 needs it to move on.
`newSeqUnsafe` can be introduced later.
2023-09-29 09:38:51 +02:00
ringabout
8761599aad fixes #22763; nimcache in nim.cfg uses the relative path to the config file (#22764)
fixes #22763
2023-09-28 18:09:58 +02:00
Juan M Gómez
4fffa0960f C++ Adds support for default arg using object construction syntax. Fixes a compiler crash (#22768)
`Foo()` below makes the compiler crash. 
```nim

proc makeBoo(a:cint = 10, b:cstring = "hello", foo: Foo = Foo()): Boo {.importcpp, constructor.}

```
2023-09-28 18:08:42 +02:00
ringabout
285cbcb6aa ref #19727; implement setLenUninit for seqsv2 (#22767)
ref #19727
2023-09-28 18:08:31 +02:00
Thiago
4bf0f846df Removed localStorage.hasKey binding (#22766)
Doesn't exists anymore.

Use `window.localStorage.getItem("key").isNil` instead

![Screenshot from 2023-09-28
07-22-41](https://github.com/nim-lang/Nim/assets/74574275/65d58921-58c7-4a81-9f3b-5faa3a79c4f2)
2023-09-28 11:30:04 +02:00
Juan Carlos
f0865fa696 Fix #21407 (#22759)
- Fix #21407

---------

Co-authored-by: Amjad Ben Hedhili <amjadhedhili@outlook.com>
2023-09-28 07:37:09 +02:00
Juan Carlos
a9e6660a74 Documentation only (#22760)
- Documentation only.
- Sometimes newbies try to use Valgrind with RefC etc.
2023-09-27 17:59:26 +02:00
ringabout
02ba28eda5 iNim switch to the official URL (#22762)
ref https://github.com/inim-repl/INim/pull/139
2023-09-27 14:35:41 +08:00
Juan Carlos
21218d743f Documentation only (#22761)
- Mention Bisect bot in Bisect documentation.
2023-09-27 05:49:17 +02:00
ringabout
a7a0cfe8eb fixes #10542; suppresses varargs conversion warnings (#22757)
fixes #10542
revives and close #20169
2023-09-26 14:05:18 +02:00
Jake Leahy
435f932088 Add test case for #15351 (#22754)
Closes #15351

Stumbled across the issue and found it now works
2023-09-26 17:40:18 +08:00
ringabout
46544f234d fixes stint CI (#22756) 2023-09-26 17:39:59 +08:00
ringabout
3979e83fcb fixes #22706; turn "unknown hint" into a hint (#22755)
fixes #22706
2023-09-25 17:51:30 +02:00
Amjad Ben Hedhili
f0bf94e531 Make newStringUninit available in the VM [backport] (#22748)
It's equivalent to `newString`.
2023-09-25 07:19:09 +02:00
Juan Carlos
5840101968 Update Bisect (#22750)
- Support multiple OS Bisects (Linux, Windows, MacOS).
- Install Valgrind only if needed to speed up non-Valgrind builds.
- Valgrind+MacOS bisect support.
- Show IR of OK repro code samples.
- YAML only, tiny diff.


#### New features

- Bisect bugs that only reproduce on Windows and OSX.


#### See also

- https://github.com/juancarlospaco/nimrun-action/pull/10
2023-09-25 11:21:09 +08:00
SirOlaf
1b0447c208 Add magic toOpenArrayChar (#22751)
Should help with stuff like the checksums package which only takes
`openArray[char]`

Co-authored-by: SirOlaf <>
2023-09-24 20:47:56 +02:00
Amjad Ben Hedhili
a6c281bd1d Fix newStringUninit not setting the '\0' terminator [backport] (#22746)
Causes problems when working with `cstring`s.
2023-09-23 17:08:24 +02:00
Amjad Ben Hedhili
eadd0d72cf Initialize newString in js [backport:1.6] (#22745)
```nim
echo newString(8)
```

results in:
```
D:\User\test.js:25
                  var code_33556944 = c_33556931.toString(16);
                                                 ^

TypeError: Cannot read properties of undefined (reading 'toString')
    at toJSStr (D:\User\test.js:25:50)
    at rawEcho (D:\User\test.js:70:16)
    at Object.<anonymous> (D:\User\test.js:101:1)
    at Module._compile (node:internal/modules/cjs/loader:1095:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1147:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:17:47

Node.js v17.0.1
Error: execution of an external program failed: '"C:\Program Files\nodejs\node.exe" --unhandled-rejections=strict D:\User\test.js'
```
2023-09-23 16:10:17 +02:00
Amjad Ben Hedhili
b10a809274 Make newStringUninit available on the js backend [backport] (#22743) 2023-09-23 11:39:11 +02:00
ringabout
c0838826c0 fixes #22519; DocGen does not work for std/times on JS backend (#22738)
fixes #22519
2023-09-22 11:38:30 +08:00
ringabout
a1b6fa9420 fixes #22246; generate __builtin_unreachable hints for case defaults (#22737)
fixes #22246
resurrects #22350
2023-09-21 19:47:29 +02:00
Juan M Gómez
c75cbdde70 moves addUnique to std/sequtils (#22734)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-21 13:56:00 +02:00
Juan Carlos
b289617013 Documentation only (#22735)
- Add Atomic ARC to Documentation. Documentation only, tiny diff.
2023-09-21 09:05:23 +02:00
ringabout
ed30692d29 fixes #22687; js backend - std/bitops/bitsliced throws compile error … (#22722)
…in typeMasked

fixes #22687
2023-09-21 00:35:48 +02:00
ringabout
d82bc0a29f items, pairs and friends now use unCheckedInc (#22729)
`{.push overflowChecks: off.}` works in backends. Though it could be
implemented as a magic function.

By inspecting the generated C code, the overflow check is eliminated in
the debug or release mode.


![image](https://github.com/nim-lang/Nim/assets/43030857/49c3dbf4-675e-414a-b972-b91cf218c9f8)

Likewise, the index checking is probably not needed.
2023-09-20 12:50:23 +02:00
Juan M Gómez
af617be67a removes references to this in the constructor section (#22730) 2023-09-20 12:02:55 +02:00
Juan M Gómez
fefde3a735 fixes compiler crash by preventing exportc on generics (#22731)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-20 08:19:29 +02:00
Juan M Gómez
5568ba0d9f constructor now uses result instead of this (#22724) 2023-09-19 21:16:55 +02:00
metagn
81756d1810 second test case haul for templates and generics (#22728)
closes #8390, closes #11726, closes #8446, closes #21221, closes #7461,
closes #7995
2023-09-19 15:26:26 +08:00
metagn
51cb493b22 make parseEnum skip type aliases for enum type sym (#22727)
fixes #22726
2023-09-19 09:14:55 +02:00
Amjad Ben Hedhili
b542be1e7d Fix capacity for const and shallow [backport] (#22705) 2023-09-18 22:57:30 +02:00
ringabout
2c5b94bbfd fixes #22692; ships ci/funs.sh (#22721)
fixes #22692
2023-09-18 22:57:03 +02:00
sls1005
dba9000609 Add descriptions and examples for rawProc and rawEnv (#22710)
Add descriptions for `rawProc` and `rawEnv`. See
<https://forum.nim-lang.org/t/10485> for more informations.

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
Co-authored-by: Juan Carlos <juancarlospaco@gmail.com>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-18 16:42:43 +02:00
litlighilit
741285b335 Update osfiles.nim, make moveFile consider permission on *nix (#22719)
see https://github.com/nim-lang/Nim/issues/22674
2023-09-18 13:15:17 +02:00
ringabout
63c2ea5566 fixes incorrect cint overflow in system (#22718)
fixes #22700
2023-09-18 10:00:46 +02:00
ringabout
deefbc420e fixes result requires explicit initialization on noReturn code (#22717)
fixes #21615; fixes #16735

It also partially fixes | #22673, though It still gives 'baseless'
warnings.
2023-09-18 08:28:40 +02:00
Juan M Gómez
bd857151d8 prevents declaring a constructor without importcpp fixes #22712 (#22715)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-18 08:26:21 +02:00
metagn
5f9038a5d7 make expressions opt in to symchoices (#22716)
refs #22605

Sym choice nodes are now only allowed to pass through semchecking if
contexts ask for them to (with `efAllowSymChoice`). Otherwise they are
resolved or treated as ambiguous. The contexts that can receive
symchoices in this PR are:

* Call operands and addresses and emulations of such, which will subject
them to overload resolution which will resolve them or fail.
* Type conversion operands only for routine symchoices for type
disambiguation syntax (like `(proc (x: int): int)(foo)`), which will
resolve them or fail.
* Proc parameter default values both at the declaration and during
generic instantiation, which undergo type narrowing and so will resolve
them or fail.

This means unless these contexts mess up sym choice nodes should never
leave the semchecking stage. This serves as a blueprint for future
improvements to intermediate symbol resolution.

Some tangential changes are also in this PR:

1. The `AmbiguousEnum` hint is removed, it was always disabled by
default and since #22606 it only started getting emitted after the
symchoice was soundly resolved.
2. Proc setter syntax (`a.b = c` becoming `` `b=`(a, c) ``) used to
fully type check the RHS before passing the transformed call node to
proc overloading. Now it just passes the original node directly so proc
overloading can deal with its typechecking.
2023-09-18 06:39:22 +02:00
SirOlaf
fcf4c1ae17 Fix #22713: Make size unknown for tyForward (#22714)
Close #22713

---------

Co-authored-by: SirOlaf <>
2023-09-17 20:03:43 +02:00
metagn
8836207a4e implement semgnrc for tuple and object type nodes (#22709)
fixes #22699
2023-09-16 09:16:12 +02:00
Juan M Gómez
cd0d0ca530 Document C++ Initializers (#22704)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-15 12:08:41 +02:00
Juan Carlos
ae0a3f65c6 Fix Bisect bot (#22703)
-
https://github.com/nim-lang/Nim/actions/runs/6187256704/job/16796720625#step:4:29
- https://github.com/nim-lang/Nim/issues/22699
2023-09-14 20:43:45 +02:00
Amjad Ben Hedhili
38b58239e8 followup of #22568 (#22690) 2023-09-14 17:38:33 +02:00
Juan M Gómez
96e1949610 implements RFC: [C++] Constructors as default initializers (#22694)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-14 17:37:30 +02:00
metagn
ac1804aba6 refactor semtempl ident declarations, some special word use (#22693)
`semtempl` is refactored to combine the uses of `getIdentNode`,
`onlyReplaceParams`, `isTemplParam` and most of `replaceIdentBySym` into
a single `getIdentReplaceParams` proc. This might fix possible problems
with injections of `nkAccQuoted`.

Some special word comparison in `ast` and `semtempl` are also made more
efficient.
2023-09-14 06:22:22 +02:00
Amjad Ben Hedhili
325341866f Make capacity work with refc [backport] (#22697)
followup of #19771.
2023-09-13 20:43:25 +02:00
Andreas Rumpf
8f5b90f886 produce better code for object constructions and 'result' [backport] (#22668) 2023-09-11 18:48:20 +02:00
Juan M Gómez
7e86cd6fa7 fixes #22680 Nim zero clear an object inherits C++ imported class when a proc return it (#22684) 2023-09-11 12:55:11 +02:00
ringabout
b1a8d6976f fixes the discVal register is used after free in vmgen (#22688)
follow up https://github.com/nim-lang/Nim/pull/11955
2023-09-11 10:54:41 +02:00
Amjad Ben Hedhili
fbb5ac512c Remove some unnecessary initialization in seq operations (#22677)
* `PrepareSeqAdd`
* `add`
* `setLen`
* `grow`

Merge after #21842.

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-09-10 17:36:49 +02:00
ringabout
f8f6a3c926 renderIr should print the actual return assign node (#22682)
follow up https://github.com/nim-lang/Nim/pull/10806

Eventually we need a new option to print high level IR. It's confusing
when I'm debugging the compiler without showing `return result = 1`
using the expandArc option.

For 
```nim
proc foo: int =
  return 2
```
It now outputs when expanding ARC IR
```nim
proc foo: int =
  return result = 2
```
2023-09-10 17:35:40 +02:00
Juan M Gómez
8032f252b2 fixes #22669 constructor pragma doesnt init Nim default fields (#22670)
fixes #22669 constructor pragma doesnt init Nim default fields

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-10 12:45:36 +02:00
Juan M Gómez
cd24195d44 fixes #22679 Nim zero clear an object contains C++ imported class when a proc return it (#22681) 2023-09-10 12:30:03 +02:00
ringabout
2ce9197d3a [minor] merge similar branches in vmgen (#22683) 2023-09-10 10:43:46 +02:00
Amjad Ben Hedhili
8853fb0775 Make newSeqOfCap not initialize memory. (#21842)
It's used in `newSeqUninitialized`.

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-09-09 21:11:45 +02:00
ringabout
5717a4843d fixes #22676; remove wMerge which is a noop for more than 8 years (#22678)
fixes #22676

If csource or CI forbids it, we can always fall back to adding it to the
nonPragmaWords list. I doubt it was used outside of the system since it
was used to implement & or something for magics.
2023-09-09 17:25:48 +02:00
Juan M Gómez
e6ca13ec85 Instantiates generics in the module that uses it (#22513)
Attempts to move the generic instantiation to the module that uses it.
This should decrease re-compilation times as the source module where the
generic lives doesnt need to be recompiled

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-09 10:34:20 +02:00
ringabout
5f13e15e0a fixes #22664; guard against potential seqs self assignments (#22671)
fixes #22664
2023-09-08 17:05:57 +02:00
Juan M Gómez
d45270bdf7 fixes #22662 Procs with constructor pragma doesn't initialize object's fields (#22665)
fixes #22662 Procs with constructor pragma doesn't initialize object's
fields

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-08 10:46:40 +02:00
SirOlaf
2a8c759df0 Fix #21742: Check generic alias depth before skip (#22443)
Close #21742

Checking if there's any side-effects and if just changing typeRel is
adequate for this issue before trying to look into related ones.

`skipBoth` is also not that great, it can lead to code that works
sometimes but fails when the proc is instantiated with branching
aliases. This is mostly an issue with error clarity though.

---------

Co-authored-by: SirOlaf <unknown>
Co-authored-by: SirOlaf <>
2023-09-08 06:50:39 +02:00
SirOlaf
ee4a219012 Fix #17509: Continue instead of return with unfinished generics (#22563)
Close #17509

Current knowledge:
- delaying cache fixes the issue
- changing return of `if inst.len < key.len:` in `searchInstTypes` to
`continue` fixes the issue. With return the broken types are also cached
over and over

Related issues are completely unaffected as of now, so there must be
something deeper.

I am also still trying to find the true cause, so feel free to ignore
for now

---------

Co-authored-by: SirOlaf <>
2023-09-07 05:46:45 +02:00
Amjad Ben Hedhili
a4df44d9fb Remove some unnecessary initialization in string operations (#22579)
* `prepareAdd`
* `toNimStr`
* `setLengthStrV2`
* `NimAsgnStrV2`
* `prepareMutation`
* Some cleanups
2023-09-07 05:45:54 +02:00
metagn
e5106d1ef3 minor refactoring, move some sym/type construction to semdata (#22654)
Move `symFromType` and `symNodeFromType` from `sem`, and `isSelf` and
`makeTypeDesc` from `concepts` into `semdata`.

`makeTypeDesc` was moved out from semdata [when the `concepts` module
was
added](6278b5d89a),
so its old position might have been intended. If not, `isSelf` can also
go in `ast`.
2023-09-07 05:33:01 +02:00
metagn
ad7c1c38ff run docs CI on compiler changes (#22656)
refs #22650

Docs CI cover standard library runnable examples that aren't covered by
the test suite and can be affected by compiler changes without knowing
2023-09-07 05:31:15 +02:00
metagn
ed9e3cba07 make getType nodes of generic insts have full inst type (#22655)
fixes #22639 for the third time

Nodes generated by `getType` for `tyGenericInst` types, instead of
having the original `tyGenericInst` type, will have the type of the last
child (due to the `mapTypeToAst` calls which set the type to the given
argument). This will cause subsequent `getType` calls to lose
information and think it's OK to use the sym of the instantiated type
rather than fully expand the generic instantiation.

To prevent this, update the type of the node from the `mapTypeToAst`
calls to the full generic instantiation type.
2023-09-07 05:30:37 +02:00
metagn
b9f039e0c3 switch back to main neo in CI (#22660)
refs https://github.com/andreaferretti/neo/pull/53
2023-09-06 12:37:51 +03:00
ringabout
009ce1e17e add union to packages (#22658) 2023-09-06 09:05:01 +02:00
metagn
90f87bcab7 fully revert generic inst sym change, test #22646 (#22653)
reverts #22642, reopens #22639, closes #22646, refs #22650, refs
https://github.com/alaviss/union/issues/51, refs #22652

The fallout is too much from #22642, we can come back to it if we can
account for all the affected code.
2023-09-06 05:45:07 +03:00
ringabout
eb91cf991a fixes #22619; don't lift cursor fields in the hook calls (#22638)
fixes https://github.com/nim-lang/Nim/issues/22619

It causes double free for closure iterators because cursor fields are
destroyed in the lifted destructors of `Env`.

Besides, according to the Nim manual

> In fact, cursor more generally prevents object
construction/destruction pairs and so can also be useful in other
contexts.

At least, destruction of cursor fields might cause troubles.


todo
- [x] tests
- [x] revert a certain old PR

---------

Co-authored-by: zerbina <100542850+zerbina@users.noreply.github.com>
2023-09-05 10:31:28 +02:00
metagn
6000cc8c0f fix sym of created generic instantiation type (#22642)
fixes #22639

A `tyGenericInst` has its last son as the instantiated body of the
original generic type. However this type keeps its original `sym` field
from the original generic types, which means the sym's type is
uninstantiated. This causes problems in the implementation of `getType`,
where it uses the `sym` fields of types to represent them in AST, the
relevant example for the issue being
[here](d13aab50cf/compiler/vmdeps.nim (L191))
called from
[here](d13aab50cf/compiler/vmdeps.nim (L143)).

To fix this, create a new symbol from the original symbol for the
instantiated body during the creation of `tyGenericInst`s with the
appropriate type. Normally `replaceTypeVarsS` would be used for this,
but here it seems to cause some recursion issue (immediately gives an
error like "cannot instantiate HSlice[T, U]"), so we directly set the
symbol's type to the instantiated type.

Avoiding recursion means we also cannot use `replaceTypeVarsN` for the
symbol AST, and the symbol not having any AST crashes the implementation
of `getType` again
[here](d13aab50cf/compiler/vmdeps.nim (L167)),
so the symbol AST is set to the original generic type AST for now which
is what it was before anyway.

Not sure about this because not sure why the recursion issue is
happening, putting it at the end of the proc doesn't help either. Also
not sure if the `cl.owner != nil and s.owner != cl.owner` condition from
`replaceTypeVarsS` is relevant here. This might also break some code if
it depended on the original generic type symbol being given.
2023-09-05 10:30:13 +02:00
Amjad Ben Hedhili
8f7aedb3d1 Add hasDefaultValue type trait (#22636)
Needed for #21842.
2023-09-04 23:18:58 +02:00
ringabout
3fbb078a3c update checkout to v4 (#22640)
ref https://github.com/actions/checkout/issues/1448

probably nodejs needs to be updated to 20.x
2023-09-04 23:09:27 +02:00
ringabout
d13aab50cf fixes branches interacting with break, raise etc. in strictdefs (#22627)
```nim
{.experimental: "strictdefs".}

type Test = object
  id: int

proc test(): Test =
  if true:
    return Test()
  else:
    return
echo test()
```

I will tackle https://github.com/nim-lang/Nim/issues/16735 and #21615 in
the following PR.


The old code just premises that in branches ended with returns, raise
statements etc. , all variables including the result variable are
initialized for that branch. It's true for noreturn statements. But it
is false for the result variable in a branch tailing with a return
statement, in which the result variable is not initialized. The solution
is not perfect for usages below branch statements with the result
variable uninitialized, but it should suffice for now, which gives a
proper warning.

It also fixes

```nim

{.experimental: "strictdefs".}

type Test = object
  id: int

proc foo {.noreturn.} = discard

proc test9(x: bool): Test =
  if x:
    foo()
  else:
    foo()
```
which gives a warning, but shouldn't
2023-09-04 14:36:45 +02:00
Andrey Makarov
c5495f40d5 docgen: add Pandoc footnotes (fixes #21080) (#22591)
This implements Pandoc Markdown-style footnotes,
that are compatible with Pandoc referencing syntax:

    Ref. [^ftn].

    [^ftn]: Block.

See https://pandoc.org/MANUAL.html#footnotes for more examples.
2023-09-03 16:09:36 +02:00
metagn
480e98c479 resolve unambiguous enum symchoices from local scope, error on rest (#22606)
fixes #22598, properly fixes #21887 and fixes test case issue number

When an enum field sym choice has to choose a type, check if its name is
ambiguous in the local scope, then check if the first symbol found in
the local scope is the first symbol in the sym choice. If so, choose
that symbol. Otherwise, give an ambiguous identifier error.

The dependence on the local scope implies this will always give
ambiguity errors for unpicked enum symchoices from generics and
templates and macros from other scopes. We can change `not
isAmbiguous(...) and foundSym == first` to `not (isAmbiguous(...) and
foundSym == first)` to make it so they never give ambiguity errors, and
always pick the first symbol in the symchoice. I can do this if this is
preferred, but no code from CI seems affected.
2023-09-03 13:59:03 +02:00
SirOlaf
d2f36c071b Exclude block from endsInNoReturn, fix regression (#22632)
Co-authored-by: SirOlaf <>
2023-09-02 20:42:40 +02:00
metagn
bd6adbcc9d fix isNil folding for compile time closures (#22574)
fixes #20543
2023-09-02 10:32:46 +02:00
Pylgos
9f1fe8a2da Fix the problem where instances of generic objects with sendable pragmas are not being cached (#22622)
remove `tfSendable` from `eqTypeFlags`
2023-09-02 06:00:26 +02:00
metagn
2542dc09c8 use dummy dest for void branches to fix noreturn in VM (#22617)
fixes #22216
2023-09-01 15:38:25 +02:00
metagn
6738f44af3 unify explicit generic param semchecking in calls (#22618)
fixes #9040
2023-09-01 15:37:16 +02:00
Juan M Gómez
0c6e13806d fixes internal error: no generic body fixes #1500 (#22580)
* fixes internal error: no generic body fixes #1500

* adds guard

* adds guard

* removes unnecessary test

* refactor: extracts containsGenericInvocationWithForward
2023-09-01 13:42:47 +02:00
metagn
f1789cc465 resolve local symbols in generic type call RHS (#22610)
resolve local symbols in generic type call

fixes #14509
2023-09-01 09:00:15 +02:00
metagn
53d9fb259f don't update const symbol on const section re-sems (#22609)
fixes #19849
2023-09-01 08:59:48 +02:00
ringabout
affd3f7858 fixes #22613; Default value does not work with object's discriminator (#22614)
* fixes #22613; Default value does not work with object's discriminator

fixes #22613

* merge branches

* add a test case

* fixes status

* remove outdated comments

* move collectBranchFields into the global scope
2023-09-01 08:55:19 +02:00
SirOlaf
3b206ed988 Fix #22604: Make endsInNoReturn traverse the tree (#22612)
* Rewrite endsInNoReturn

* Handle `try` stmt again and add tests

* Fix unreachable code warning

* Remove unreachable code in semexprs again

* Check `it.len` before skip

* Move import of assertions

---------

Co-authored-by: SirOlaf <>
2023-09-01 06:41:39 +02:00
metagn
ba158d73dc type annotations for variable tuple unpacking, better error messages (#22611)
* type annotations for variable tuple unpacking, better error messages

closes #17989, closes https://github.com/nim-lang/RFCs/issues/339

* update grammar

* fix test
2023-09-01 06:26:53 +02:00
ringabout
b3912c25d3 remove outdated config (#22603) 2023-08-31 18:01:29 +02:00
ringabout
5387b30211 closes #22600; adds a test case (#22602)
closes #22600
2023-08-31 22:30:19 +08:00
ringabout
5bd1afc3f9 fixes #17197; fixes #22560; fixes the dest of newSeqOfCap in refc (#22594) 2023-08-31 19:04:32 +08:00
ringabout
dfb3a88cc3 fixes yaml tests (#22595) 2023-08-31 15:26:09 +08:00
metagn
2e4e2f8f50 handle typedesc params in VM (#22581)
* handle typedesc params in VM

fixes #15760

* add test

* fix getType(typedesc) test
2023-08-30 07:23:14 +02:00
Juan M Gómez
d7634c1bd4 fixes an issue where sometimes wasMoved produced bad codegen for cpp (#22587) 2023-08-30 07:22:36 +02:00
ringabout
a7a0105d8c deprecate std/threadpool; use malebolgia, weave, nim-taskpool instead (#22576)
* deprecate `std/threadpool`; use `malebolgia` instead

* Apply suggestions from code review

* Apply suggestions from code review

* change the URL of inim
2023-08-29 15:00:13 +02:00
metagn
b6cea7b599 clearer error for different size int/float cast in VM (#22582)
refs #16547
2023-08-29 14:59:49 +02:00
ringabout
e53c66ef39 fixes #22555; implements newStringUninit (#22572)
* fixes newStringUninitialized; implement `newStringUninitialized`

* add a simple test case

* adds a changelog

* Update lib/system.nim

* Apply suggestions from code review

rename to newStringUninit
2023-08-29 13:29:42 +02:00
ringabout
1fcb53cded fixes broken nightlies; follow up #22544 (#22585)
ref https://github.com/nim-lang/nightlies/actions/runs/5970369118/job/16197865657

> /home/runner/work/nightlies/nightlies/nim/lib/pure/os.nim(678, 30) Error: getApplOpenBsd() can raise an unlisted exception: ref OSError
2023-08-29 10:40:19 +02:00
ringabout
d8ffc6a75e minor style changes in the compiler (#22584)
* minor style changes in the compiler

* use raiseAssert
2023-08-29 13:59:51 +08:00
metagn
6b955ac4af properly fold constants for dynlib pragma (#22575)
fixes #12929
2023-08-28 21:41:18 +02:00
metagn
3de8d75513 correct logic for qualified symbol in templates (#22577)
* correct logic for qualified symbol in templates

fixes #19865

* add test
2023-08-28 21:40:46 +02:00
metagn
94454addb2 define toList procs after add for lists [backport] (#22573)
fixes #22543
2023-08-28 15:09:43 +02:00
ringabout
2e7c8a339f newStringOfCap now won't initialize all elements anymore (#22568)
newStringOfCap nows won't initialize all elements anymore
2023-08-28 10:43:58 +02:00
ringabout
306b9aca48 initCandidate and friends now return values (#22570)
* `initCandidate` and friends now return values

* fixes semexprs.nim

* fixes semcall.nim

* Update compiler/semcall.nim
2023-08-28 15:57:24 +08:00
Bung
094a29eb31 add test case for #19095 (#22566) 2023-08-28 12:31:16 +08:00
Bung
100eb6820c close #9334 (#22565) 2023-08-27 22:56:50 +08:00
Bung
0b78b7f595 fix #22548;environment misses for type reference in iterator access n… (#22559)
* fix #22548;environment misses for type reference in iterator access nested in closure

* fix #21737

* Update lambdalifting.nim

* remove containsCallKinds

* simplify
2023-08-27 14:29:24 +02:00
metagn
c19fd69b69 test case haul for old generic/template/macro issues (#22564)
* test case haul for old generic/template/macro issues

closes #12582, closes #19552, closes #2465, closes #4596, closes #15246,
closes #12683, closes #7889, closes #4547, closes #12415, closes #2002,
closes #1771, closes #5121

The test for #5648 is also moved into its own test
from `types/tissues_types` due to not being joinable.

* fix template gensym test
2023-08-27 11:27:47 +02:00
Juan Carlos
a108a451c5 Improve compiler cli args (#22509)
* .

* Fix cli args out of range with descriptive error instead of crash

* https://github.com/nim-lang/Nim/pull/22509#issuecomment-1692259451
2023-08-25 22:55:17 +02:00
metagn
1cc4d3f622 fix generic param substitution in templates (#22535)
* fix generic param substitution in templates

fixes #13527, fixes #17240, fixes #6340, fixes #20033, fixes #19576, fixes #19076

* fix bare except in test, test updated packages in CI
2023-08-25 21:08:47 +02:00
ringabout
d677ed31e5 follow up #22549 (#22551) 2023-08-25 06:48:08 +02:00
Amjad Ben Hedhili
fc6a388780 Add cursor to lists iterator variables (#22531)
* followup #21507
2023-08-24 20:57:49 +02:00
ringabout
1013378854 fixes a strictdef ten years long vintage bug, which counts the same thing twice (#22549)
fixes a strictdef ten years long vintage bug
2023-08-24 20:56:58 +02:00
Jacek Sieka
bc9785c08d Fix getAppFilename exception handling (#22544)
* Fix `getAppFilename` exception handling

avoid platform-dependendent error handling strategies

* more fixes

* space
2023-08-24 15:41:29 +02:00
ringabout
c56a712e7d fixes #22541; peg matchLen can raise an unlisted exception: Exception (#22545)
The `mopProc` is a recursive function.
2023-08-24 12:59:45 +02:00
metagn
53d43e9671 round out tuple unpacking assignment, support underscores (#22537)
* round out tuple unpacking assignment, support underscores

fixes #18710

* fix test messages

* use discard instead of continue

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-08-24 06:11:48 +02:00
metagn
03f267c801 make jsffi properly gensym (#22539)
fixes #21208
2023-08-23 19:25:26 +02:00
metagn
4f891aa50c don't render underscore identifiers with id (#22538) 2023-08-23 13:43:02 +02:00
SirOlaf
3de75ffc02 Fix #21532: Check if template return is untyped (#22517)
* Don't ignore return in semTemplateDef

* Add test

---------

Co-authored-by: SirOlaf <>
2023-08-23 06:18:35 +02:00
Andreas Rumpf
6b04d0395a allow tuples and procs in 'toTask' + minor things (#22530) 2023-08-22 21:01:08 +02:00
Hamid Bluri
a26ccb3476 fix #22492 (#22511)
* fix #22492

* Update nimdoc.css

remove scroll-y

* Update nimdoc.out.css

* Update nimdoc.css

* make it sticky again

* Update nimdoc.out.css

* danm sticky, use fixed

* Update nimdoc.out.css

* fix margin

* Update nimdoc.out.css

* make search input react to any change (not just keyboard events) according to https://github.com/nim-lang/Nim/pull/22511#issuecomment-1685218787
2023-08-22 18:31:21 +02:00
metagn
602f537eb2 allow non-pragma special words as user pragmas (#22526)
allow non-pragma special words as macro pragmas

fixes #22525
2023-08-21 20:08:57 +02:00
metagn
942f846f04 fix getNullValue for cstring in VM, make other VM code aware of nil cstring (#22527)
* fix getNullValue for cstring in VM

fixes #22524

* very ugly fixes, but fix #15730

* nil cstring len works, more test lines

* fix high
2023-08-21 20:08:00 +02:00
metagn
a4781dc4bc use old typeinfo generation for hot code reloading (#22518)
* use old typeinfo generation for hot code reloading

* at least test hello world compilation on orc
2023-08-20 06:30:36 +02:00
SirOlaf
c0ecdb01a9 Fix #21722 (#22512)
* Keep return in mind for sink
* Keep track of return using bool instead of mode
* Update compiler/injectdestructors.nim
* Add back IsReturn

---------

Co-authored-by: SirOlaf <>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-08-19 21:04:25 +02:00
PhilippMDoerner
93407096db #22514 expand testament option docs (#22516)
* #22514 Expand docs on testament spec options

The file, line and column options of testament are not in the docs,
but can be very important to know.
They allow you to specify where a compile-time error originated from.

Particularly given that testament assumes the origin to always be
the test-file, this is important to know.

* #22514 Specify nimout relevance a bit more

* #22514 Fix slightly erroneous doc-link

* #22514 Add example

* #22514 Add some docs on ccodecheck
2023-08-19 17:25:38 +02:00
Amjad Ben Hedhili
d77ada5bdf Markdown code blocks migration part 9 (#22506)
* Markdown code blocks migration part 9

* fix [skip ci]
2023-08-19 15:14:56 +02:00
Nan Xiao
6eb722c47d replace getOpt with getopt (#22515) 2023-08-19 15:05:17 +02:00
Juan Carlos
c44c8ddb44 Remove Deprecated Babel (#22507) 2023-08-19 07:05:06 +02:00
Alberto Torres
20cbdc2741 Fix #22366 by making nimlf_/nimln_ part of the same line (#22503)
Fix #22366 by making nimlf_/nimln_ part of the same line so the debugger doesn't advance to the next line before executing it
2023-08-18 21:13:27 +02:00
Tomohiro
eb83d20d0d Add staticFileExists and staticDirExists (#22278) 2023-08-18 16:47:47 +02:00
ringabout
7fababd583 make float32 literals stringifying behave in JS the same as in C (#22500) 2023-08-17 18:52:38 +02:00
metagn
98c39e8e57 cascade tyFromExpr in type conversions in generic bodies (#22499)
fixes #22490, fixes #22491, adapts #22029 to type conversions
2023-08-17 18:52:28 +02:00
ringabout
fede757238 bump checksums (#22497) 2023-08-17 16:48:28 +02:00
Nan Xiao
019b488e1f fixes syncio document (#22498) 2023-08-17 20:26:33 +08:00
ringabout
2e3d9cdbee fixes #22441; build documentation for more modules in the checksums (#22453)
Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
2023-08-17 13:54:00 +02:00
ringabout
ee817557ec close #22748; cursorinference + -d:nimNoLentIterators results in err… (#22495)
closed #22748; cursorinference + -d:nimNoLentIterators results in erroneous recursion
2023-08-17 13:33:19 +02:00
Juan M Gómez
60307cc373 updates manual with codegenDecl on params docs (#22333)
* documents member

* Update doc/manual_experimental.md

Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
2023-08-17 12:20:22 +02:00
Amjad Ben Hedhili
299394d21a Fix seq.capacity (#22488) 2023-08-17 06:38:15 +02:00
ringabout
940b1607b8 fixes #22357; don't sink elements of var tuple cursors (#22486) 2023-08-16 13:46:44 +02:00
ringabout
ade75a1483 fixes #22481; fixes card undefined misalignment behavior (#22484)
* fixes `card` undefined misalignment behavior

* Update lib/system/sets.nim

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-08-15 23:31:44 +02:00
Jason Beetham
6c4e7835bf When in object handles procedure call again, fixes #22474 (#22480)
Ping @narimiran please backport to the 2.0 line.
2023-08-15 17:48:31 +02:00
ringabout
9296b45de4 update test command of important packages (#22485) 2023-08-15 21:42:26 +08:00
Andrey Makarov
a660c17d30 Markdown code blocks migration part 8 (#22478) 2023-08-15 06:27:36 +02:00
Emery Hemingway
1927ae72d0 Add Linux constant SO_BINDTODEVICE (#22468) 2023-08-14 21:00:48 +02:00
ringabout
09d0fda7fd fixes #22469; generates nimTestErrorFlag for top level statements (#22472)
fixes #22469; generates `nimTestErrorFlag` for top level statements
2023-08-14 13:08:01 +02:00
ringabout
7bb2462d06 fixes CI (#22471)
Revert "fixes bareExcept warnings; catch specific exceptions (#21119)"

This reverts commit 9207d77848.
2023-08-14 15:04:02 +08:00
Nan Xiao
9bf605cf98 fixes syncio document (#22467) 2023-08-14 08:44:50 +08:00
ringabout
9207d77848 fixes bareExcept warnings; catch specific exceptions (#21119)
* fixes bareExcept warnings; catch specific exceptions

* Update lib/pure/coro.nim
2023-08-13 00:02:36 +02:00
ringabout
4c89223171 relax the parameter of ensureMove; allow let statements (#22466)
* relax the parameter of `ensureMove`; allow let statements

* fixes the test
2023-08-12 13:23:54 +02:00
Juan M Gómez
f642c9dbf1 documents member (#22460)
* documents member

* Apply suggestions from code review

Co-authored-by: Juan Carlos <juancarlospaco@gmail.com>

* Update doc/manual_experimental.md

* Update doc/manual_experimental.md

* Update doc/manual_experimental.md

* Update doc/manual_experimental.md

* Update doc/manual_experimental.md

* Update doc/manual_experimental.md

---------

Co-authored-by: Juan Carlos <juancarlospaco@gmail.com>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-08-12 10:37:52 +02:00
ringabout
23f3f9ae2c better initialization patterns for seminst (#22456)
* better initialization patterns for seminst

* Update compiler/seminst.nim

* Update compiler/seminst.nim
2023-08-12 08:30:17 +08:00
ringabout
3f7e1d7daa replace doAssert false with raiseAssert in lib, which works better with strictdefs (#22458) 2023-08-11 18:24:46 +02:00
Pylgos
48da472dd2 fix #22448 Remove structuredErrorHook temporary in tryConstExpr (#22450)
* fix #22448

* add test
2023-08-11 18:23:09 +02:00
ringabout
469c9cfab4 unpublic the sons field of PType; the precursor to PType refactorings (#22446)
* unpublic the sons field of PType

* tiny fixes

* fixes an omittance

* fixes IC

* fixes
2023-08-11 22:18:24 +08:00
ringabout
72bc72bf9e refactor result = default(...) into object construction (#22455) 2023-08-11 22:16:58 +08:00
Bung
277393d0f1 close #17045;Compiler crash when a tuple iterator with when nimvm is … (#22452)
close #17045;Compiler crash when a tuple iterator with when nimvm is iterated in a closure iterator
2023-08-11 19:11:47 +08:00
Bung
3bb75f2dea close #18103 internal error: inconsistent environment type (#22451) 2023-08-11 18:50:31 +08:00
ringabout
9fed58d5a0 modernize lambdalifting (#22449)
* modernize lambdalifting

* follow @beef331's suggestions
2023-08-11 17:08:51 +08:00
ringabout
0bf286583a initNodeTable and friends now return (#22444) 2023-08-11 12:50:41 +08:00
ringabout
faf1c91e6a fixes move sideeffects issues [backport] (#22439)
* fixes move sideeffects issues [backport]

* fix openarray

* fixes openarray
2023-08-10 18:04:29 +02:00
ringabout
7be2e2bef5 replaces doAssert false with raiseAssert for unreachable branches, which works better with strictdefs (#22436)
replaces `doAssert false` with `raiseAssert`, which works better with strictdefs
2023-08-10 14:26:40 +02:00
ringabout
8523b543d6 getTemp and friends now return TLoc as requested (#22440)
getTemp and friends now return `TLoc`
2023-08-10 14:17:15 +02:00
Juan M Gómez
8625e71250 adds support for functor in member (#22433)
* adds support for functor in member

* improves functor test
2023-08-10 14:15:23 +02:00
ringabout
05f7c4f79d fixes a typo (#22437) 2023-08-10 16:41:24 +08:00
Bung
2aab03bdfb fix #19304 Borrowing std/times.format causes Error: illformed AST (#20659)
* fix #19304 Borrowing std/times.format causes Error: illformed AST

* follow suggestions

* mitigate for #4121

* improve error message
2023-08-10 16:26:23 +08:00
ringabout
a6610745d8 initLocExpr and friends now return TLoc (#22434)
`initLocExpr` and friends now return TLoc
2023-08-10 07:57:34 +02:00
SirOlaf
baf350493b Fix #21760 (#22422)
* Remove call-specific replaceTypeVarsN

* Run for all call kinds and ignore typedesc

* Testcase

---------

Co-authored-by: SirOlaf <>
2023-08-10 07:56:09 +02:00
ringabout
fa58d23080 modernize sempass2; initEffects now returns TEffects (#22435) 2023-08-10 11:29:42 +08:00
Juan M Gómez
6ec1c80779 makes asmnostackframe work with cpp member #22411 (#22429) 2023-08-09 20:57:52 +02:00
ringabout
91c3221855 simplify isAtom condition (#22430) 2023-08-09 20:57:13 +02:00
Bung
46e94c83d4 Fix #5780 (#22428)
* fix #5780
2023-08-09 23:17:08 +08:00
ringabout
5ec81d076b fixes cascades of out parameters, which produces wrong ProveInit warnings (#22413) 2023-08-09 13:49:30 +02:00
Bung
d53a89e453 fix #12938 index type of array in type section without static (#20529)
* fix #12938 nim compiler assertion fail when literal integer is passed as template argument for array size

* use new flag tfImplicitStatic

* fix

* fix #14193

* correct tfUnresolved add condition

* clean test
2023-08-09 12:45:43 +02:00
ringabout
5334dc921f fixes #22419; async/closure environment does not align local variables (#22425)
* fixes #22419; async/closure environment does not align local variables

* Apply suggestions from code review

* Update tests/align/talign.nim

Co-authored-by: Jacek Sieka <arnetheduck@gmail.com>

* apply code review

* update tests

---------

Co-authored-by: Jacek Sieka <arnetheduck@gmail.com>
2023-08-09 12:43:17 +02:00
Bung
989da75b84 fix #20891 Illegal capture error of env its self (#22414)
* fix #20891 Illegal capture error of env its self

* fix innerClosure too earlier, make condition shorter
2023-08-09 09:43:39 +02:00
ringabout
c622e58db9 make the name of procs consistent with the name forwards (#22424)
It seems that `--stylecheck:error` acts up when the name forwards is involved.


```nim
proc thisOne*(x: var int)
proc thisone(x: var int) = x = 1
```

It cannot understand this at all.
2023-08-09 13:18:50 +08:00
ringabout
28b2e429ef refactors initSrcGen and initTokRender into returning objects (#22421) 2023-08-09 06:40:17 +02:00
ringabout
ce079a8da4 modernize jsgen; clean up some leftovers (#22423) 2023-08-09 06:33:19 +02:00
metagn
3aaef9e4cf block ambiguous type conversion dotcalls in generics (#22375)
fixes #22373
2023-08-09 06:12:14 +02:00
ringabout
d136af0122 modernize lineinfos; it seems that array access hinders strict def analysis like field access (#22420)
modernize lineinfos; array access hinders strict def analysis like field access

A bug ?

```nim
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
  result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept}
  result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
  result[1] = result[2] - {warnProveField, warnProveIndex,
    warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
    hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin, hintPerformance}
  result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf,
    hintProcessing, hintPattern, hintExecuting, hintLinking, hintCC}
```
2023-08-09 08:18:47 +08:00
ringabout
73e661d01b modernize compiler/reorder, which exposes yet another strictdefs bug (#22415)
```nim
{.experimental: "strictdefs".}

type
  NodeKind = enum
    nkImportStmt
    nkStmtList
    nkNone

  PNode = ref object
    kind: NodeKind

proc hasImportStmt(n: PNode): bool =
  # Checks if the node is an import statement or
  # i it contains one
  case n.kind
  of nkImportStmt:
    return true
  of nkStmtList:
    if false:
      return true
  else:
    result = false

var n = PNode()
echo hasImportStmt(n)
```
It compiles without warnings, but shouldn't. As a contrast, 

```nim
{.experimental: "strictdefs".}

type
  NodeKind = enum
    nkImportStmt
    nkStmtList
    nkNone

  PNode = ref object
    kind: NodeKind

proc hasImportStmt(n: PNode): bool =
  # Checks if the node is an import statement or
  # i it contains one
  case n.kind
  of nkImportStmt:
    result = true
  of nkStmtList:
    if false:
      return true
  else:
    result = false

var n = PNode()
echo hasImportStmt(n)
```
This gives a proper warning.
2023-08-08 21:12:54 +08:00
ringabout
10a6e4c236 clean up gc:arc or gc:orc in docs and in error messages (#22408)
* clean up gc:arc/orc in docs

* in error messages
2023-08-08 05:55:18 -04:00
ringabout
bf5d173bc6 fixes LineTooLong hints on old compilers (#22412)
* fixes LineTooLong hints on old compilers

* fixes config/nim.cfg
2023-08-08 17:53:21 +08:00
ringabout
4c6be40b34 modernize compiler/filter_tmpl.nim (#22407) 2023-08-08 16:08:16 +08:00
Bung
37d8f32ae9 fix #18823 Passing Natural to bitops.BitsRange[T] parameter in generi… (#20683)
* fix #18823 Passing Natural to bitops.BitsRange[T] parameter in generic proc is compile error
2023-08-08 16:06:47 +08:00
ringabout
47d06d3d4c fixes #22387; Undefined behavior when with hash(...) (#22404)
* fixes #22387; Undefined behavior when with hash(...)

* fixes vm

* fixes nimscript
2023-08-08 13:42:08 +08:00
Bung
0219c5a607 fix #22287 nimlf_ undefined error (#22382) 2023-08-08 06:13:14 +02:00
ringabout
b4b555d8d1 tiny change on action.nim (#22405) 2023-08-08 11:13:38 +08:00
ringabout
260b4236fc use out parameters for getTemp (#22399) 2023-08-07 10:11:59 +02:00
Juan M Gómez
b5b4b48c94 [C++] Member pragma RFC (https://github.com/nim-lang/RFCs/issues/530) (#22272)
* [C++] Member pragma RFC #530
rebase devel

* changes the test so `echo` is not used before Nim is init

* rebase devel

* fixes Error: use explicit initialization of X for clarity [Uninit]
2023-08-07 10:11:00 +02:00
Bung
fe9ae2c69a nimIoselector option (#22395)
* selectors.nim: Add define to select event loop implementation

* rename to nimIoselector

---------

Co-authored-by: Jan Pobrislo <ccx@webprojekty.cz>
2023-08-07 10:09:35 +02:00
ringabout
614a18cd05 Delete parse directory, which was pushed wrongly before [backport] (#22401)
Delete parse directory
2023-08-07 15:49:30 +08:00
ringabout
26eb0a944f a bit modern code for depends (#22400)
* a bit modern code for depends

* simplify
2023-08-07 15:40:39 +08:00
ringabout
e7b4c7cddb unify starting blank lines in the experimental manual (#22396)
unify starting blank lines in the experimental manal
2023-08-06 17:59:43 +02:00
ringabout
93ced31353 use strictdefs for compiler (#22365)
* wip; use strictdefs for compiler

* checkpoint

* complete the chores

* more fixes

* first phase cleanup

* Update compiler/bitsets.nim

* cleanup
2023-08-06 14:26:21 +02:00
konsumlamm
53586d1f32 Fix some jsgen bugs (#22330)
Fix `succ`, `pred`
Fix `genRangeChck` for unsigned ints
Fix typo in `dec`
2023-08-06 14:24:35 +02:00
SirOlaf
67122a9cb6 Let inferGenericTypes continue if a param is already bound (#22384)
* Play with typeRel

* Temp solution: Fixup call's param types

* Test result type with two generic params

* Asserts

* Tiny cleanup

* Skip sink

* Ignore proc

* Use changeType

* Remove conversion

* Remove last bits of conversion

* Flag

---------

Co-authored-by: SirOlaf <>
2023-08-06 14:23:00 +02:00
Bung
d2b197bdcd Stick search result (#22394)
* nimdoc: stick search result inside browser viewport

* fix nimdoc.out.css

---------

Co-authored-by: Locria Cyber <74560659+locriacyber@users.noreply.github.com>
2023-08-06 19:07:36 +08:00
Bung
f18e4c4050 fix set op related to {sfGlobal, sfPure} (#22393) 2023-08-06 19:07:01 +08:00
Bung
95c751a9e4 fix #15005; [ARC] Global variable declared in a block is destroyed too… (#22388)
* fix #15005 [ARC] Global variable declared in a block is destroyed too early
2023-08-06 15:46:43 +08:00
Bung
137d608d7d add test for #3907 (#21069)
* add test for #3907
2023-08-06 15:21:24 +08:00
ringabout
b2c3b8f931 introduces online bisecting (#22390)
* introduces online bisecting

* Update .github/ISSUE_TEMPLATE/bug_report.yml
2023-08-06 08:52:17 +08:00
Daniel Belmes
7bf7496557 fix server caching issue causing Theme failures (#22378)
* fix server caching issue causing Theme failures

* Fix tester to ignore version cache param

* fix case of people using -d:nimTestsNimdocFixup

* rsttester needed the same fix
2023-08-06 02:50:47 +08:00
norrath-hero-cn
e0396900ed Prevent early destruction of gFuns, fixes AddressSanitizer: heap-use-after-free (#22386)
Prevent destruction of gFuns before callClosures
2023-08-05 19:38:32 +02:00
Andreas Rumpf
9872453365 destructors: better docs [backport:2.0] (#22391) 2023-08-05 19:35:37 +02:00
konsumlamm
e15e19308e Revert adding generic V: Ordinal parameter to succ, pred, inc, dec (#22328)
* Use `int` in `digitsutils`, `dragonbox`, `schubfach`

* Fix error message
2023-08-06 00:38:46 +08:00
Andreas Rumpf
873eaa3f65 compiler/llstream: modern code for llstream (#22385) 2023-08-04 22:52:31 +02:00
Tomohiro
db435a4a79 Fix searchExtPos so that it returns -1 when the path is not a file ext (#22245)
* Fix searchExtPos so that it returns -1 when the path is not a file ext

* fix comparision expression

* Remove splitDrive from searchExtPos
2023-08-04 20:00:43 +02:00
norrath-hero-cn
73a29d72e3 fixes AddressSanitizer: global-buffer-overflow in getAppFilename on windows 10 (#22380)
fixes AddressSanitizer: global-buffer-overflow
2023-08-04 19:59:05 +02:00
Bung
26f183043f fix #20883 Unspecified generic on default value segfaults the compiler (#21172)
* fix #20883 Unspecified generic on default value segfaults the compiler

* fallback to isGeneric

* change to closer error

* Update t20883.nim
2023-08-04 13:35:43 +02:00
Jake Leahy
3efabd3ec6 Fix crash when using uninstantiated generic (#22379)
* Add test case

* Add in a bounds check when accessing generic types

Removes idnex out of bounds exception when comparing a generic that isn't fully instantiated
2023-08-04 12:21:36 +02:00
ringabout
7c2a2c8dc8 fixes a typo in the manual (#22383)
ref 0d3bde95f5 (commitcomment-122093273)
2023-08-04 18:00:00 +08:00
ringabout
fb7acd6600 follow up #22322; fixes changelog (#22381) 2023-08-04 09:08:41 +02:00
konsumlamm
d37b620757 Make repr(HSlice) always available (#22332)
Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-08-04 05:29:48 +02:00
awr1
14bc3f3268 Allow libffi to work via koch boot (#22322)
* Divert libffi from nimble path, impl into koch

* Typo in koch

* Update options.nim comment

* Fix CI Test

* Update changelog

* Clarify libffi nimble comment

* Future pending changelog

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-08-03 23:06:30 +02:00
SirOlaf
8d8d75706c Add experimental inferGenericTypes switch (#22317)
* Infer generic bindings

* Simple test

* Add t

* Allow it to work for templates too

* Fix some builds by putting bindings in a template

* Fix builtins

* Slightly more exotic seq test

* Test value-based generics using array

* Pass expectedType into buildBindings

* Put buildBindings into a proc

* Manual entry

* Remove leftover `

* Improve language used in the manual

* Experimental flag and fix basic constructors

* Tiny commend cleanup

* Move to experimental manual

* Use 'kind' so tuples continue to fail like before

* Explicitly disallow tuples

* Table test and document tuples

* Test type reduction

* Disable inferGenericTypes check for CI tests

* Remove tuple info in manual

* Always reduce types. Testing CI

* Fixes

* Ignore tyGenericInst

* Prevent binding already bound generic params

* tyUncheckedArray

* Few more types

* Update manual and check for flag again

* Update tests/generics/treturn_inference.nim

* var candidate, remove flag check again for CI

* Enable check once more

---------

Co-authored-by: SirOlaf <>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-08-03 22:49:52 +02:00
Bung
6b913b4741 Revert "fix #22173 sink paramers not moved into closure (refc) (#22… (#22376)
Revert "fix #22173 `sink` paramers not moved into closure (refc) (#22359)"

This reverts commit b40da812f7.
2023-08-03 19:56:05 +02:00
Bung
b40da812f7 fix #22173 sink paramers not moved into closure (refc) (#22359)
* use genRefAssign when assign to sink string

* add test case
2023-08-02 14:08:51 +02:00
ringabout
825a0e7df4 fixes #22362; Compiler crashes with staticBoundsCheck on (#22363) 2023-08-02 11:00:34 +02:00
ringabout
f3a7622514 fixes #22360; compare with the half of randMax (#22361)
* fixes #22360; compare with the half of randMax

* add a test
2023-08-02 10:58:29 +02:00
Michal Maršálek
da368885da Fix the position of "Grey" in colors.nim (#22358)
Update the position of "Grey"
2023-08-01 20:56:38 +02:00
ringabout
1d2c27d2e6 bump the devel version to 211 (#22356) 2023-08-01 16:48:52 +02:00
ringabout
a23e53b490 fixes #22262; fixes -d:useMalloc broken with --mm:none and --threads on (#22355)
* fixes #22262; -d:useMalloc broken with --mm:none and threads on

* fixes
2023-08-01 15:18:08 +02:00
546 changed files with 17423 additions and 5248 deletions

View File

@@ -71,5 +71,6 @@ body:
which should give more context on a compiler crash.
- If it's a regression, you can help us by identifying which version introduced the bug,
see [Bisecting for regressions](https://nim-lang.github.io/Nim/intern.html#bisecting-for-regressions),
or at least try known past releases (eg `choosenim 1.2.0`).
or at least try known past releases (e.g. `choosenim 2.0.0`). The Nim repo also supports online bisecting
via making a comment, which contains a code block starting by `!nim c`, `!nim js` etc. , see [nimrun-action](https://github.com/juancarlospaco/nimrun-action).
- [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html)

View File

@@ -5,19 +5,27 @@ on:
types: created
jobs:
test:
runs-on: ubuntu-latest
bisects:
if: |
github.event_name == 'issue_comment' && startsWith(github.event.comment.body, '!nim ') && github.event.issue.pull_request == null && github.event.comment.author_association != 'NONE'
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, windows-latest, macos-latest]
name: ${{ matrix.platform }}-bisects
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
# nimrun-action requires Nim installed.
- uses: jiro4989/setup-nim-action@v1
with:
nim-version: 'devel'
- uses: jiro4989/setup-nim-action@v1
with:
nim-version: 'devel'
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends -yq valgrind
- uses: juancarlospaco/nimrun-action@nim
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: juancarlospaco/nimrun-action@nim
if: |
runner.os == 'Linux' && contains(github.event.comment.body, '-d:linux' ) ||
runner.os == 'Windows' && contains(github.event.comment.body, '-d:windows') ||
runner.os == 'macOS' && contains(github.event.comment.body, '-d:osx' ) ||
runner.os == 'Linux' && !contains(github.event.comment.body, '-d:linux') && !contains(github.event.comment.body, '-d:windows') && !contains(github.event.comment.body, '-d:osx')
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -17,7 +17,7 @@ jobs:
timeout-minutes: 60 # refs bug #18178
steps:
- name: 'Checkout'
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2
@@ -60,7 +60,7 @@ jobs:
run: nim c -r -d:release ci/action.nim
- name: 'Checkout minimize'
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: 'nim-lang/ci_bench'
path: minimize

View File

@@ -2,8 +2,7 @@ name: Nim Docs CI
on:
push:
paths:
- 'compiler/docgen.nim'
- 'compiler/renderverbatim.nim'
- 'compiler/**.nim'
- 'config/nimdoc.cfg'
- 'doc/**.rst'
- 'doc/**.md'
@@ -18,8 +17,7 @@ on:
pull_request:
# Run only on changes on these files.
paths:
- 'compiler/docgen.nim'
- 'compiler/renderverbatim.nim'
- 'compiler/**.nim'
- 'config/nimdoc.cfg'
- 'doc/**.rst'
- 'doc/**.md'
@@ -47,7 +45,7 @@ jobs:
- target: windows
os: windows-2019
- target: osx
os: macos-12
os: macos-11
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
@@ -55,7 +53,7 @@ jobs:
steps:
- name: 'Checkout'
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2

View File

@@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-12]
os: [ubuntu-20.04, macos-11]
cpu: [amd64]
batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num`
name: '${{ matrix.os }} (batch: ${{ matrix.batch }})'
@@ -28,7 +28,7 @@ jobs:
NIM_TESTAMENT_BATCH: ${{ matrix.batch }}
steps:
- name: 'Checkout'
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2

View File

@@ -17,7 +17,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: 'Checkout'
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2

View File

@@ -29,10 +29,10 @@ jobs:
# vmImage: 'ubuntu-18.04'
# CPU: i386
OSX_amd64:
vmImage: 'macOS-12'
vmImage: 'macOS-11'
CPU: amd64
OSX_amd64_cpp:
vmImage: 'macOS-12'
vmImage: 'macOS-11'
CPU: amd64
NIM_COMPILE_TO_CPP: true
Windows_amd64_batch0_3:
@@ -73,8 +73,8 @@ jobs:
- task: NodeTool@0
inputs:
versionSpec: '16.x'
displayName: 'Install node.js 16.x'
versionSpec: '20.x'
displayName: 'Install node.js 20.x'
condition: and(succeeded(), eq(variables['skipci'], 'false'))
- bash: |

View File

@@ -3,28 +3,46 @@
## Changes affecting backward compatibility
- `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` was out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backwards compatibility.
- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/<version>` instead of `Nim httpclient/<version>` which was incorrect according to the HTTP spec.
- Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to be in the same module where their type has been defined.
- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.
## Standard library additions and changes
[//]: # "Changes:"
- Changed `std/osfiles.copyFile` to allow to specify `bufferSize` instead of a hardcoded one.
- Changed `std/osfiles.copyFile` to use `POSIX_FADV_SEQUENTIAL` hints for kernel-level aggressive sequential read-aheads.
- `std/htmlparser` has been moved to a nimble package, use `nimble` or `atlas` to install it.
[//]: # "Additions:"
- Added `newStringUninit` to system, which creates a new string of length `len` like `newString` but with uninitialized content.
- Added `setLenUninit` to system, which doesn't initalize
slots when enlarging a sequence.
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
- Added Viewport API for the JavaScript targets in the `dom` module.
[//]: # "Deprecations:"
- Deprecates `system.newSeqUninitialized`, which is replaced by `newSeqUninit`.
[//]: # "Removals:"
## Language changes
- `noInit` can be used in types and fields to disable member initializers in the C++ backend.
- C++ custom constructors initializers see https://nim-lang.org/docs/manual_experimental.htm#constructor-initializer
- `member` can be used to attach a procedure to a C++ type.
- C++ `constructor` now reuses `result` instead creating `this`.
## Compiler changes
- `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory.
## Tool changes
- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package in tow.

View File

@@ -205,7 +205,7 @@
proc prc(): int =
123
iterator iter(): int =
iterator iter(): int {.closure.} =
yield 123
proc takesProc[T: proc](x: T) = discard

View File

@@ -0,0 +1,12 @@
# v2.2.0 - 2023-mm-dd
## Changes affecting backward compatibility
## Standard library additions and changes
## Language changes
## Compiler changes
## Tool changes

View File

@@ -3,7 +3,7 @@ import std/[strutils, os, osproc, parseutils, strformat]
proc main() =
var msg = ""
const cmd = "./koch boot --gc:orc -d:release"
const cmd = "./koch boot --mm:orc -d:release"
let (output, exitCode) = execCmdEx(cmd)

View File

@@ -74,7 +74,7 @@ proc aliases*(obj, field: PNode): AliasKind =
# x[i] -> x[i]: maybe; Further analysis could make this return true when i is a runtime-constant
# x[i] -> x[j]: maybe; also returns maybe if only one of i or j is a compiletime-constant
template collectImportantNodes(result, n) =
var result: seq[PNode]
var result: seq[PNode] = @[]
var n = n
while true:
case n.kind

View File

@@ -10,7 +10,9 @@
## Simple alias analysis for the HLO and the code generators.
import
ast, astalgo, types, trees, intsets
ast, astalgo, types, trees
import std/intsets
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -114,6 +116,8 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
# use expensive type check:
if isPartOf(a.sym.typ, b.sym.typ) != arNo:
result = arMaybe
else:
result = arNo
of nkBracketExpr:
result = isPartOf(a[0], b[0])
if a.len >= 2 and b.len >= 2:
@@ -149,7 +153,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
result = isPartOf(a[1], b[1])
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isPartOf(a[0], b[0])
else: discard
else: result = arNo
# Calls return a new location, so a default of ``arNo`` is fine.
else:
# go down recursively; this is quite demanding:
@@ -165,6 +169,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
of DerefKinds:
# a* !<| b[] iff
result = arNo
if isPartOf(a.typ, b.typ) != arNo:
result = isPartOf(a, b[0])
if result == arNo: result = arMaybe
@@ -186,7 +191,9 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
if isPartOf(a.typ, b.typ) != arNo:
result = isPartOf(a[0], b)
if result == arNo: result = arMaybe
else: discard
else:
result = arNo
else: result = arNo
of nkObjConstr:
result = arNo
for i in 1..<b.len:
@@ -204,4 +211,6 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
of nkBracket:
if b.len > 0:
result = isPartOf(a, b[0])
else: discard
else:
result = arNo
else: result = arNo

View File

@@ -10,8 +10,10 @@
# abstract syntax tree + symbol table
import
lineinfos, hashes, options, ropes, idents, int128, tables
from strutils import toLowerAscii
lineinfos, options, ropes, idents, int128, wordrecg
import std/[tables, hashes]
from std/strutils import toLowerAscii
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -314,6 +316,7 @@ type
# an infinite loop, this flag is used as a sentinel to stop it.
sfVirtual # proc is a C++ virtual function
sfByCopy # param is marked as pass bycopy
sfMember # proc is a C++ member of a type
sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl
TSymFlags* = set[TSymFlag]
@@ -347,6 +350,7 @@ const
sfBase* = sfDiscriminant
sfCustomPragma* = sfRegister # symbol is custom pragma template
sfTemplateRedefinition* = sfExportc # symbol is a redefinition of an earlier template
sfCppMember* = { sfVirtual, sfMember, sfConstructor } # proc is a C++ member, meaning it will be attached to the type definition
const
# getting ready for the future expr/stmt merge
@@ -589,6 +593,7 @@ type
tfEffectSystemWorkaround
tfIsOutParam
tfSendable
tfImplicitStatic
TTypeFlags* = set[TTypeFlag]
@@ -638,7 +643,7 @@ const
skError* = skUnknown
var
eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr, tfGcSafe, tfNoSideEffect, tfIsOutParam, tfSendable}
eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr, tfGcSafe, tfNoSideEffect, tfIsOutParam}
## type flags that are essential for type equality.
## This is now a variable because for emulation of version:1.0 we
## might exclude {tfGcSafe, tfNoSideEffect}.
@@ -922,7 +927,7 @@ type
# for variables a slot index for the evaluator
offset*: int32 # offset of record field
disamb*: int32 # disambiguation number; the basic idea is that
# `<procname>__<module>_<disamb>`
# `<procname>__<module>_<disamb>` is unique
loc*: TLoc
annex*: PLib # additional fields (seldom used, so we use a
# reference to another object to save space)
@@ -934,6 +939,7 @@ type
# it won't cause problems
# for skModule the string literal to output for
# deprecated modules.
instantiatedFrom*: PSym # for instances, the generic symbol where it came from.
when defined(nimsuggest):
allUsages*: seq[TLineInfo]
@@ -956,7 +962,7 @@ type
kind*: TTypeKind # kind of type
callConv*: TCallingConvention # for procs
flags*: TTypeFlags # flags of the type
sons*: TTypeSeq # base types, etc.
sons: TTypeSeq # base types, etc.
n*: PNode # node for types:
# for range types a nkRange node
# for record types a nkRecord node
@@ -1037,6 +1043,8 @@ proc comment*(n: PNode): string =
if nfHasComment in n.flags and not gconfig.useIc:
# IC doesn't track comments, see `packed_ast`, so this could fail
result = gconfig.comments[n.nodeId]
else:
result = ""
proc `comment=`*(n: PNode, a: string) =
let id = n.nodeId
@@ -1158,7 +1166,7 @@ proc idGeneratorFromModule*(m: PSym): IdGenerator =
proc idGeneratorForPackage*(nextIdWillBe: int32): IdGenerator =
result = IdGenerator(module: PackageModuleId, symId: nextIdWillBe - 1'i32, typeId: 0, disambTable: initCountTable[PIdent]())
proc nextSymId*(x: IdGenerator): ItemId {.inline.} =
proc nextSymId(x: IdGenerator): ItemId {.inline.} =
assert(not x.sealed)
inc x.symId
result = ItemId(module: x.module, item: x.symId)
@@ -1223,6 +1231,7 @@ proc getDeclPragma*(n: PNode): PNode =
case n.kind
of routineDefs:
if n[pragmasPos].kind != nkEmpty: result = n[pragmasPos]
else: result = nil
of nkTypeDef:
#[
type F3*{.deprecated: "x3".} = int
@@ -1242,6 +1251,8 @@ proc getDeclPragma*(n: PNode): PNode =
]#
if n[0].kind == nkPragmaExpr:
result = n[0][1]
else:
result = nil
else:
# support as needed for `nkIdentDefs` etc.
result = nil
@@ -1257,6 +1268,12 @@ proc extractPragma*(s: PSym): PNode =
if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1:
# s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma]
result = s.ast[0][1]
else:
result = nil
else:
result = nil
else:
result = nil
assert result == nil or result.kind == nkPragma
proc skipPragmaExpr*(n: PNode): PNode =
@@ -1486,7 +1503,7 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
result = newNode(nkIntLit)
of tyStatic: # that's a pre-existing bug, will fix in another PR
result = newNode(nkIntLit)
else: doAssert false, $kind
else: raiseAssert $kind
result.intVal = intVal
result.typ = typ
@@ -1524,15 +1541,31 @@ proc `$`*(s: PSym): string =
else:
result = "<nil>"
proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType =
iterator items*(t: PType): PType =
for i in 0..<t.sons.len: yield t.sons[i]
iterator pairs*(n: PType): tuple[i: int, n: PType] =
for i in 0..<n.sons.len: yield (i, n.sons[i])
proc newType*(kind: TTypeKind, idgen: IdGenerator; owner: PSym, sons: seq[PType] = @[]): PType =
let id = nextTypeId idgen
result = PType(kind: kind, owner: owner, size: defaultSize,
align: defaultAlignment, itemId: id,
uniqueId: id)
uniqueId: id, sons: sons)
when false:
if result.itemId.module == 55 and result.itemId.item == 2:
echo "KNID ", kind
writeStackTrace()
template newType*(kind: TTypeKind, id: IdGenerator; owner: PSym, parent: PType): PType =
newType(kind, id, owner, parent.sons)
proc setSons*(dest: PType; sons: seq[PType]) {.inline.} = dest.sons = sons
when false:
proc newType*(prev: PType, sons: seq[PType]): PType =
result = prev
result.sons = sons
proc mergeLoc(a: var TLoc, b: TLoc) =
if a.k == low(typeof(a.k)): a.k = b.k
@@ -1562,13 +1595,17 @@ proc assignType*(dest, src: PType) =
newSons(dest, src.len)
for i in 0..<src.len: dest[i] = src[i]
proc copyType*(t: PType, id: ItemId, owner: PSym): PType =
result = newType(t.kind, id, owner)
proc copyType*(t: PType, idgen: IdGenerator, owner: PSym): PType =
result = newType(t.kind, idgen, owner)
assignType(result, t)
result.sym = t.sym # backend-info should not be copied
proc exactReplica*(t: PType): PType =
result = copyType(t, t.itemId, t.owner)
result = PType(kind: t.kind, owner: t.owner, size: defaultSize,
align: defaultAlignment, itemId: t.itemId,
uniqueId: t.uniqueId)
assignType(result, t)
result.sym = t.sym # backend-info should not be copied
proc copySym*(s: PSym; idgen: IdGenerator): PSym =
result = newSym(s.kind, s.name, idgen, s.owner, s.info, s.options)
@@ -1598,19 +1635,13 @@ proc createModuleAlias*(s: PSym, idgen: IdGenerator, newIdent: PIdent, info: TLi
result.loc = s.loc
result.annex = s.annex
proc initStrTable*(x: var TStrTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc initStrTable*(): TStrTable =
result = TStrTable(counter: 0)
newSeq(result.data, StartSize)
proc newStrTable*: TStrTable =
initStrTable(result)
proc initIdTable*(x: var TIdTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc newIdTable*: TIdTable =
initIdTable(result)
proc initIdTable*(): TIdTable =
result = TIdTable(counter: 0)
newSeq(result.data, StartSize)
proc resetIdTable*(x: var TIdTable) =
x.counter = 0
@@ -1618,17 +1649,17 @@ proc resetIdTable*(x: var TIdTable) =
setLen(x.data, 0)
setLen(x.data, StartSize)
proc initObjectSet*(x: var TObjectSet) =
x.counter = 0
newSeq(x.data, StartSize)
proc initObjectSet*(): TObjectSet =
result = TObjectSet(counter: 0)
newSeq(result.data, StartSize)
proc initIdNodeTable*(x: var TIdNodeTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc initIdNodeTable*(): TIdNodeTable =
result = TIdNodeTable(counter: 0)
newSeq(result.data, StartSize)
proc initNodeTable*(x: var TNodeTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc initNodeTable*(): TNodeTable =
result = TNodeTable(counter: 0)
newSeq(result.data, StartSize)
proc skipTypes*(t: PType, kinds: TTypeKinds; maxIters: int): PType =
result = t
@@ -1678,9 +1709,6 @@ proc rawAddSon*(father, son: PType; propagateHasAsgn = true) =
father.sons.add(son)
if not son.isNil: propagateToOwner(father, son, propagateHasAsgn)
proc rawAddSonNoPropagationOfTypeFlags*(father, son: PType) =
father.sons.add(son)
proc addSonNilAllowed*(father, son: PNode) =
father.sons.add(son)
@@ -1812,6 +1840,7 @@ proc hasNilSon*(n: PNode): bool =
result = false
proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
result = false
if n == nil: return
case n.kind
of nkEmpty..nkNilLit: result = n.kind in kinds
@@ -1912,7 +1941,7 @@ proc skipGenericOwner*(s: PSym): PSym =
## Generic instantiations are owned by their originating generic
## symbol. This proc skips such owners and goes straight to the owner
## of the generic itself (the module or the enclosing proc).
result = if s.kind in skProcKinds and sfFromGeneric in s.flags:
result = if s.kind in skProcKinds and sfFromGeneric in s.flags and s.owner.kind != skModule:
s.owner.owner
else:
s.owner
@@ -1964,7 +1993,7 @@ proc toVar*(typ: PType; kind: TTypeKind; idgen: IdGenerator): PType =
## returned. Otherwise ``typ`` is simply returned as-is.
result = typ
if typ.kind != kind:
result = newType(kind, nextTypeId(idgen), typ.owner)
result = newType(kind, idgen, typ.owner)
rawAddSon(result, typ)
proc toRef*(typ: PType; idgen: IdGenerator): PType =
@@ -1972,7 +2001,7 @@ proc toRef*(typ: PType; idgen: IdGenerator): PType =
## returned. Otherwise ``typ`` is simply returned as-is.
result = typ
if typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject:
result = newType(tyRef, nextTypeId(idgen), typ.owner)
result = newType(tyRef, idgen, typ.owner)
rawAddSon(result, typ)
proc toObject*(typ: PType): PType =
@@ -2013,9 +2042,11 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
if base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {}:
result = true
else:
result = false
proc isInfixAs*(n: PNode): bool =
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as"
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.id == ord(wAs)
proc skipColon*(n: PNode): PNode =
result = n
@@ -2023,10 +2054,12 @@ proc skipColon*(n: PNode): PNode =
result = n[1]
proc findUnresolvedStatic*(n: PNode): PNode =
# n.typ == nil: see issue #14802
if n.kind == nkSym and n.typ != nil and n.typ.kind == tyStatic and n.typ.n == nil:
return n
if n.typ != nil and n.typ.kind == tyTypeDesc:
let t = skipTypes(n.typ, {tyTypeDesc})
if t.kind == tyGenericParam and t.len == 0:
return n
for son in n:
let n = son.findUnresolvedStatic
if n != nil: return n
@@ -2064,14 +2097,20 @@ proc isClosureIterator*(typ: PType): bool {.inline.} =
proc isClosure*(typ: PType): bool {.inline.} =
typ.kind == tyProc and typ.callConv == ccClosure
proc isNimcall*(s: PSym): bool {.inline.} =
s.typ.callConv == ccNimCall
proc isExplicitCallConv*(s: PSym): bool {.inline.} =
tfExplicitCallConv in s.typ.flags
proc isSinkParam*(s: PSym): bool {.inline.} =
s.kind == skParam and (s.typ.kind == tySink or tfHasOwned in s.typ.flags)
proc isSinkType*(t: PType): bool {.inline.} =
t.kind == tySink or tfHasOwned in t.flags
proc newProcType*(info: TLineInfo; id: ItemId; owner: PSym): PType =
result = newType(tyProc, id, owner)
proc newProcType*(info: TLineInfo; idgen: IdGenerator; owner: PSym): PType =
result = newType(tyProc, idgen, owner)
result.n = newNodeI(nkFormalParams, info)
rawAddSon(result, nil) # return type
# result.n[0] used to be `nkType`, but now it's `nkEffectList` because
@@ -2122,7 +2161,7 @@ proc toHumanStr*(kind: TTypeKind): string =
## strips leading `tk`
result = toHumanStrImpl(kind, 2)
proc skipAddr*(n: PNode): PNode {.inline.} =
proc skipHiddenAddr*(n: PNode): PNode {.inline.} =
(if n.kind == nkHiddenAddr: n[0] else: n)
proc isNewStyleConcept*(n: PNode): bool {.inline.} =
@@ -2138,3 +2177,7 @@ const
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt}
proc isTrue*(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0

View File

@@ -12,10 +12,11 @@
# the data structures here are used in various places of the compiler.
import
ast, hashes, intsets, options, lineinfos, ropes, idents, rodutils,
ast, options, lineinfos, ropes, idents, rodutils,
msgs
import strutils except addf
import std/[hashes, intsets]
import std/strutils except addf
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -109,7 +110,7 @@ type
data*: TIIPairSeq
proc initIiTable*(x: var TIITable)
proc initIITable*(x: var TIITable)
proc iiTableGet*(t: TIITable, key: int): int
proc iiTablePut*(t: var TIITable, key, val: int)
@@ -197,6 +198,7 @@ proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym =
result = nil
proc sameIgnoreBacktickGensymInfo(a, b: string): bool =
result = false
if a[0] != b[0]: return false
var alen = a.len - 1
while alen > 0 and a[alen] != '`': dec(alen)
@@ -226,10 +228,11 @@ proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym =
## Named parameters are special because a named parameter can be
## gensym'ed and then they have '\`<number>' suffix that we need to
## ignore, see compiler / evaltempl.nim, snippet:
## ```
## ```nim
## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id),
## if c.instLines: actual.info else: templ.info)
## ```
result = nil
for i in 1..<list.len:
let it = list[i].sym
if it.name.id == ident.id or
@@ -327,8 +330,10 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
maxRecDepth: int): Rope =
var sonsRope: Rope
if n == nil:
result = ""
sonsRope = rope("null")
elif containsOrIncl(marker, n.id):
result = ""
sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
strutils.toHex(cast[int](n), sizeof(n) * 2))]
else:
@@ -365,7 +370,7 @@ proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int,
if conf != nil:
result.addf(",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
case n.kind
of nkCharLit..nkInt64Lit:
of nkCharLit..nkUInt64Lit:
result.addf(",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
result.addf(",$N$1\"floatVal\": $2",
@@ -404,7 +409,7 @@ proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1
var marker = initIntSet()
result = symToYamlAux(conf, n, marker, indent, maxRecDepth)
import tables
import std/tables
const backrefStyle = "\e[90m"
const enumStyle = "\e[34m"
@@ -1063,6 +1068,7 @@ proc isAddrNode*(n: PNode): bool =
else: false
proc listSymbolNames*(symbols: openArray[PSym]): string =
result = ""
for sym in symbols:
if result.len > 0:
result.add ", "

View File

@@ -87,5 +87,11 @@ const populationCount: array[uint8, uint8] = block:
arr
proc bitSetCard*(x: TBitSet): BiggestInt =
result = 0
for it in x:
result.inc int(populationCount[it])
proc bitSetToWord*(s: TBitSet; size: int): BiggestUInt =
result = 0
for j in 0..<size:
if j < s.len: result = result or (BiggestUInt(s[j]) shl (j * 8))

View File

@@ -38,6 +38,7 @@ template less(a, b): bool = cmp(a, b) < 0
template eq(a, b): bool = cmp(a, b) == 0
proc getOrDefault*[Key, Val](b: BTree[Key, Val], key: Key): Val =
result = default(Val)
var x = b.root
while x.isInternal:
for j in 0..<x.entries:

View File

@@ -24,6 +24,7 @@ proc canRaiseDisp(p: BProc; n: PNode): bool =
proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool =
result = false
var n = le
while true:
# do NOT follow nkHiddenDeref here!
@@ -46,6 +47,7 @@ proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
# cannot analyse the location; assume the worst
return true
result = false
if le != nil:
for i in 1..<ri.len:
let r = ri[i]
@@ -87,7 +89,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd':
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
if d.k == locNone: d = getTemp(p, typ[0], needsInit=true)
elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
discard "resetLoc(p, d)"
@@ -95,8 +97,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
pl.add(");\n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
pl.add(addrLoc(p.config, tmp))
pl.add(");\n")
line(p, cpsStmts, pl)
@@ -114,28 +115,24 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
excl d.flags, lfSingleUse
else:
if d.k == locNone and p.splitDecls == 0:
getTempCpp(p, typ[0], d, pl)
d = getTempCpp(p, typ[0], pl)
else:
if d.k == locNone: getTemp(p, typ[0], d)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
if d.k == locNone: d = getTemp(p, typ[0])
var list = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
elif isHarmlessStore(p, canRaise, d):
if d.k == locNone: getTemp(p, typ[0], d)
if d.k == locNone: d = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
var list = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
var list = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, tmp, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
@@ -157,10 +154,9 @@ proc reifiedOpenArray(n: PNode): bool {.inline.} =
result = true
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) =
var a, b, c: TLoc
initLocExpr(p, q[1], a)
initLocExpr(p, q[2], b)
initLocExpr(p, q[3], c)
var a = initLocExpr(p, q[1])
var b = initLocExpr(p, q[2])
var c = initLocExpr(p, q[3])
# but first produce the required index checks:
if optBoundsCheck in p.options:
genBoundsCheck(p, a, b, c)
@@ -198,13 +194,14 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
if atyp.kind in {tyVar} and not compileToCpp(p.module):
result = ("(($5) ? (($4*)(*$1)$3+($2)) : NIM_NIL)" %
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, "*" & rdLoc(a))],
[rdLoc(a), rdLoc(b), dataField(p, ty.kind == tyString), dest, dataFieldAccessor(p, "*" & rdLoc(a))],
lengthExpr)
else:
result = ("(($5) ? (($4*)$1$3+($2)) : NIM_NIL)" %
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, rdLoc(a))],
[rdLoc(a), rdLoc(b), dataField(p, ty.kind == tyString), dest, dataFieldAccessor(p, rdLoc(a))],
lengthExpr)
else:
result = ("", "")
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
@@ -224,9 +221,9 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0])
result.add x & ", " & y
else:
var a: TLoc
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
case skipTypes(a.t, abstractVar+{tyStatic}).kind
var a = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n)
let typKind = skipTypes(a.t, abstractVar+{tyStatic}).kind
case typKind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(n):
if a.t.kind in {tyVar, tyLent}:
@@ -244,11 +241,11 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
var t: TLoc
t.r = "(*$1)" % [a.rdLoc]
result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, t), dataField(p),
[a.rdLoc, lenExpr(p, t, typKind == tyString), dataField(p, typKind == tyString),
dataFieldAccessor(p, "*" & a.rdLoc)]
else:
result.add "($4) ? ($1$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)]
[a.rdLoc, lenExpr(p, a, typKind == tyString), dataField(p, typKind == tyString), dataFieldAccessor(p, a.rdLoc)]
of tyArray:
result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))]
of tyPtr, tyRef:
@@ -257,7 +254,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
var t: TLoc
t.r = "(*$1)" % [a.rdLoc]
result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, t), dataField(p),
[a.rdLoc, lenExpr(p, t, typKind == tyString), dataField(p, typKind == tyString),
dataFieldAccessor(p, "*" & a.rdLoc)]
of tyArray:
result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))]
@@ -271,18 +268,17 @@ proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc =
# Also don't regress for non ARC-builds, too risky.
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
getSize(p.config, a.lode.typ) < 1024:
getTemp(p, a.lode.typ, result, needsInit=false)
result = getTemp(p, a.lode.typ, needsInit=false)
genAssignment(p, result, a, {})
else:
result = a
proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc =
getTemp(p, a.lode.typ, result, needsInit=false)
result = getTemp(p, a.lode.typ, needsInit=false)
genAssignment(p, result, a, {})
proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} =
var a: TLoc
initLocExpr(p, n[0], a)
var a = initLocExpr(p, n[0])
appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc])
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) =
@@ -292,16 +288,16 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
var n = if n.kind != nkHiddenAddr: n else: n[0]
openArrayLoc(p, param.typ, n, result)
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and
(optByRef notin param.options or not p.module.compileToCpp):
initLocExpr(p, n, a)
a = initLocExpr(p, n)
if n.kind in {nkCharLit..nkNilLit}:
addAddrLoc(p.config, literalsNeedsTmp(p, a), result)
else:
addAddrLoc(p.config, withTmpIfNeeded(p, a, needsTmp), result)
elif p.module.compileToCpp and param.typ.kind in {tyVar} and
n.kind == nkHiddenAddr:
initLocExprSingleUse(p, n[0], a)
a = initLocExprSingleUse(p, n[0])
# if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
# means '*T'. See posix.nim for lots of examples that do that in the wild.
let callee = call[0]
@@ -312,7 +308,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
else:
addRdLoc(a, result)
else:
initLocExprSingleUse(p, n, a)
a = initLocExprSingleUse(p, n)
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
#assert result != nil
@@ -321,12 +317,13 @@ proc genArgNoParam(p: BProc, n: PNode; result: var Rope; needsTmp = false) =
if n.kind == nkStringToCString:
genArgStringToCString(p, n, result, needsTmp)
else:
initLocExprSingleUse(p, n, a)
a = initLocExprSingleUse(p, n)
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
import aliasanalysis
proc potentialAlias(n: PNode, potentialWrites: seq[PNode]): bool =
result = false
for p in potentialWrites:
if p.aliases(n) != no or n.aliases(p) != no:
return true
@@ -382,13 +379,13 @@ proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
# We must generate temporaries in cases like #14396
# to keep the strict Left-To-Right evaluation
var needTmp = newSeq[bool](ri.len - 1)
var potentialWrites: seq[PNode]
var potentialWrites: seq[PNode] = @[]
for i in countdown(ri.len - 1, 1):
if ri[i].skipTrivialIndirections.kind == nkSym:
needTmp[i - 1] = potentialAlias(ri[i], potentialWrites)
else:
#if not ri[i].typ.isCompileTimeOnly:
var potentialReads: seq[PNode]
var potentialReads: seq[PNode] = @[]
getPotentialReads(ri[i], potentialReads)
for n in potentialReads:
if not needTmp[i - 1]:
@@ -420,9 +417,8 @@ proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
res = res & "_actual".rope
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op: TLoc
# this is a hotspot in the compiler
initLocExpr(p, ri[0], op)
var op = initLocExpr(p, ri[0])
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
assert(typ.kind == tyProc)
@@ -444,8 +440,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)"
const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists
var op: TLoc
initLocExpr(p, ri[0], op)
var op = initLocExpr(p, ri[0])
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
@@ -470,7 +465,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd':
if d.k == locNone:
getTemp(p, typ[0], d, needsInit=true)
d = getTemp(p, typ[0], needsInit=true)
elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
discard "resetLoc(p, d)"
@@ -478,17 +473,15 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genCallPattern()
if canRaise: raiseExit(p)
else:
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
pl.add(addrLoc(p.config, tmp))
genCallPattern()
if canRaise: raiseExit(p)
genAssignment(p, d, tmp, {}) # no need for deep copying
elif isHarmlessStore(p, canRaise, d):
if d.k == locNone: getTemp(p, typ[0], d)
if d.k == locNone: d = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
if tfIterator in typ.flags:
list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
else:
@@ -496,11 +489,9 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc
getTemp(p, typ[0], tmp)
var tmp: TLoc = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
if tfIterator in typ.flags:
list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
else:
@@ -668,7 +659,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
inc j
inc i
of '\'':
var idx, stars: int
var idx, stars: int = 0
if scanCppGenericSlot(pat, i, idx, stars):
var t = resolveStarsInCppType(typ, idx, stars)
if t == nil: result.add("void")
@@ -682,8 +673,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
result.add(substr(pat, start, i - 1))
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op: TLoc
initLocExpr(p, ri[0], op)
var op = initLocExpr(p, ri[0])
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
assert(typ.kind == tyProc)
@@ -705,10 +695,9 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
d.r = pl
excl d.flags, lfSingleUse
else:
if d.k == locNone: getTemp(p, typ[0], d)
if d.k == locNone: d = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
@@ -728,8 +717,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# generates a crappy ObjC call
var op: TLoc
initLocExpr(p, ri[0], op)
var op = initLocExpr(p, ri[0])
var pl = "["
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
@@ -771,24 +759,22 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# beware of 'result = p(result)'. We always allocate a temporary:
if d.k in {locTemp, locNone}:
# We already got a temp. Great, special case it:
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
if d.k == locNone: d = getTemp(p, typ[0], needsInit=true)
pl.add("Result: ")
pl.add(addrLoc(p.config, d))
pl.add("];\n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
pl.add(addrLoc(p.config, tmp))
pl.add("];\n")
line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
pl.add("]")
if d.k == locNone: getTemp(p, typ[0], d)
if d.k == locNone: d = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, ri, OnUnknown)
var list: TLoc = initLoc(locCall, ri, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:

File diff suppressed because it is too large Load Diff

View File

@@ -94,6 +94,48 @@ proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Ro
pureLit = m.tmpBase & rope(id)
result.addf "{$1, (NimStrPayload*)&$2}", [rope(n.strVal.len), pureLit]
# ------ Version 3: destructor based strings and seqs -----------------------
# strings are enhanced by interned strings
proc toConstLenV3(len: int): string =
result = rope((len shl 1) or 1)
proc genStringLiteralDataOnlyV3(m: BModule, s: string; result: Rope; isConst: bool) =
# TODO: fixme: perhaps use makeCString for clarity for C
m.s[cfsStrData].addf("static $4 NIM_CHAR $1[$2] = $3;$n",
[result, rope(s.len), makeCCharArray(s),
rope(if isConst: "const" else: "")])
proc genStringLiteralV3(m: BModule; n: PNode; isConst: bool; result: var Rope) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
if id == m.labels:
let pureLit = getTempName(m)
genStringLiteralDataOnlyV3(m, n.strVal, pureLit, isConst)
let tmp = getTempName(m)
result.add tmp
cgsym(m, "NimStringV3")
# string literal not found in the cache:
m.s[cfsStrData].addf("static $4 NimStringV3 $1 = {$2, (NIM_CHAR*)&$3};$n",
[tmp, toConstLenV3(n.strVal.len), pureLit, rope(if isConst: "const" else: "")])
else:
let tmp = getTempName(m)
result.add tmp
m.s[cfsStrData].addf("static $4 NimStringV3 $1 = {$2, (NIM_CHAR*)&$3};$n",
[tmp, toConstLenV3(n.strVal.len), m.tmpBase & rope(id),
rope(if isConst: "const" else: "")])
proc genStringLiteralV3Const(m: BModule; n: PNode; isConst: bool; result: var Rope) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var pureLit: Rope
if id == m.labels:
pureLit = getTempName(m)
cgsym(m, "NimStringV3")
# string literal not found in the cache:
genStringLiteralDataOnlyV3(m, n.strVal, pureLit, isConst)
else:
pureLit = m.tmpBase & rope(id)
result.addf "{$1, (NIM_CHAR*)&$2}", [toConstLenV3(n.strVal.len), pureLit]
# ------ Version selector ---------------------------------------------------
proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
@@ -104,6 +146,10 @@ proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
let tmp = getTempName(m)
genStringLiteralDataOnlyV2(m, s, tmp, isConst)
result.add tmp
of 3:
let tmp = getTempName(m)
genStringLiteralDataOnlyV3(m, s, tmp, isConst)
result.add tmp
else:
localError(m.config, info, "cannot determine how to produce code for string literal")
@@ -114,5 +160,6 @@ proc genStringLiteral(m: BModule; n: PNode; result: var Rope) =
case detectStrVersion(m)
of 0, 1: genStringLiteralV1(m, n, result)
of 2: genStringLiteralV2(m, n, isConst = true, result)
of 3: genStringLiteralV3(m, n, isConst = true, result)
else:
localError(m.config, n.info, "cannot determine how to produce code for string literal")

View File

@@ -57,8 +57,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
specializeResetT(p, accessor, lastSon(typ))
of tyArray:
let arraySize = lengthOrd(p.config, typ[0])
var i: TLoc
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i)
var i: TLoc = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt))
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.r, arraySize])
specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.r]), typ[1])
@@ -83,7 +82,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
lineCg(p, cpsStmts, "$1.ClP_0 = NIM_NIL;$n", [accessor])
else:
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
of tyChar, tyBool, tyEnum, tyRange, tyInt..tyUInt64:
of tyChar, tyBool, tyEnum, tyInt..tyUInt64:
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
of tyCstring, tyPointer, tyPtr, tyVar, tyLent:
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
@@ -95,12 +94,12 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
of ctInt8, ctInt16, ctInt32, ctInt64:
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
else:
doAssert false, "unexpected set type kind"
of {tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
tyGenericParam, tyOrdinal, tyOpenArray, tyForward, tyVarargs,
raiseAssert "unexpected set type kind"
of tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
tyGenericParam, tyOrdinal, tyRange, tyOpenArray, tyForward, tyVarargs,
tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot,
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable}:
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable:
discard
proc specializeReset(p: BProc, a: TLoc) =

View File

@@ -50,6 +50,7 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
result = true
proc inExceptBlockLen(p: BProc): int =
result = 0
for x in p.nestedTryStmts:
if x.inExcept: result.inc
@@ -71,7 +72,6 @@ template startBlock(p: BProc, start: FormatStr = "{$n",
proc endBlock(p: BProc)
proc genVarTuple(p: BProc, n: PNode) =
var tup, field: TLoc
if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
# if we have a something that's been captured, use the lowering instead:
@@ -83,7 +83,7 @@ proc genVarTuple(p: BProc, n: PNode) =
# check only the first son
var forHcr = treatGlobalDifferentlyForHCR(p.module, n[0].sym)
let hcrCond = if forHcr: getTempName(p.module) else: ""
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]]
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]] = @[]
# determine if the tuple is constructed at top-level scope or inside of a block (if/while/block)
let isGlobalInBlock = forHcr and p.blocks.len > 2
# do not close and reopen blocks if this is a 'global' but inside of a block (if/while/block)
@@ -95,7 +95,7 @@ proc genVarTuple(p: BProc, n: PNode) =
startBlock(p)
genLineDir(p, n)
initLocExpr(p, n[^1], tup)
var tup = initLocExpr(p, n[^1])
var t = tup.t.skipTypes(abstractInst)
for i in 0..<n.len-2:
let vn = n[i]
@@ -108,7 +108,7 @@ proc genVarTuple(p: BProc, n: PNode) =
else:
assignLocalVar(p, vn)
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1]))
initLoc(field, locExpr, vn, tup.storage)
var field = initLoc(locExpr, vn, tup.storage)
if t.kind == tyTuple:
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
else:
@@ -169,7 +169,7 @@ proc endBlock(p: BProc, blockEnd: Rope) =
proc endBlock(p: BProc) =
let topBlock = p.blocks.len - 1
let frameLen = p.blocks[topBlock].frameLen
var blockEnd: Rope
var blockEnd: Rope = ""
if frameLen > 0:
blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope])
if p.blocks[topBlock].label.len != 0:
@@ -244,8 +244,7 @@ proc genGotoState(p: BProc, n: PNode) =
# switch (x.state) {
# case 0: goto STATE0;
# ...
var a: TLoc
initLocExpr(p, n[0], a)
var a: TLoc = initLocExpr(p, n[0])
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
p.flags.incl beforeRetNeeded
lineF(p, cpsStmts, "case -1:$n", [])
@@ -264,13 +263,13 @@ proc genGotoState(p: BProc, n: PNode) =
proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
initLoc(d, locExpr, n, OnUnknown)
d = initLoc(locExpr, n, OnUnknown)
if n[0].kind == nkClosure:
initLocExpr(p, n[0][1], a)
a = initLocExpr(p, n[0][1])
d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)]
else:
initLocExpr(p, n[0], a)
a = initLocExpr(p, n[0])
# the environment is guaranteed to contain the 'state' field at offset 1:
d.r = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)]
@@ -290,14 +289,22 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) =
#echo "New code produced for ", v.name.s, " ", p.config $ value.info
genBracedInit(p, value, isConst = false, v.typ, result)
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) =
var params = newRopeAppender()
proc genCppParamsForCtor(p: BProc; call: PNode): string =
result = ""
var argsCounter = 0
let typ = skipTypes(value[0].typ, abstractInst)
let typ = skipTypes(call[0].typ, abstractInst)
assert(typ.kind == tyProc)
for i in 1..<value.len:
for i in 1..<call.len:
assert(typ.len == typ.n.len)
genOtherArg(p, value, i, typ, params, argsCounter)
#if it's a type we can just generate here another initializer as we are in an initializer context
if call[i].kind == nkCall and call[i][0].kind == nkSym and call[i][0].sym.kind == skType:
if argsCounter > 0: result.add ","
result.add genCppInitializer(p.module, p, call[i][0].sym.typ)
else:
genOtherArg(p, call, i, typ, result, argsCounter)
proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope) =
let params = genCppParamsForCtor(p, call)
if params.len == 0:
decl = runtimeFormat("$#;\n", [decl])
else:
@@ -341,7 +348,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
# Only do this for complex types that may need a call to `objectInit`
if sfThread in v.flags and emulatedThreadVars(p.config) and
isComplexValueType(v.typ):
initLocExprSingleUse(p.module.preInitProc, vn, loc)
loc = initLocExprSingleUse(p.module.preInitProc, vn)
genObjectInit(p.module.preInitProc, cpsInit, v.typ, loc, constructObj)
# Alternative construction using default constructor (which may zeromem):
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
@@ -359,10 +366,10 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
var decl = localVarDecl(p, vn)
var tmp: TLoc
if isCppCtorCall:
genCppVarForCtor(p, v, vn, value, decl)
genCppVarForCtor(p, value, decl)
line(p, cpsStmts, decl)
else:
initLocExprSingleUse(p, value, tmp)
tmp = initLocExprSingleUse(p, value)
lineF(p, cpsStmts, "$# = $#;\n", [decl, tmp.rdLoc])
return
assignLocalVar(p, vn)
@@ -408,8 +415,7 @@ proc genSingleVar(p: BProc, a: PNode) =
proc genClosureVar(p: BProc, a: PNode) =
var immediateAsgn = a[2].kind != nkEmpty
var v: TLoc
initLocExpr(p, a[0], v)
var v: TLoc = initLocExpr(p, a[0])
genLineDir(p, a)
if immediateAsgn:
loadInto(p, a[0], a[2], v)
@@ -444,7 +450,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
a: TLoc
lelse: TLabel
if not isEmptyType(n.typ) and d.k == locNone:
getTemp(p, n.typ, d)
d = getTemp(p, n.typ)
genLineDir(p, n)
let lend = getLabel(p)
for it in n.sons:
@@ -452,7 +458,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
if it.len == 2:
startBlock(p)
initLocExprSingleUse(p, it[0], a)
a = initLocExprSingleUse(p, it[0])
lelse = getLabel(p)
inc(p.labels)
lineF(p, cpsStmts, "if (!$1) goto $2;$n",
@@ -520,7 +526,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
# wrapped inside stmt lists by inject destructors won't be recognised
let n = n.flattenStmts()
var casePos = -1
var arraySize: int
var arraySize: int = 0
for i in 0..<n.len:
let it = n[i]
if it.kind == nkCaseStmt:
@@ -554,8 +560,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
genStmts(p, n[j])
let caseStmt = n[casePos]
var a: TLoc
initLocExpr(p, caseStmt[0], a)
var a: TLoc = initLocExpr(p, caseStmt[0])
# first goto:
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
@@ -593,8 +598,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
else:
genStmts(p, it)
var a: TLoc
initLocExpr(p, caseStmt[0], a)
var a: TLoc = initLocExpr(p, caseStmt[0])
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
endBlock(p)
@@ -622,7 +626,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
else:
p.breakIdx = startBlock(p, "while (1) {$n")
p.blocks[p.breakIdx].isLoop = true
initLocExpr(p, t[0], a)
a = initLocExpr(p, t[0])
if (t[0].kind != nkIntLit) or (t[0].intVal == 0):
lineF(p, cpsStmts, "if (!$1) goto ", [rdLoc(a)])
assignLabel(p.blocks[p.breakIdx], p.s(cpsStmts))
@@ -641,7 +645,7 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
# bug #4505: allocate the temp in the outer scope
# so that it can escape the generated {}:
if d.k == locNone:
getTemp(p, n.typ, d)
d = getTemp(p, n.typ)
d.flags.incl(lfEnforceDeref)
preserveBreakIdx:
p.breakIdx = startBlock(p)
@@ -661,14 +665,13 @@ proc genParForStmt(p: BProc, t: PNode) =
preserveBreakIdx:
let forLoopVar = t[0].sym
var rangeA, rangeB: TLoc
assignLocalVar(p, t[0])
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
#discard mangleName(forLoopVar)
let call = t[1]
assert(call.len == 4 or call.len == 5)
initLocExpr(p, call[1], rangeA)
initLocExpr(p, call[2], rangeB)
var rangeA = initLocExpr(p, call[1])
var rangeB = initLocExpr(p, call[2])
# $n at the beginning because of #9710
if call.len == 4: # procName(a, b, annotation)
@@ -685,8 +688,7 @@ proc genParForStmt(p: BProc, t: PNode) =
rangeA.rdLoc, rangeB.rdLoc,
call[3].getStr.rope])
else: # `||`(a, b, step, annotation)
var step: TLoc
initLocExpr(p, call[3], step)
var step: TLoc = initLocExpr(p, call[3])
lineF(p, cpsStmts, "$n#pragma omp $5$n" &
"for ($1 = $2; $1 <= $3; $1 += $4)",
[forLoopVar.loc.rdLoc,
@@ -756,8 +758,7 @@ proc raiseInstr(p: BProc; result: var Rope) =
proc genRaiseStmt(p: BProc, t: PNode) =
if t[0].kind != nkEmpty:
var a: TLoc
initLocExprSingleUse(p, t[0], a)
var a: TLoc = initLocExprSingleUse(p, t[0])
finallyActions(p)
var e = rdLoc(a)
discard getTypeDesc(p.module, t[0].typ)
@@ -787,12 +788,12 @@ template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
var x, y: TLoc
for i in 0..<b.len - 1:
if b[i].kind == nkRange:
initLocExpr(p, b[i][0], x)
initLocExpr(p, b[i][1], y)
x = initLocExpr(p, b[i][0])
y = initLocExpr(p, b[i][1])
lineCg(p, cpsStmts, rangeFormat,
[rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
else:
initLocExpr(p, b[i], x)
x = initLocExpr(p, b[i])
lineCg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
@@ -834,8 +835,7 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
template genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: FormatStr) =
var a: TLoc
initLocExpr(p, t[0], a)
var a: TLoc = initLocExpr(p, t[0])
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, t.len-1, a)
fixLabel(p, lend)
@@ -845,8 +845,8 @@ proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
var x: TLoc
for i in 0..<b.len - 1:
assert(b[i].kind != nkRange)
initLocExpr(p, b[i], x)
var j: int
x = initLocExpr(p, b[i])
var j: int = 0
case b[i].kind
of nkStrLit..nkTripleStrLit:
j = int(hashString(p.config, b[i].strVal) and high(branches))
@@ -869,8 +869,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
var bitMask = math.nextPowerOfTwo(strings) - 1
var branches: seq[Rope]
newSeq(branches, bitMask + 1)
var a: TLoc
initLocExpr(p, t[0], a) # fist pass: generate ifs+goto:
var a: TLoc = initLocExpr(p, t[0]) # first pass: generate ifs+goto:
var labId = p.labels
for i in 1..<t.len:
inc(p.labels)
@@ -906,6 +905,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
proc branchHasTooBigRange(b: PNode): bool =
result = false
for it in b:
# last son is block
if (it.kind == nkRange) and
@@ -913,6 +913,7 @@ proc branchHasTooBigRange(b: PNode): bool =
return true
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
result = 0
for i in 1..<n.len:
var branch = n[i]
var stmtBlock = lastSon(branch)
@@ -948,8 +949,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
var splitPoint = ifSwitchSplitPoint(p, n)
# generate if part (might be empty):
var a: TLoc
initLocExpr(p, n[0], a)
var a: TLoc = initLocExpr(p, n[0])
var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
eqFormat = "if ($1 == $2) goto $3;$n",
@@ -971,15 +971,18 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
hasDefault = true
exprBlock(p, branch.lastSon, d)
lineF(p, cpsStmts, "break;$n", [])
if (hasAssume in CC[p.config.cCompiler].props) and not hasDefault:
lineF(p, cpsStmts, "default: __assume(0);$n", [])
if not hasDefault:
if hasBuiltinUnreachable in CC[p.config.cCompiler].props:
lineF(p, cpsStmts, "default: __builtin_unreachable();$n", [])
elif hasAssume in CC[p.config.cCompiler].props:
lineF(p, cpsStmts, "default: __assume(0);$n", [])
lineF(p, cpsStmts, "}$n", [])
if lend != "": fixLabel(p, lend)
proc genCase(p: BProc, t: PNode, d: var TLoc) =
genLineDir(p, t)
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
d = getTemp(p, t.typ)
case skipTypes(t[0].typ, abstractVarRange).kind
of tyString:
genStringCase(p, t, tyString, d)
@@ -1030,7 +1033,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
p.module.includeHeader("<exception>")
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
d = getTemp(p, t.typ)
genLineDir(p, t)
inc(p.labels, 2)
@@ -1195,7 +1198,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
expr(p, body, d)
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
d = getTemp(p, t.typ)
genLineDir(p, t)
cgsym(p.module, "popCurrentExceptionEx")
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
@@ -1273,7 +1276,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
p.flags.incl nimErrorFlagAccessed
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
d = getTemp(p, t.typ)
expr(p, t[0], d)
@@ -1380,7 +1383,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
# propagateCurrentException();
#
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
d = getTemp(p, t.typ)
let quirkyExceptions = p.config.exc == excQuirky or
(t.kind == nkHiddenTryStmt and sfSystemModule in p.module.module.flags)
if not quirkyExceptions:
@@ -1389,7 +1392,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
p.flags.incl noSafePoints
genLineDir(p, t)
cgsym(p.module, "Exception")
var safePoint: Rope
var safePoint: Rope = ""
if not quirkyExceptions:
safePoint = getTempName(p.module)
linefmt(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
@@ -1454,7 +1457,8 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
if optTinyRtti in p.config.globalOptions:
let checkFor = $getObjDepth(t[i][j].typ)
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)",
[memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
else:
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
@@ -1492,8 +1496,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
of nkSym:
var sym = it.sym
if sym.kind in {skProc, skFunc, skIterator, skMethod}:
var a: TLoc
initLocExpr(p, it, a)
var a: TLoc = initLocExpr(p, it)
res.add($rdLoc(a))
elif sym.kind == skType:
res.add($getTypeDesc(p.module, sym.typ))
@@ -1505,8 +1508,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
res.add($getTypeDesc(p.module, it.typ))
else:
discard getTypeDesc(p.module, skipTypes(it.typ, abstractPtrs))
var a: TLoc
initLocExpr(p, it, a)
var a: TLoc = initLocExpr(p, it)
res.add($a.rdLoc)
if isAsmStmt and hasGnuAsm in CC[p.config.cCompiler].props:
@@ -1608,11 +1610,10 @@ when false:
expr(p, call, d)
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
var a, tmp: TLoc
var dotExpr = e[0]
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0]
initLocExpr(p, e[0], a)
getTemp(p, a.t, tmp)
var a = initLocExpr(p, e[0])
var tmp: TLoc = getTemp(p, a.t)
expr(p, e[1], tmp)
if p.inUncheckedAssignSection == 0:
let field = dotExpr[1].sym
@@ -1630,9 +1631,8 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
else:
let le = e[0]
let ri = e[1]
var a: TLoc
var a: TLoc = initLoc(locNone, le, OnUnknown)
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar)
initLoc(a, locNone, le, OnUnknown)
a.flags.incl(lfEnforceDeref)
a.flags.incl(lfPrepareForMutation)
genLineDir(p, le) # it can be a nkBracketExpr, which may raise
@@ -1644,7 +1644,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
loadInto(p, le, ri, a)
proc genStmts(p: BProc, t: PNode) =
var a: TLoc
var a: TLoc = default(TLoc)
let isPush = p.config.hasHint(hintExtendedContext)
if isPush: pushInfoContext(p.config, t.info)

View File

@@ -21,7 +21,7 @@ const
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType)
proc genCaseRange(p: BProc, branch: PNode)
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
typ: PType) =
@@ -74,8 +74,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
genTraverseProc(c, accessor, lastSon(typ))
of tyArray:
let arraySize = lengthOrd(c.p.config, typ[0])
var i: TLoc
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i)
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
var oldCode = p.s(cpsStmts)
freeze oldCode
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
@@ -119,12 +118,10 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
var p = c.p
assert typ.kind == tySequence
var i: TLoc
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i)
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
var oldCode = p.s(cpsStmts)
freeze oldCode
var a: TLoc
a.r = accessor
var a: TLoc = TLoc(r: accessor)
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.r, lenExpr(c.p, a)])

View File

@@ -11,8 +11,9 @@
# ------------------------- Name Mangling --------------------------------
import sighashes, modulegraphs, strscans
import sighashes, modulegraphs, std/strscans
import ../dist/checksums/src/checksums/md5
import std/sequtils
type
TypeDescKind = enum
@@ -24,7 +25,7 @@ type
dkResult #skResult
dkConst #skConst
dkOther #skType, skTemp, skLet and skForVar so far
proc descKindFromSymKind(kind: TSymKind): TypeDescKind =
case kind
of skParam: dkParam
@@ -33,7 +34,7 @@ proc descKindFromSymKind(kind: TSymKind): TypeDescKind =
of skResult: dkResult
of skConst: dkConst
else: dkOther
proc isKeyword(w: PIdent): bool =
# Nim and C++ share some keywords
# it's more efficient to test the whole Nim keywords range
@@ -54,31 +55,13 @@ proc mangleField(m: BModule; name: PIdent): string =
if isKeyword(name):
result.add "_0"
proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string =
result = "_Z" # Common prefix in Itanium ABI
result.add encodeSym(m, s, makeUnique)
if s.typ.len > 1: #we dont care about the return param
for i in 1..<s.typ.len:
if s.typ[i].isNil: continue
result.add encodeType(m, s.typ[i])
if result in m.g.mangledPrcs:
result = mangleProc(m, s, true)
else:
m.g.mangledPrcs.incl(result)
proc fillBackendName(m: BModule; s: PSym) =
if s.loc.r == "":
var result: Rope
if s.kind in routineKinds and optCDebug in m.g.config.globalOptions and
m.g.config.symbolFiles == disabledSf:
result = mangleProc(m, s, false).rope
else:
result = s.name.s.mangle.rope
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.addInt s.itemId.item # s.disamb #
var result = s.name.s.mangle.rope
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.addInt s.itemId.item # s.disamb #
if m.hcrOn:
result.add '_'
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config))
@@ -224,8 +207,12 @@ proc mapType(conf: ConfigRef; typ: PType; isParam: bool): TCTypeKind =
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
of tyStatic:
if typ.n != nil: result = mapType(conf, lastSon typ, isParam)
else: doAssert(false, "mapType: " & $typ.kind)
else: doAssert(false, "mapType: " & $typ.kind)
else:
result = ctVoid
doAssert(false, "mapType: " & $typ.kind)
else:
result = ctVoid
doAssert(false, "mapType: " & $typ.kind)
proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind =
@@ -324,6 +311,9 @@ proc getSimpleTypeDesc(m: BModule; typ: PType): Rope =
result = typeNameOrLiteral(m, typ, "void*")
of tyString:
case detectStrVersion(m)
of 3:
cgsym(m, "NimStringV3")
result = typeNameOrLiteral(m, typ, "NimStringV3")
of 2:
cgsym(m, "NimStrPayload")
cgsym(m, "NimStringV2")
@@ -340,7 +330,9 @@ proc getSimpleTypeDesc(m: BModule; typ: PType): Rope =
of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ[0])
of tyStatic:
if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ)
else: internalError(m.config, "tyStatic for getSimpleTypeDesc")
else:
result = ""
internalError(m.config, "tyStatic for getSimpleTypeDesc")
of tyGenericInst, tyAlias, tySink, tyOwned:
result = getSimpleTypeDesc(m, lastSon typ)
else: result = ""
@@ -476,7 +468,7 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr
var num = 0
while i < frmt.len:
if frmt[i] == c:
inc(i)
inc(i)
case frmt[i]
of c:
res.add(c)
@@ -489,11 +481,11 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr
if i >= frmt.len or frmt[i] notin {'0'..'9'}: break
num = j
if j > high(arg) + 1:
doAssert false, "invalid format string: " & frmt
raiseAssert "invalid format string: " & frmt
else:
res.add(arg[j-1])
else:
doAssert false, "invalid format string: " & frmt
raiseAssert "invalid format string: " & frmt
var start = i
while i < frmt.len:
if frmt[i] != c: inc(i)
@@ -505,12 +497,12 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr
template cgDeclFrmt*(s: PSym): string =
s.constraint.strVal
proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var string,
proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params: var string,
check: var IntSet, declareEnvironment=true;
weakDep=false;) =
let t = prc.typ
let isCtor = sfConstructor in prc.flags
if isCtor:
if isCtor or (name[0] == '~' and sfMember in prc.flags): #destructors cant have void
rettype = ""
elif t[0] == nil or isInvalidReturnType(m.config, t):
rettype = "void"
@@ -519,8 +511,8 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var
rettype = getTypeDescAux(m, t[0], check, dkResult)
else:
rettype = runtimeFormat(rettype.replace("'0", "$1"), [getTypeDescAux(m, t[0], check, dkResult)])
var types, names, args: seq[string]
if not isCtor:
var types, names, args: seq[string] = @[]
if not isCtor:
var this = t.n[1].sym
fillParamName(m, this)
fillLoc(this.loc, locParam, t.n[1],
@@ -533,7 +525,7 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var
types.add getTypeDescWeak(m, this.typ, check, dkParam)
let firstParam = if isCtor: 1 else: 2
for i in firstParam..<t.n.len:
for i in firstParam..<t.n.len:
if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genMemberProcParams")
var param = t.n[i].sym
var descKind = dkParam
@@ -567,6 +559,7 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var
multiFormat(params, @['\'', '#'], [types, names])
multiFormat(superCall, @['\'', '#'], [types, names])
multiFormat(name, @['\'', '#'], [types, names]) #so we can ~'1 on members
if params == "()":
if types.len == 0:
params = "(void)"
@@ -660,6 +653,28 @@ proc mangleRecFieldName(m: BModule; field: PSym): Rope =
result = rope(mangleField(m, field.name))
if result == "": internalError(m.config, field.info, "mangleRecFieldName")
proc hasCppCtor(m: BModule; typ: PType): bool =
result = false
if m.compileToCpp and typ != nil and typ.itemId in m.g.graph.memberProcsPerType:
for prc in m.g.graph.memberProcsPerType[typ.itemId]:
if sfConstructor in prc.flags:
return true
proc genCppParamsForCtor(p: BProc; call: PNode): string
proc genCppInitializer(m: BModule, prc: BProc; typ: PType): string =
#To avoid creating a BProc per test when called inside a struct nil BProc is allowed
result = "{}"
if typ.itemId in m.g.graph.initializersPerType:
let call = m.g.graph.initializersPerType[typ.itemId]
if call != nil:
var p = prc
if p == nil:
p = BProc(module: m)
result = "{" & genCppParamsForCtor(p, call) & "}"
if prc == nil:
assert p.blocks.len == 0, "BProc belongs to a struct doesnt have blocks"
proc genRecordFieldsAux(m: BModule; n: PNode,
rectype: PType,
check: var IntSet; result: var Rope; unionPrefix = "") =
@@ -724,8 +739,10 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
else:
# don't use fieldType here because we need the
# tyGenericInst for C++ template support
if fieldType.isOrHasImportedCppType():
result.addf("\t$1$3 $2{};$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias])
let noInit = sfNoInit in field.flags or (field.typ.sym != nil and sfNoInit in field.typ.sym.flags)
if not noInit and (fieldType.isOrHasImportedCppType() or hasCppCtor(m, field.owner.typ)):
var initializer = genCppInitializer(m, nil, fieldType)
result.addf("\t$1$3 $2$4;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias, initializer])
else:
result.addf("\t$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias])
else: internalError(m.config, n.info, "genRecordFieldsAux()")
@@ -737,19 +754,20 @@ proc getRecordFields(m: BModule; typ: PType, check: var IntSet): Rope =
genRecordFieldsAux(m, typ.n, typ, check, result)
if typ.itemId in m.g.graph.memberProcsPerType:
let procs = m.g.graph.memberProcsPerType[typ.itemId]
var isDefaultCtorGen, isCtorGen: bool
var isDefaultCtorGen, isCtorGen: bool = false
for prc in procs:
var header: Rope
var header: Rope = ""
if sfConstructor in prc.flags:
isCtorGen = true
if prc.typ.n.len == 1:
isDefaultCtorGen = true
if lfNoDecl in prc.loc.flags: continue
genMemberProcHeader(m, prc, header, false, true)
result.addf "$1;$n", [header]
if isCtorGen and not isDefaultCtorGen:
var ch: IntSet
result.addf "$1() = default;$n", [getTypeDescAux(m, typ, ch, dkOther)]
proc fillObjectFields*(m: BModule; typ: PType) =
# sometimes generic objects are not consistently merged. We patch over
# this fact here.
@@ -757,9 +775,10 @@ proc fillObjectFields*(m: BModule; typ: PType) =
discard getRecordFields(m, typ, check)
proc mangleDynLibProc(sym: PSym): Rope
proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope,
check: var IntSet, hasField:var bool): Rope =
check: var IntSet, hasField:var bool): Rope =
result = ""
if typ.kind == tyObject:
if typ[0] == nil:
if lacksMTypeField(typ):
@@ -800,8 +819,8 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope,
structOrUnion = "#pragma pack(push, 1)\L" & structOrUnion(typ)
else:
structOrUnion = structOrUnion(typ)
var baseType: string
if typ[0] != nil:
var baseType: string = ""
if typ[0] != nil:
baseType = getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, dkField)
if typ.sym == nil or sfCodegenDecl notin typ.sym.flags:
result = structOrUnion & " " & name
@@ -857,7 +876,7 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
# Make sure the index refers to one of the generic params of the type.
# XXX: we should catch this earlier and report it as a semantic error.
if idx >= typ.len:
doAssert false, "invalid apostrophe type parameter index"
raiseAssert "invalid apostrophe type parameter index"
result = typ[idx]
for i in 1..stars:
@@ -891,6 +910,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym)
let sig = hashType(origTyp, m.config)
result = "" # todo move `result = getTypePre(m, t, sig)` here ?
defer: # defer is the simplest in this case
if isImportedType(t) and not m.typeABICache.containsOrIncl(sig):
addAbiCheck(m, t, result)
@@ -971,7 +991,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
of tyProc:
result = getTypeName(m, origTyp, sig)
m.typeCache[sig] = result
var rettype, desc: Rope
var rettype, desc: Rope = ""
genProcParams(m, t, rettype, desc, check, true, true)
if not isImportedType(t):
if t.callConv != ccClosure: # procedure vars may need a closure!
@@ -1048,7 +1068,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
while i < cppName.len:
if cppName[i] == '\'':
var chunkEnd = i-1
var idx, stars: int
var idx, stars: int = 0
if scanCppGenericSlot(cppName, i, idx, stars):
result.add cppName.substr(chunkStart, chunkEnd)
chunkStart = i
@@ -1112,8 +1132,8 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
result = ""
# fixes bug #145:
excl(check, t.id)
proc getTypeDesc(m: BModule; typ: PType; kind = dkParam): Rope =
var check = initIntSet()
result = getTypeDescAux(m, typ, check, kind)
@@ -1128,7 +1148,7 @@ proc getClosureType(m: BModule; t: PType, kind: TClosureTypeKind): Rope =
assert t.kind == tyProc
var check = initIntSet()
result = getTempName(m)
var rettype, desc: Rope
var rettype, desc: Rope = ""
genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
if not isImportedType(t):
if t.callConv != ccClosure or kind != clFull:
@@ -1158,11 +1178,19 @@ proc isReloadable(m: BModule; prc: PSym): bool =
proc isNonReloadable(m: BModule; prc: PSym): bool =
return m.hcrOn and sfNonReloadable in prc.flags
proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride: var bool; isCtor: bool) =
var afterParams: string
proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride, isMemberVirtual: var bool; isCtor: bool, isFunctor=false) =
var afterParams: string = ""
if scanf(val, "$*($*)$s$*", name, params, afterParams):
if name.strip() == "operator" and params == "": #isFunctor?
parseVFunctionDecl(afterParams, name, params, retType, superCall, isFnConst, isOverride, isMemberVirtual, isCtor, true)
return
isFnConst = afterParams.find("const") > -1
isOverride = afterParams.find("override") > -1
isMemberVirtual = name.find("virtual ") > -1
if isMemberVirtual:
name = name.replace("virtual ", "")
if isFunctor:
name = "operator ()"
if isCtor:
discard scanf(afterParams, ":$s$*", superCall)
else:
@@ -1171,28 +1199,28 @@ proc parseVFunctionDecl(val: string; name, params, retType, superCall: var strin
params = "(" & params & ")"
proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl : bool = false) =
assert {sfVirtual, sfConstructor} * prc.flags != {}
assert sfCppMember * prc.flags != {}
let isCtor = sfConstructor in prc.flags
let isVirtual = not isCtor
var check = initIntSet()
fillBackendName(m, prc)
fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown)
var memberOp = "#." #only virtual
var typ: PType
if isCtor:
typ = prc.typ.sons[0]
typ = prc.typ[0]
else:
typ = prc.typ.sons[1]
typ = prc.typ[1]
if typ.kind == tyPtr:
typ = typ[0]
memberOp = "#->"
var typDesc = getTypeDescWeak(m, typ, check, dkParam)
let asPtrStr = rope(if asPtr: "_PTR" else: "")
var name, params, rettype, superCall: string
var isFnConst, isOverride: bool
parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isCtor)
genMemberProcParams(m, prc, superCall, rettype, params, check, true, false)
var fnConst, override: string
var name, params, rettype, superCall: string = ""
var isFnConst, isOverride, isMemberVirtual: bool = false
parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isMemberVirtual, isCtor)
genMemberProcParams(m, prc, superCall, rettype, name, params, check, true, false)
let isVirtual = sfVirtual in prc.flags or isMemberVirtual
var fnConst, override: string = ""
if isCtor:
name = typDesc
if isFnConst:
@@ -1200,28 +1228,28 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool =
if isFwdDecl:
if isVirtual:
rettype = "virtual " & rettype
if isOverride:
if isOverride:
override = " override"
superCall = ""
else:
if isVirtual:
if not isCtor:
prc.loc.r = "$1$2(@)" % [memberOp, name]
elif superCall != "":
superCall = " : " & superCall
name = "$1::$2" % [typDesc, name]
result.add "N_LIB_PRIVATE "
result.addf("$1$2($3, $4)$5$6$7$8",
[rope(CallingConvToStr[prc.typ.callConv]), asPtrStr, rettype, name,
params, fnConst, override, superCall])
proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false) =
# using static is needed for inline procs
var check = initIntSet()
fillBackendName(m, prc)
fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown)
var rettype, params: Rope
var rettype, params: Rope = ""
genProcParams(m, prc.typ, rettype, params, check, true, false)
# handle the 2 options for hotcodereloading codegen - function pointer
# (instead of forward declaration) or header for function body with "_actual" postfix
@@ -1461,7 +1489,7 @@ proc genEnumInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
genTypeInfoAux(m, typ, typ, name, info)
var nodePtrs = getTempName(m) & "_" & $typ.n.len
genTNimNodeArray(m, nodePtrs, rope(typ.n.len))
var enumNames, specialCases: Rope
var enumNames, specialCases: Rope = ""
var firstNimNode = m.typeNodes
var hasHoles = false
for i in 0..<typ.n.len:
@@ -1506,9 +1534,9 @@ proc genArrayInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
proc fakeClosureType(m: BModule; owner: PSym): PType =
# we generate the same RTTI as for a tuple[pointer, ref tuple[]]
result = newType(tyTuple, nextTypeId m.idgen, owner)
result.rawAddSon(newType(tyPointer, nextTypeId m.idgen, owner))
var r = newType(tyRef, nextTypeId m.idgen, owner)
result = newType(tyTuple, m.idgen, owner)
result.rawAddSon(newType(tyPointer, m.idgen, owner))
var r = newType(tyRef, m.idgen, owner)
let obj = createObj(m.g.graph, m.idgen, owner, owner.info, final=false)
r.rawAddSon(obj)
result.rawAddSon(r)
@@ -1540,6 +1568,7 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope =
result = it.sym.name.s
else:
var p = m.owner
result = ""
if p != nil and p.kind == skPackage:
result.add p.name.s & "."
result.add m.name.s & "."
@@ -1550,10 +1579,6 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope =
proc isTrivialProc(g: ModuleGraph; s: PSym): bool {.inline.} = getBody(g, s).len == 0
proc makePtrType(baseType: PType; idgen: IdGenerator): PType =
result = newType(tyPtr, nextTypeId idgen, baseType.owner)
addSonSkipIntLit(result, baseType, idgen)
proc generateRttiDestructor(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator; theProc: PSym): PSym =
# the wrapper is roughly like:
@@ -1565,7 +1590,7 @@ proc generateRttiDestructor(g: ModuleGraph; typ: PType; owner: PSym; kind: TType
dest.typ = getSysType(g, info, tyPointer)
result.typ = newProcType(info, nextTypeId(idgen), owner)
result.typ = newProcType(info, idgen, owner)
result.typ.addParam dest
var n = newNodeI(nkProcDef, info, bodyPos+1)
@@ -1656,6 +1681,13 @@ proc genDisplay(m: BModule; t: PType, depth: int): Rope =
result.add seqs[0]
result.add "}"
proc genVTable(seqs: seq[PSym]): string =
result = "{"
for i in 0..<seqs.len:
if i > 0: result.add ", "
result.add "(void *) " & seqs[i].loc.r
result.add "}"
proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) =
cgsym(m, "TNimTypeV2")
m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name])
@@ -1692,6 +1724,14 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin
m.s[cfsVars].addf("static $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), dkVar), objDisplayStore, rope(objDepth+1), objDisplay])
addf(typeEntry, "$1.display = $2;$n", [name, rope(objDisplayStore)])
let dispatchMethods = toSeq(getMethodsPerType(m.g.graph, t))
if dispatchMethods.len > 0:
let vTablePointerName = getTempName(m)
m.s[cfsVars].addf("static void* $1[$2] = $3;$n", [vTablePointerName, rope(dispatchMethods.len), genVTable(dispatchMethods)])
for i in dispatchMethods:
genProcPrototype(m, i)
addf(typeEntry, "$1.vTable = $2;$n", [name, vTablePointerName])
m.s[cfsTypeInit3].add typeEntry
if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
@@ -1733,8 +1773,16 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn
add(typeEntry, ", .traceImpl = (void*)")
genHook(m, t, info, attachedTrace, typeEntry)
addf(typeEntry, ", .flags = $1};$n", [rope(flags)])
m.s[cfsVars].add typeEntry
let dispatchMethods = toSeq(getMethodsPerType(m.g.graph, t))
if dispatchMethods.len > 0:
addf(typeEntry, ", .flags = $1", [rope(flags)])
for i in dispatchMethods:
genProcPrototype(m, i)
addf(typeEntry, ", .vTable = $1};$n", [genVTable(dispatchMethods)])
m.s[cfsVars].add typeEntry
else:
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)
@@ -1772,16 +1820,16 @@ 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:
if m.compileToCpp or m.hcrOn:
genTypeInfoV2OldImpl(m, t, origType, result, info)
else:
genTypeInfoV2Impl(m, t, origType, result, info)
result = prefixTI.rope & result & ")".rope
proc openArrayToTuple(m: BModule; t: PType): PType =
result = newType(tyTuple, nextTypeId m.idgen, t.owner)
let p = newType(tyPtr, nextTypeId m.idgen, t.owner)
let a = newType(tyUncheckedArray, nextTypeId m.idgen, t.owner)
result = newType(tyTuple, m.idgen, t.owner)
let p = newType(tyPtr, m.idgen, t.owner)
let a = newType(tyUncheckedArray, m.idgen, t.owner)
a.add t.lastSon
p.add a
result.add p
@@ -1921,14 +1969,14 @@ proc genTypeInfo*(config: ConfigRef, m: BModule; t: PType; info: TLineInfo): Rop
else:
result = genTypeInfoV1(m, t, info)
proc genTypeSection(m: BModule, n: PNode) =
proc genTypeSection(m: BModule, n: PNode) =
var intSet = initIntSet()
for i in 0..<n.len:
if len(n[i]) == 0: continue
if n[i][0].kind != nkPragmaExpr: continue
for p in 0..<n[i][0].len:
if (n[i][0][p].kind != nkSym): continue
if sfExportc in n[i][0][p].sym.flags:
if sfExportc in n[i][0][p].sym.flags:
discard getTypeDescAux(m, n[i][0][p].typ, intSet, descKindFromSymKind(n[i][0][p].sym.kind))
if m.g.generatedHeader != nil:
discard getTypeDescAux(m.g.generatedHeader, n[i][0][p].typ, intSet, descKindFromSymKind(n[i][0][p].sym.kind))

View File

@@ -10,10 +10,10 @@
# This module declares some helpers for the C code generator.
import
ast, types, hashes, strutils, msgs, wordrecg,
ast, types, msgs, wordrecg,
platform, trees, options, cgendata
import std/[hashes, strutils, formatfloat]
import std/[hashes, strutils]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -21,13 +21,16 @@ when defined(nimPreviewSlimSystem):
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
case n.kind
of nkStmtList:
result = nil
for i in 0..<n.len:
result = getPragmaStmt(n[i], w)
if result != nil: break
of nkPragma:
result = nil
for i in 0..<n.len:
if whichPragma(n[i]) == w: return n[i]
else: discard
else:
result = nil
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
result = getPragmaStmt(n, w) != nil
@@ -123,10 +126,10 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind =
proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
var pt = skipTypes(s.typ, typedescInst)
assert skResult != s.kind
#note precedence: params override types
if optByRef in s.options: return true
elif sfByCopy in s.flags: return false
elif sfByCopy in s.flags: return false
elif tfByRef in pt.flags: return true
elif tfByCopy in pt.flags: return false
case pt.kind
@@ -150,64 +153,3 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or
pt.kind == tySet and mapSetType(conf, pt) == ctArray)
proc encodeName*(name: string): string =
result = mangle(name)
result = $result.len & result
proc makeUnique(m: BModule; s: PSym, name: string = ""): string =
result = if name == "": s.name.s else: name
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.add $s.itemId.item
proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string =
#Module::Type
var name = s.name.s
if makeUnique:
name = makeUnique(m, s, name)
"N" & encodeName(s.owner.name.s) & encodeName(name) & "E"
proc elementType*(n: PType): PType {.inline.} = n.sons[^1]
proc encodeType*(m: BModule; t: PType): string =
result = ""
var kindName = ($t.kind)[2..^1]
kindName[0] = toLower($kindName[0])[0]
case t.kind
of tyObject, tyEnum, tyDistinct, tyUserTypeClass, tyGenericParam:
result = encodeSym(m, t.sym)
of tyGenericInst, tyUserTypeClassInst, tyGenericBody:
result = encodeName(t[0].sym.name.s)
result.add "I"
for i in 1..<t.len - 1:
result.add encodeType(m, t[i])
result.add "E"
of tySequence, tyOpenArray, tyArray, tyVarargs, tyTuple, tyProc, tySet, tyTypeDesc,
tyPtr, tyRef, tyVar, tyLent, tySink, tyStatic, tyUncheckedArray, tyOr, tyAnd, tyBuiltInTypeClass:
result =
case t.kind:
of tySequence: encodeName("seq")
else: encodeName(kindName)
result.add "I"
for i in 0..<t.len:
let s = t[i]
if s.isNil: continue
result.add encodeType(m, s)
result.add "E"
of tyRange:
var val = "range_"
if t.n[0].typ.kind in {tyFloat..tyFloat128}:
val.addFloat t.n[0].floatVal
val.add "_"
val.addFloat t.n[1].floatVal
else:
val.add $t.n[0].intVal & "_" & $t.n[1].intVal
result = encodeName(val)
of tyString..tyUInt64, tyPointer, tyBool, tyChar, tyVoid, tyAnything, tyNil, tyEmpty:
result = encodeName(kindName)
of tyAlias, tyInferred, tyOwned:
result = encodeType(m, t.elementType)
else:
assert false, "encodeType " & $t.kind

View File

@@ -10,13 +10,15 @@
## This module implements the C code generator.
import
ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
ast, astalgo, trees, platform, magicsys, extccomp, options,
nversion, nimsets, msgs, bitsets, idents, types,
ccgutils, os, ropes, math, wordrecg, treetab, cgmeth,
ccgutils, ropes, wordrecg, treetab, cgmeth,
rodutils, renderer, cgendata, aliases,
lowerings, tables, sets, ndi, lineinfos, pathutils, transf,
lowerings, ndi, lineinfos, pathutils, transf,
injectdestructors, astmsgs, modulepaths, backendpragmas
from expanddefaults import caseObjDefaultBranch
import pipelineutils
when defined(nimPreviewSlimSystem):
@@ -25,10 +27,10 @@ when defined(nimPreviewSlimSystem):
when not defined(leanCompiler):
import spawn, semparallel
import strutils except `%`, addf # collides with ropes.`%`
import std/strutils except `%`, addf # collides with ropes.`%`
from ic / ic import ModuleBackendFlag
import dynlib
import std/[dynlib, math, tables, sets, os, intsets, hashes]
when not declared(dynlib.libCandidates):
proc libCandidates(s: string, dest: var seq[string]) =
@@ -61,12 +63,10 @@ proc findPendingModule(m: BModule, s: PSym): BModule =
var ms = getModule(s)
result = m.g.modules[ms.position]
proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}) =
result.k = k
result.storage = s
result.lode = lode
result.r = ""
result.flags = flags
proc initLoc(k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}): TLoc =
result = TLoc(k: k, storage: s, lode: lode,
r: "", flags: flags
)
proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) {.inline.} =
# fills the loc if it is not already initialized
@@ -121,7 +121,7 @@ proc getModuleDllPath(m: BModule, module: int): Rope =
proc getModuleDllPath(m: BModule, s: PSym): Rope =
result = getModuleDllPath(m.g.modules[s.itemId.module])
import macros
import std/macros
proc cgFormatValue(result: var string; value: string) =
result.add value
@@ -291,6 +291,8 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
p.lastLineInfo.line = info.line
p.lastLineInfo.fileIndex = info.fileIndex
result = true
else:
result = false
proc genCLineDir(r: var Rope, p: BProc, info: TLineInfo; conf: ConfigRef) =
if optLineDir in conf.options:
@@ -299,6 +301,7 @@ proc genCLineDir(r: var Rope, p: BProc, info: TLineInfo; conf: ConfigRef) =
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, p, info, lastFileIndex)
proc genLineDir(p: BProc, t: PNode) =
if p == p.module.preInitProc: return
let line = t.info.safeLineNm
if optEmbedOrigSrc in p.config.globalOptions:
@@ -345,9 +348,12 @@ proc addRdLoc(a: TLoc; result: var Rope) =
proc lenField(p: BProc): Rope {.inline.} =
result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
proc lenExpr(p: BProc; a: TLoc): Rope =
proc lenExpr(p: BProc; a: TLoc; isString = false): Rope =
if optSeqDestructors in p.config.globalOptions:
result = rdLoc(a) & ".len"
if isString and p.config.isDefined("nimSeqsV3"):
result = ropecg(p.module, "(#nimStrLenV3($1))", [rdLoc(a)])
else:
result = rdLoc(a) & ".len"
else:
result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)]
@@ -357,12 +363,18 @@ proc dataFieldAccessor(p: BProc, sym: Rope): Rope =
else:
result = sym
proc dataField(p: BProc): Rope =
proc dataField(p: BProc; isString: bool = false): Rope =
# TODO: revisit this after unify strings and seqs
if optSeqDestructors in p.config.globalOptions:
result = rope".p->data"
if isString and p.config.isDefined("nimSeqsV3"):
result = rope".p"
else:
result = rope".p->data"
else:
result = rope"->data"
proc genProcPrototype(m: BModule, sym: PSym)
include ccgliterals
include ccgtypes
@@ -432,7 +444,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
of frEmbedded:
if optTinyRtti in p.config.globalOptions:
var tmp: TLoc
var tmp: TLoc = default(TLoc)
if mode == constructRefObj:
let objType = t.skipTypes(abstractInst+{tyRef})
rawConstExpr(p, newNodeIT(nkType, a.lode.info, objType), tmp)
@@ -474,14 +486,19 @@ proc resetLoc(p: BProc, loc: var TLoc) =
assert loc.r != ""
let atyp = skipTypes(loc.t, abstractInst)
if atyp.kind in {tyVar, tyLent}:
linefmt(p, cpsStmts, "$1->len = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)])
if p.config.isDefined("nimSeqsV3") and typ.kind == tyString:
if atyp.kind in {tyVar, tyLent}:
linefmt(p, cpsStmts, "$1->rawlen = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)])
else:
linefmt(p, cpsStmts, "$1.rawlen = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
else:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
if atyp.kind in {tyVar, tyLent}:
linefmt(p, cpsStmts, "$1->len = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)])
else:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
elif not isComplexValueType(typ):
if containsGcRef:
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.lode, OnStack)
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
nilLoc.r = rope("NIM_NIL")
genRefAssign(p, loc, nilLoc)
else:
@@ -498,21 +515,32 @@ proc resetLoc(p: BProc, loc: var TLoc) =
else:
# array passed as argument decayed into pointer, bug #7332
# so we use getTypeDesc here rather than rdLoc(loc)
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc),
getTypeDesc(p.module, loc.t, descKindFromSymKind mapTypeChooser(loc))])
let tyDesc = getTypeDesc(p.module, loc.t, descKindFromSymKind mapTypeChooser(loc))
if p.module.compileToCpp and isOrHasImportedCppType(typ):
if lfIndirect in loc.flags:
#C++ cant be just zeroed. We need to call the ctors
var tmp = getTemp(p, loc.t)
linefmt(p, cpsStmts,"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
[addrLoc(p.config, loc), addrLoc(p.config, tmp), tyDesc])
else:
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc), tyDesc])
# XXX: We can be extra clever here and call memset only
# on the bytes following the m_type field?
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
let typ = loc.t
if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
let typKind = skipTypes(typ, abstractInst + {tyStatic}).kind
if optSeqDestructors in p.config.globalOptions and typKind in {tyString, tySequence}:
if typKind == tyString and p.config.isDefined("nimSeqsV3"):
linefmt(p, cpsStmts, "$1.rawlen = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
else:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
elif not isComplexValueType(typ):
if containsGarbageCollectedRef(loc.t):
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.lode, OnStack)
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
nilLoc.r = rope("NIM_NIL")
genRefAssign(p, loc, nilLoc)
else:
@@ -539,17 +567,15 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
if not immediateAsgn:
constructLoc(p, v.loc)
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
inc(p.labels)
result.r = "T" & rope(p.labels) & "_"
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
storage: OnStack, flags: {})
if p.module.compileToCpp and isOrHasImportedCppType(t):
linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, dkVar), result.r])
linefmt(p, cpsLocals, "$1 $2$3;$n", [getTypeDesc(p.module, t, dkVar), result.r,
genCppInitializer(p.module, p, t)])
else:
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkVar), result.r])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
result.flags = {}
constructLoc(p, result, not needsInit)
when false:
# XXX Introduce a compiler switch in order to detect these easily.
@@ -560,25 +586,21 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
echo "ENORMOUS TEMPORARY! ", p.config $ p.lastLineInfo
writeStackTrace()
proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) =
proc getTempCpp(p: BProc, t: PType, value: Rope): TLoc =
inc(p.labels)
result.r = "T" & rope(p.labels) & "_"
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
storage: OnStack, flags: {})
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkVar), result.r, value])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
result.flags = {}
proc getIntTemp(p: BProc, result: var TLoc) =
proc getIntTemp(p: BProc): TLoc =
inc(p.labels)
result.r = "T" & rope(p.labels) & "_"
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp,
storage: OnStack, lode: lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt),
flags: {})
linefmt(p, cpsLocals, "NI $1;$n", [result.r])
result.k = locTemp
result.storage = OnStack
result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt)
result.flags = {}
proc localVarDecl(p: BProc; n: PNode): Rope =
result = ""
let s = n.sym
if s.loc.k == locNone:
fillLocalName(p, s)
@@ -606,7 +628,10 @@ proc assignLocalVar(p: BProc, n: PNode) =
# this need not be fulfilled for inline procs; they are regenerated
# for each module that uses them!
let nl = if optLineDir in p.config.options: "" else: "\n"
let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};" else: ";") & nl
var decl = localVarDecl(p, n)
if p.module.compileToCpp and isOrHasImportedCppType(n.typ):
decl.add genCppInitializer(p.module, p, n.typ)
decl.add ";" & nl
line(p, cpsLocals, decl)
include ccgthreadvars
@@ -640,17 +665,17 @@ proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) =
else:
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope)
proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope)
proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode) =
let s = vn.sym
fillBackendName(p.module, s)
fillLoc(s.loc, locGlobalVar, vn, OnHeap)
var decl: Rope
var decl: Rope = ""
let td = getTypeDesc(p.module, vn.sym.typ, dkVar)
genGlobalVarDecl(p, vn, td, "", decl)
decl.add " " & $s.loc.r
genCppVarForCtor(p, v, vn, value, decl)
genCppVarForCtor(p, value, decl)
p.module.s[cfsVars].add decl
proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
@@ -728,19 +753,19 @@ proc genVarPrototype(m: BModule, n: PNode)
proc requestConstImpl(p: BProc, sym: PSym)
proc genStmts(p: BProc, t: PNode)
proc expr(p: BProc, n: PNode, d: var TLoc)
proc genProcPrototype(m: BModule, sym: PSym)
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
proc intLiteral(i: BiggestInt; result: var Rope)
proc genLiteral(p: BProc, n: PNode; result: var Rope)
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
proc raiseExit(p: BProc)
proc initLocExpr(p: BProc, e: PNode, result: var TLoc, flags: TLocFlags = {}) =
initLoc(result, locNone, e, OnUnknown, flags)
proc initLocExpr(p: BProc, e: PNode, flags: TLocFlags = {}): TLoc =
result = initLoc(locNone, e, OnUnknown, flags)
expr(p, e, result)
proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, e, OnUnknown)
proc initLocExprSingleUse(p: BProc, e: PNode): TLoc =
result = initLoc(locNone, e, OnUnknown)
if e.kind in nkCallKinds and (e[0].kind != nkSym or e[0].sym.magic == mNone):
# We cannot check for tfNoSideEffect here because of mutable parameters.
discard "bug #8202; enforce evaluation order for nested calls for C++ too"
@@ -831,8 +856,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
var p = newProc(nil, m)
p.options.excl optStackTrace
p.flags.incl nimErrorFlagDisabled
var dest: TLoc
initLoc(dest, locTemp, lib.path, OnStack)
var dest: TLoc = initLoc(locTemp, lib.path, OnStack)
dest.r = getTempName(m)
appcg(m, m.s[cfsDynLibInit],"$1 $2;$n",
[getTypeDesc(m, lib.path.typ, dkVar), rdLoc(dest)])
@@ -867,11 +891,10 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
inc(m.labels, 2)
if isCall:
let n = lib.path
var a: TLoc
initLocExpr(m.initProc, n[0], a)
var a: TLoc = initLocExpr(m.initProc, n[0])
var params = rdLoc(a) & "("
for i in 1..<n.len-1:
initLocExpr(m.initProc, n[i], a)
a = initLocExpr(m.initProc, n[i])
params.add(rdLoc(a))
params.add(", ")
let load = "\t$1 = ($2) ($3$4));$n" %
@@ -1007,6 +1030,7 @@ proc containsResult(n: PNode): bool =
if containsResult(n[i]): return true
proc easyResultAsgn(n: PNode): PNode =
result = nil
case n.kind
of nkStmtList, nkStmtListExpr:
var i = 0
@@ -1131,7 +1155,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
proc getProcTypeCast(m: BModule, prc: PSym): Rope =
result = getTypeDesc(m, prc.loc.t)
if prc.typ.callConv == ccClosure:
var rettype, params: Rope
var rettype, params: Rope = ""
var check = initIntSet()
genProcParams(m, prc.typ, rettype, params, check)
result = "$1(*)$2" % [rettype, params]
@@ -1149,14 +1173,15 @@ proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
proc genProcAux*(m: BModule, prc: PSym) =
var p = newProc(prc, m)
var header = newRopeAppender()
if m.config.backend == backendCpp and {sfVirtual, sfConstructor} * prc.flags != {}:
let isCppMember = m.config.backend == backendCpp and sfCppMember * prc.flags != {}
if isCppMember:
genMemberProcHeader(m, prc, header)
else:
genProcHeader(m, prc, header)
var returnStmt: Rope = ""
assert(prc.ast != nil)
var procBody = transformBody(m.g.graph, m.idgen, prc, dontUseCache)
var procBody = transformBody(m.g.graph, m.idgen, prc, {})
if sfInjectDestructors in prc.flags:
procBody = injectDestructorCalls(m.g.graph, m.idgen, prc, procBody)
@@ -1172,8 +1197,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
var decl = localVarDecl(p, resNode)
var a: TLoc
initLocExprSingleUse(p, val, a)
var a: TLoc = initLocExprSingleUse(p, val)
linefmt(p, cpsStmts, "$1 = $2;$n", [decl, rdLoc(a)])
else:
# declare the result symbol:
@@ -1188,6 +1212,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
initLocalVar(p, res, immediateAsgn=false)
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
elif sfConstructor in prc.flags:
resNode.sym.loc.flags.incl lfIndirect
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
else:
fillResult(p.config, resNode, prc.typ)
@@ -1215,13 +1240,13 @@ proc genProcAux*(m: BModule, prc: PSym) =
prc.info = tmpInfo
var generatedProc: Rope
var generatedProc: Rope = ""
generatedProc.genCLineDir prc.info, m.config
if isNoReturn(p.module, prc):
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
header = "__declspec(noreturn) " & header
if sfPure in prc.flags:
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
header = "__declspec(naked) " & header
generatedProc.add ropecg(p.module, "$1 {$n$2$3$4}$N$N",
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
@@ -1266,7 +1291,7 @@ proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym)
if lfNoDecl in sym.loc.flags or {sfVirtual, sfConstructor} * sym.flags != {}: return
if lfNoDecl in sym.loc.flags or sfCppMember * sym.flags != {}: return
if lfDynamicLib in sym.loc.flags:
if sym.itemId.module != m.module.position and
not containsOrIncl(m.declaredThings, sym.id):
@@ -1445,17 +1470,21 @@ proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
proc getSomeNameForModule(conf: ConfigRef, filename: AbsoluteFile): Rope =
## Returns a mangled module name.
result = ""
result.add mangleModuleName(conf, filename).mangle
proc getSomeNameForModule(m: BModule): Rope =
## Returns a mangled module name.
assert m.module.kind == skModule
assert m.module.owner.kind == skPackage
result = ""
result.add mangleModuleName(m.g.config, m.filename).mangle
proc getSomeInitName(m: BModule, suffix: string): Rope =
if not m.hcrOn:
result = getSomeNameForModule(m)
else:
result = ""
result.add suffix
proc getInitName(m: BModule): Rope =
@@ -1474,10 +1503,10 @@ proc genMainProc(m: BModule) =
## this function is called in cgenWriteModules after all modules are closed,
## it means raising dependency on the symbols is too late as it will not propagate
## into other modules, only simple rope manipulations are allowed
var preMainCode: Rope
var preMainCode: Rope = ""
if m.hcrOn:
proc loadLib(handle: string, name: string): Rope =
result = ""
let prc = magicsys.getCompilerProc(m.g.graph, name)
assert prc != nil
let n = newStrNode(nkStrLit, prc.annex.path.strVal)
@@ -1501,7 +1530,7 @@ proc genMainProc(m: BModule) =
else:
preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix])
var posixCmdLine: Rope
var posixCmdLine: Rope = ""
if optNoMain notin m.config.globalOptions:
posixCmdLine.add "N_LIB_PRIVATE int cmdCount;\L"
posixCmdLine.add "N_LIB_PRIVATE char** cmdLine;\L"
@@ -1890,13 +1919,13 @@ proc genInitCode(m: BModule) =
if beforeRetNeeded in m.initProc.flags:
prc.add("\tBeforeRet_: ;\n")
if sfMainModule in m.module.flags and m.config.exc == excGoto:
if m.config.exc == excGoto:
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
prc.add(deinitFrame(m.initProc))
elif sfMainModule in m.module.flags and m.config.exc == excGoto:
elif m.config.exc == excGoto:
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
@@ -1996,7 +2025,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
result.preInitProc = newProc(nil, result)
result.preInitProc.flags.incl nimErrorFlagDisabled
result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated
initNodeTable(result.dataCache)
result.dataCache = initNodeTable()
result.typeStack = @[]
result.typeNodesName = getTempName(result)
result.nimTypesName = getTempName(result)
@@ -2171,7 +2200,7 @@ proc updateCachedModule(m: BModule) =
cf.flags = {CfileFlag.Cached}
addFileToCompile(m.config, cf)
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
## Also called from IC.
if sfMainModule in m.module.flags:
# phase ordering problem here: We need to announce this
@@ -2220,7 +2249,11 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
if m.g.forwardedProcs.len == 0:
incl m.flags, objHasKidsValid
result = generateMethodDispatchers(graph, m.idgen)
if optMultiMethods in m.g.config.globalOptions or
m.g.config.selectedGC notin {gcArc, gcOrc, gcAtomicArc} or
vtables notin m.g.config.features:
generateIfMethodDispatchers(graph, m.idgen)
let mm = m
m.g.modulesClosed.add mm

View File

@@ -10,8 +10,10 @@
## This module contains the data structures for the C code generation phase.
import
ast, ropes, options, intsets,
tables, ndi, lineinfos, pathutils, modulegraphs, sets
ast, ropes, options,
ndi, lineinfos, pathutils, modulegraphs
import std/[intsets, tables, sets]
type
TLabel* = Rope # for the C generator a label is just a rope
@@ -135,7 +137,6 @@ type
# unconditionally...
# nimtvDeps is VERY hard to cache because it's
# not a list of IDs nor can it be made to be one.
mangledPrcs*: HashSet[string]
TCGen = object of PPassContext # represents a C source file
s*: TCFileSections # sections of the C file
@@ -197,6 +198,8 @@ proc newProc*(prc: PSym, module: BModule): BProc =
result = BProc(
prc: prc,
module: module,
optionsStack: if module.initProc != nil: module.initProc.optionsStack
else: @[],
options: if prc != nil: prc.options
else: module.config.options,
blocks: @[initBlock()],

View File

@@ -10,12 +10,15 @@
## This module implements code generation for methods.
import
intsets, options, ast, msgs, idents, renderer, types, magicsys,
sempass2, modulegraphs, lineinfos
options, ast, msgs, idents, renderer, types, magicsys,
sempass2, modulegraphs, lineinfos, astalgo
import std/intsets
when defined(nimPreviewSlimSystem):
import std/assertions
import std/[tables]
proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode =
var dest = skipTypes(d, abstractPtrs)
@@ -44,6 +47,8 @@ proc getDispatcher*(s: PSym): PSym =
if dispatcherPos < s.ast.len:
result = s.ast[dispatcherPos].sym
doAssert sfDispatcher in result.flags
else:
result = nil
proc methodCall*(n: PNode; conf: ConfigRef): PNode =
result = n
@@ -62,6 +67,7 @@ type
MethodResult = enum No, Invalid, Yes
proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
result = No
if a.name.id != b.name.id: return
if a.typ.len != b.typ.len:
return
@@ -95,7 +101,8 @@ proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
return No
if result == Yes:
# check for return type:
if not sameTypeOrNil(a.typ[0], b.typ[0]):
# ignore flags of return types; # bug #22673
if not sameTypeOrNil(a.typ[0], b.typ[0], {IgnoreFlags}):
if b.typ[0] != nil and b.typ[0].kind == tyUntyped:
# infer 'auto' from the base to make it consistent:
b.typ[0] = a.typ[0]
@@ -117,7 +124,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
incl(disp.flags, sfDispatcher)
excl(disp.flags, sfExported)
let old = disp.typ
disp.typ = copyType(disp.typ, nextTypeId(idgen), disp.typ.owner)
disp.typ = copyType(disp.typ, idgen, disp.typ.owner)
copyTypeProps(g, idgen.module, disp.typ, old)
# we can't inline the dispatcher itself (for now):
@@ -149,7 +156,10 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
disp.ast[resultPos] = copyTree(meth.ast[resultPos])
proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
var witness: PSym
var witness: PSym = nil
if s.typ[1].owner.getModule != s.getModule and vtables in g.config.features and not g.config.isDefined("nimInternalNonVtablesTesting"):
localError(g.config, s.info, errGenerated, "method `" & s.name.s &
"` can be defined only in the same module with its type (" & s.typ[1].typeToString() & ")")
for i in 0..<g.methods.len:
let disp = g.methods[i].dispatcher
case sameMethodBucket(disp, s, multimethods = optMultiMethods in g.config.globalOptions)
@@ -168,6 +178,11 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
of Invalid:
if witness.isNil: witness = g.methods[i].methods[0]
# create a new dispatcher:
# stores the id and the position
if s.typ[1].skipTypes(skipPtrs).itemId notin g.bucketTable:
g.bucketTable[s.typ[1].skipTypes(skipPtrs).itemId] = 1
else:
g.bucketTable.inc(s.typ[1].skipTypes(skipPtrs).itemId)
g.methods.add((methods: @[s], dispatcher: createDispatcher(s, g, idgen)))
#echo "adding ", s.info
if witness != nil:
@@ -176,8 +191,9 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
elif sfBase notin s.flags:
message(g.config, s.info, warnUseBase)
proc relevantCol(methods: seq[PSym], col: int): bool =
proc relevantCol*(methods: seq[PSym], col: int): bool =
# returns true iff the position is relevant
result = false
var t = methods[0].typ[col].skipTypes(skipPtrs)
if t.kind == tyObject:
for i in 1..high(methods):
@@ -186,6 +202,7 @@ proc relevantCol(methods: seq[PSym], col: int): bool =
return true
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
result = 0
for col in 1..<a.typ.len:
if contains(relevantCols, col):
var aa = skipTypes(a.typ[col], skipPtrs)
@@ -194,7 +211,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
if (d != high(int)) and d != 0:
return d
proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
proc sortBucket*(a: var seq[PSym], relevantCols: IntSet) =
# we use shellsort here; fast and simple
var n = a.len
var h = 1
@@ -213,7 +230,7 @@ proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
a[j] = v
if h == 1: break
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym =
proc genIfDispatcher*(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym =
var base = methods[0].ast[dispatcherPos].sym
result = base
var paramLen = base.typ.len
@@ -272,8 +289,7 @@ proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idg
nilchecks.flags.incl nfTransf # should not be further transformed
result.ast[bodyPos] = nilchecks
proc generateMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator): PNode =
result = newNode(nkStmtList)
proc generateIfMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator) =
for bucket in 0..<g.methods.len:
var relevantCols = initIntSet()
for col in 1..<g.methods[bucket].methods[0].typ.len:
@@ -282,4 +298,4 @@ proc generateMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator): PNode =
# if multi-methods are not enabled, we are interested only in the first field
break
sortBucket(g.methods[bucket].methods, relevantCols)
result.add newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols, idgen))
g.addDispatchers genIfDispatcher(g, g.methods[bucket].methods, relevantCols, idgen)

View File

@@ -134,7 +134,9 @@
import
ast, msgs, idents,
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos,
tables, options
options
import std/tables
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -258,8 +260,9 @@ proc hasYields(n: PNode): bool =
of nkYieldStmt:
result = true
of nkSkip:
discard
result = false
else:
result = false
for c in n:
if c.hasYields:
result = true
@@ -325,7 +328,7 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
var ifBranch: PNode
if c.len > 1:
var cond: PNode
var cond: PNode = nil
for i in 0..<c.len - 1:
assert(c[i].kind == nkType)
let nextCond = newTree(nkCall,
@@ -388,19 +391,22 @@ proc getFinallyNode(ctx: var Ctx, n: PNode): PNode =
proc hasYieldsInExpressions(n: PNode): bool =
case n.kind
of nkSkip:
discard
result = false
of nkStmtListExpr:
if isEmptyType(n.typ):
result = false
for c in n:
if c.hasYieldsInExpressions:
return true
else:
result = n.hasYields
of nkCast:
result = false
for i in 1..<n.len:
if n[i].hasYieldsInExpressions:
return true
else:
result = false
for c in n:
if c.hasYieldsInExpressions:
return true
@@ -495,7 +501,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if ns:
needsSplit = true
var tmp: PSym
var tmp: PSym = nil
let isExpr = not isEmptyType(n.typ)
if isExpr:
tmp = ctx.newTempVar(n.typ)
@@ -1154,9 +1160,9 @@ proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode=
n[i] = ctx.skipThroughEmptyStates(n[i])
proc newArrayType(g: ModuleGraph; n: int, t: PType; idgen: IdGenerator; owner: PSym): PType =
result = newType(tyArray, nextTypeId(idgen), owner)
result = newType(tyArray, idgen, owner)
let rng = newType(tyRange, nextTypeId(idgen), owner)
let rng = newType(tyRange, idgen, owner)
rng.n = newTree(nkRange, g.newIntLit(owner.info, 0), g.newIntLit(owner.info, n - 1))
rng.rawAddSon(t)
@@ -1361,6 +1367,7 @@ proc freshVars(n: PNode; c: var FreshVarsContext): PNode =
else:
result.add it
of nkRaiseStmt:
result = nil
localError(c.config, c.info, "unsupported control flow: 'finally: ... raise' duplicated because of 'break'")
else:
result = n

View File

@@ -11,7 +11,9 @@
import
options, idents, nimconf, extccomp, commands, msgs,
lineinfos, modulegraphs, condsyms, os, pathutils, parseopt
lineinfos, modulegraphs, condsyms, pathutils
import std/[os, parseopt]
proc prependCurDir*(f: AbsoluteFile): AbsoluteFile =
when defined(unix):

View File

@@ -27,7 +27,9 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
import std/[setutils, os, strutils, parseutils, parseopt, sequtils, strtabs]
import
msgs, options, nversion, condsyms, extccomp, platform,
wordrecg, nimblecmd, lineinfos, pathutils, pathnorm
wordrecg, nimblecmd, lineinfos, pathutils
import std/pathnorm
from ast import setUseIc, eqTypeFlags, tfGcSafe, tfNoSideEffect
@@ -184,7 +186,7 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
info: TLineInfo; orig: string; conf: ConfigRef) =
var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off
var i = 0
var notes: set[TMsgKind]
var notes: set[TMsgKind] = {}
var isBracket = false
if i < arg.len and arg[i] == '[':
isBracket = true
@@ -205,7 +207,11 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
# unfortunately, hintUser and warningUser clash, otherwise implementation would simplify a bit
let x = findStr(noteMin, noteMax, id, errUnknown)
if x != errUnknown: notes = {TNoteKind(x)}
else: localError(conf, info, "unknown $#: $#" % [name, id])
else:
if isSomeHint:
message(conf, info, hintUnknownHint, id)
else:
localError(conf, info, "unknown $#: $#" % [name, id])
case id.normalize
of "all": # other note groups would be easy to support via additional cases
notes = if isSomeHint: {hintMin..hintMax} else: {warnMin..warnMax}
@@ -263,13 +269,17 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
of "none": result = conf.selectedGC == gcNone
of "stack", "regions": result = conf.selectedGC == gcRegions
of "atomicarc": result = conf.selectedGC == gcAtomicArc
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
else:
result = false
localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
of "opt":
case arg.normalize
of "speed": result = contains(conf.options, optOptimizeSpeed)
of "size": result = contains(conf.options, optOptimizeSize)
of "none": result = conf.options * {optOptimizeSpeed, optOptimizeSize} == {}
else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
else:
result = false
localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
of "verbosity": result = $conf.verbosity == arg
of "app":
case arg.normalize
@@ -279,7 +289,9 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
not contains(conf.globalOptions, optGenGuiApp)
of "staticlib": result = contains(conf.globalOptions, optGenStaticLib) and
not contains(conf.globalOptions, optGenGuiApp)
else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
else:
result = false
localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
of "dynliboverride":
result = isDynlibOverride(conf, arg)
of "exceptions":
@@ -288,8 +300,12 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
of "setjmp": result = conf.exc == excSetjmp
of "quirky": result = conf.exc == excQuirky
of "goto": result = conf.exc == excGoto
else: localError(conf, info, errInvalidExceptionSystem % arg)
else: invalidCmdLineOption(conf, passCmd1, switch, info)
else:
result = false
localError(conf, info, errInvalidExceptionSystem % arg)
else:
result = false
invalidCmdLineOption(conf, passCmd1, switch, info)
proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool =
case switch.normalize
@@ -335,10 +351,14 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
if switch.normalize == "patterns": deprecatedAlias(switch, "trmacros")
result = contains(conf.options, optTrMacros)
of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
of "nilseqs", "nilchecks", "taintmode": warningOptionNoop(switch)
of "nilseqs", "nilchecks", "taintmode":
warningOptionNoop(switch)
result = false
of "panics": result = contains(conf.globalOptions, optPanics)
of "jsbigint64": result = contains(conf.globalOptions, optJsBigInt64)
else: invalidCmdLineOption(conf, passCmd1, switch, info)
else:
result = false
invalidCmdLineOption(conf, passCmd1, switch, info)
proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
notRelativeToProj = false): AbsoluteDir =
@@ -380,7 +400,8 @@ proc makeAbsolute(s: string): AbsoluteFile =
proc setTrackingInfo(conf: ConfigRef; dirty, file, line, column: string,
info: TLineInfo) =
## set tracking info, common code for track, trackDirty, & ideTrack
var ln, col: int
var ln: int = 0
var col: int = 0
if parseUtils.parseInt(line, ln) <= 0:
localError(conf, info, errInvalidNumber % line)
if parseUtils.parseInt(column, col) <= 0:
@@ -441,10 +462,12 @@ proc handleCmdInput*(conf: ConfigRef) =
proc parseCommand*(command: string): Command =
case command.normalize
of "c", "cc", "compile", "compiletoc": cmdCompileToC
of "nir": cmdCompileToNir
of "cpp", "compiletocpp": cmdCompileToCpp
of "objc", "compiletooc": cmdCompileToOC
of "js", "compiletojs": cmdCompileToJS
of "r": cmdCrun
of "m": cmdM
of "run": cmdTcc
of "check": cmdCheck
of "e": cmdNimscript
@@ -477,6 +500,7 @@ proc setCmd*(conf: ConfigRef, cmd: Command) =
of cmdCompileToCpp: conf.backend = backendCpp
of cmdCompileToOC: conf.backend = backendObjc
of cmdCompileToJS: conf.backend = backendJs
of cmdCompileToNir: conf.backend = backendNir
else: discard
proc setCommandEarly*(conf: ConfigRef, command: string) =
@@ -589,10 +613,17 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
defineSymbol(conf.symbols, "gcregions")
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
proc pathRelativeToConfig(arg: string, pass: TCmdLinePass, conf: ConfigRef): string =
if pass == passPP and not isAbsolute(arg):
assert isAbsolute(conf.currentConfigDir), "something is wrong with currentConfigDir"
result = conf.currentConfigDir / arg
else:
result = arg
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
conf: ConfigRef) =
var
key, val: string
var key = ""
var val = ""
case switch.normalize
of "eval":
expectArg(conf, switch, arg, pass, info)
@@ -607,8 +638,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
for path in nimbleSubs(conf, arg):
addPath(conf, if pass == passPP: processCfgPath(conf, path, info)
else: processPath(conf, path, info), info)
of "nimblepath", "babelpath":
if switch.normalize == "babelpath": deprecatedAlias(switch, "nimblepath")
of "nimblepath":
if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions:
expectArg(conf, switch, arg, pass, info)
var path = processPath(conf, arg, info, notRelativeToProj=true)
@@ -618,8 +648,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
nimblePath(conf, path, info)
path = nimbleDir / RelativeDir"pkgs"
nimblePath(conf, path, info)
of "nonimblepath", "nobabelpath":
if switch.normalize == "nobabelpath": deprecatedAlias(switch, "nonimblepath")
of "nonimblepath":
expectNoArg(conf, switch, arg, pass, info)
disableNimblePath(conf)
of "clearnimblepath":
@@ -636,7 +665,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
# refs bug #18674, otherwise `--os:windows` messes up with `--nimcache` set
# in config nims files, e.g. via: `import os; switch("nimcache", "/tmp/somedir")`
if conf.target.targetOS == osWindows and DirSep == '/': arg = arg.replace('\\', '/')
conf.nimcacheDir = processPath(conf, arg, info, notRelativeToProj=true)
conf.nimcacheDir = processPath(conf, pathRelativeToConfig(arg, pass, conf), info, notRelativeToProj=true)
of "out", "o":
expectArg(conf, switch, arg, pass, info)
let f = splitFile(processPath(conf, arg, info, notRelativeToProj=true).string)
@@ -770,7 +799,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
if conf.backend == backendJs or conf.cmd == cmdNimscript: discard
else: processOnOffSwitchG(conf, {optThreads}, arg, pass, info)
#if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe)
of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
of "tlsemulation":
processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
if optTlsEmulation in conf.globalOptions:
conf.legacyFeatures.incl emitGenerics
of "implicitstatic":
processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info)
of "patterns", "trmacros":
@@ -878,15 +910,19 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
defineSymbol(conf.symbols, "nodejs")
of "maxloopiterationsvm":
expectArg(conf, switch, arg, pass, info)
conf.maxLoopIterationsVM = parseInt(arg)
var value: int = 10_000_000
discard parseSaturatedNatural(arg, value)
if not value > 0: localError(conf, info, "maxLoopIterationsVM must be a positive integer greater than zero")
conf.maxLoopIterationsVM = value
of "errormax":
expectArg(conf, switch, arg, pass, info)
# Note: `nim check` (etc) can overwrite this.
# `0` is meaningless, give it a useful meaning as in clang's -ferror-limit
# If user doesn't set this flag and the code doesn't either, it'd
# have the same effect as errorMax = 1
let ret = parseInt(arg)
conf.errorMax = if ret == 0: high(int) else: ret
var value: int = 0
discard parseSaturatedNatural(arg, value)
conf.errorMax = if value == 0: high(int) else: value
of "verbosity":
expectArg(conf, switch, arg, pass, info)
let verbosity = parseInt(arg)
@@ -900,7 +936,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
conf.mainPackageNotes = conf.notes
of "parallelbuild":
expectArg(conf, switch, arg, pass, info)
conf.numberOfProcessors = parseInt(arg)
var value: int = 0
discard parseSaturatedNatural(arg, value)
conf.numberOfProcessors = value
of "version", "v":
expectNoArg(conf, switch, arg, pass, info)
writeVersionInfo(conf, pass)
@@ -1109,7 +1147,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
else: invalidCmdLineOption(conf, pass, switch, info)
proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
var cmd, arg: string
var cmd = ""
var arg = ""
splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo)
processSwitch(cmd, arg, pass, gCmdLineInfo, config)
@@ -1136,7 +1175,10 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
config.projectName = unixToNativePath(p.key)
config.arguments = cmdLineRest(p)
result = true
elif pass != passCmd2: setCommandEarly(config, p.key)
elif pass != passCmd2:
setCommandEarly(config, p.key)
result = false
else: result = false
else:
if pass == passCmd1: config.commandArgs.add p.key
if argsCount == 1:
@@ -1147,4 +1189,6 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
config.projectName = unixToNativePath(p.key)
config.arguments = cmdLineRest(p)
result = true
else:
result = false
inc argsCount

View File

@@ -11,9 +11,9 @@
## for details. Note this is a first implementation and only the "Concept matching"
## section has been implemented.
import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types, intsets
import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types
from magicsys import addSonSkipIntLit
import std/intsets
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -28,23 +28,11 @@ proc declareSelf(c: PContext; info: TLineInfo) =
## Adds the magical 'Self' symbols to the current scope.
let ow = getCurrOwner(c)
let s = newSym(skType, getIdent(c.cache, "Self"), c.idgen, ow, info)
s.typ = newType(tyTypeDesc, nextTypeId(c.idgen), ow)
s.typ = newType(tyTypeDesc, c.idgen, ow)
s.typ.flags.incl {tfUnresolved, tfPacked}
s.typ.add newType(tyEmpty, nextTypeId(c.idgen), ow)
s.typ.add newType(tyEmpty, c.idgen, ow)
addDecl(c, s, info)
proc isSelf*(t: PType): bool {.inline.} =
## Is this the magical 'Self' type?
t.kind == tyTypeDesc and tfPacked in t.flags
proc makeTypeDesc*(c: PContext, typ: PType): PType =
if typ.kind == tyTypeDesc and not isSelf(typ):
result = typ
else:
result = newTypeS(tyTypeDesc, c)
incl result.flags, tfCheckedForDestructor
result.addSonSkipIntLit(typ, c.idgen)
proc semConceptDecl(c: PContext; n: PNode): PNode =
## Recursive helper for semantic checking for the concept declaration.
## Currently we only support (possibly empty) lists of statements
@@ -121,8 +109,11 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
for i in 0..<a.len:
if not matchType(c, f[i], a[i], m): return false
return true
else:
result = false
of tyGenericInvocation:
result = false
if a.kind == tyGenericInst and a[0].kind == tyGenericBody:
if sameType(f[0], a[0]) and f.len == a.len-1:
for i in 1 ..< f.len:
@@ -156,15 +147,17 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
result = matchType(c, old, ak, m)
if m.magic == mArrPut and ak.kind == tyGenericParam:
result = true
else:
result = false
#echo "B for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)
of tyVar, tySink, tyLent, tyOwned:
# modifiers in the concept must be there in the actual implementation
# too but not vice versa.
if a.kind == f.kind:
result = matchType(c, f.sons[0], a.sons[0], m)
result = matchType(c, f[0], a[0], m)
elif m.magic == mArrPut:
result = matchType(c, f.sons[0], a, m)
result = matchType(c, f[0], a, m)
else:
result = false
of tyEnum, tyObject, tyDistinct:
@@ -185,6 +178,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
m.inferred.setLen oldLen
of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr,
tyGenericInst:
result = false
let ak = a.skipTypes(ignorableForArgType - {f.kind})
if ak.kind == f.kind and f.len == ak.len:
for i in 0..<ak.len:
@@ -209,6 +203,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
if not result:
m.inferred.setLen oldLen
else:
result = false
for i in 0..<f.len:
result = matchType(c, f[i], a, m)
if result: break # and remember the binding!
@@ -257,7 +252,7 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
m.inferred.setLen oldLen
return false
if not matchReturnType(c, n[0].sym.typ.sons[0], candidate.typ.sons[0], m):
if not matchReturnType(c, n[0].sym.typ[0], candidate.typ[0], m):
m.inferred.setLen oldLen
return false

View File

@@ -10,7 +10,7 @@
# This module handles the conditional symbols.
import
strtabs
std/strtabs
from options import Feature
from lineinfos import hintMin, hintMax, warnMin, warnMax
@@ -143,7 +143,6 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasTemplateRedefinitionPragma")
defineSymbol("nimHasCstringCase")
defineSymbol("nimHasCallsitePragma")
defineSymbol("nimHasAmbiguousEnumHint")
defineSymbol("nimHasWarnCastSizes") # deadcode
defineSymbol("nimHasOutParams")
@@ -158,4 +157,12 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimAllowNonVarDestructor")
defineSymbol("nimHasQuirky")
defineSymbol("nimHasEnsureMove")
defineSymbol("nimHasNoLineTooLong")
defineSymbol("nimUseStrictDefs")
defineSymbol("nimHasNolineTooLong")
defineSymbol("nimHasCastExtendedVm")
defineSymbol("nimHasWarnStdPrefix")
defineSymbol("nimHasVtables")
defineSymbol("nimHasSeqsV3")

View File

@@ -14,7 +14,7 @@ import options, ast, ropes, pathutils, msgs, lineinfos
import modulegraphs
import std/[os, parseutils]
import strutils except addf
import std/strutils except addf
import std/private/globs
when defined(nimPreviewSlimSystem):
@@ -42,7 +42,7 @@ proc toNimblePath(s: string, isStdlib: bool): string =
let sub = "lib/"
var start = s.find(sub)
if start < 0:
doAssert false
raiseAssert "unreachable"
else:
start += sub.len
let base = s[start..^1]
@@ -105,11 +105,6 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
changeFileExt(project, "dot"))
proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
var g: PGen
new(g)
g.module = module
g.config = graph.config
g.graph = graph
result = PGen(module: module, config: graph.config, graph: graph)
if graph.backend == nil:
graph.backend = Backend(dotGraph: "")
result = g

View File

@@ -22,8 +22,9 @@
## "A GraphFree Approach to DataFlow Analysis" by Markus Mohnen.
## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf
import ast, intsets, lineinfos, renderer, aliasanalysis
import ast, lineinfos, renderer, aliasanalysis
import std/private/asciitables
import std/intsets
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -60,6 +61,7 @@ type
proc codeListing(c: ControlFlowGraph, start = 0; last = -1): string =
# for debugging purposes
# first iteration: compute all necessary labels:
result = ""
var jumpTargets = initIntSet()
let last = if last < 0: c.len-1 else: min(last, c.len-1)
for i in start..last:
@@ -111,7 +113,7 @@ proc patch(c: var Con, p: TPosition) =
proc gen(c: var Con; n: PNode)
proc popBlock(c: var Con; oldLen: int) =
var exits: seq[TPosition]
var exits: seq[TPosition] = @[]
exits.add c.gotoI()
for f in c.blocks[oldLen].breakFixups:
c.patch(f[0])
@@ -128,10 +130,6 @@ template withBlock(labl: PSym; body: untyped) =
body
popBlock(c, oldLen)
proc isTrue(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0
template forkT(body) =
let lab1 = c.forkI()
body
@@ -263,7 +261,7 @@ proc genBreakOrRaiseAux(c: var Con, i: int, n: PNode) =
if c.blocks[i].isTryBlock:
c.blocks[i].raiseFixups.add lab1
else:
var trailingFinales: seq[PNode]
var trailingFinales: seq[PNode] = @[]
if c.inTryStmt > 0:
# Ok, we are in a try, lets see which (if any) try's we break out from:
for b in countdown(c.blocks.high, i):
@@ -469,7 +467,7 @@ proc gen(c: var Con; n: PNode) =
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, PathKinds1:
gen(c, n[1])
of nkVarSection, nkLetSection: genVarSection(c, n)
of nkDefer: doAssert false, "dfa construction pass requires the elimination of 'defer'"
of nkDefer: raiseAssert "dfa construction pass requires the elimination of 'defer'"
else: discard
when false:

View File

@@ -15,15 +15,16 @@
## For corresponding users' documentation see [Nim DocGen Tools Guide].
import
ast, strutils, strtabs, algorithm, sequtils, options, msgs, os, idents,
ast, options, msgs, idents,
wordrecg, syntaxes, renderer, lexer,
packages/docutils/[rst, rstidx, rstgen, dochelpers],
json, xmltree, trees, types,
typesrenderer, astalgo, lineinfos, intsets,
pathutils, tables, nimpaths, renderverbatim, osproc, packages
trees, types,
typesrenderer, astalgo, lineinfos,
pathutils, nimpaths, renderverbatim, packages
import packages/docutils/rstast except FileIndex, TLineInfo
from uri import encodeUrl
import std/[os, strutils, strtabs, algorithm, json, osproc, tables, intsets, xmltree, sequtils]
from std/uri import encodeUrl
from nodejs import findNodeJs
when defined(nimPreviewSlimSystem):
@@ -170,6 +171,7 @@ proc cmpDecimalsIgnoreCase(a, b: string): int =
proc prettyString(a: object): string =
# xxx pending std/prettyprint refs https://github.com/nim-lang/RFCs/issues/203#issuecomment-602534906
result = ""
for k, v in fieldPairs(a):
result.add k & ": " & $v & "\n"
@@ -215,12 +217,16 @@ proc whichType(d: PDoc; n: PNode): PSym =
if n.kind == nkSym:
if d.types.strTableContains(n.sym):
result = n.sym
else:
result = nil
else:
result = nil
for i in 0..<n.safeLen:
let x = whichType(d, n[i])
if x != nil: return x
proc attachToType(d: PDoc; p: PSym): PSym =
result = nil
let params = p.ast[paramsPos]
template check(i) =
result = whichType(d, params[i])
@@ -343,7 +349,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
if conf.configVars.hasKey("doc.googleAnalytics") and
conf.configVars.hasKey("doc.plausibleAnalytics"):
doAssert false, "Either use googleAnalytics or plausibleAnalytics"
raiseAssert "Either use googleAnalytics or plausibleAnalytics"
if conf.configVars.hasKey("doc.googleAnalytics"):
result.analytics = """
@@ -368,7 +374,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
result.seenSymbols = newStringTable(modeCaseInsensitive)
result.id = 100
result.jEntriesFinal = newJArray()
initStrTable result.types
result.types = initStrTable()
result.onTestSnippet =
proc (gen: var RstGenerator; filename, cmd: string; status: int; content: string) {.gcsafe.} =
if conf.docCmd == docCmdSkip: return
@@ -435,6 +441,8 @@ proc genComment(d: PDoc, n: PNode): PRstNode =
d.conf, d.sharedState)
except ERecoverableError:
result = newRstNode(rnLiteralBlock, @[newRstLeaf(n.comment)])
else:
result = nil
proc genRecCommentAux(d: PDoc, n: PNode): PRstNode =
if n == nil: return nil
@@ -469,6 +477,7 @@ proc getPlainDocstring(n: PNode): string =
elif startsWith(n.comment, "##"):
result = n.comment
else:
result = ""
for i in 0..<n.safeLen:
result = getPlainDocstring(n[i])
if result.len > 0: return
@@ -484,9 +493,8 @@ proc externalDep(d: PDoc; module: PSym): string =
proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string;
renderFlags: TRenderFlags = {};
procLink: string) =
var r: TSrcGen
var r: TSrcGen = initTokRender(n, renderFlags)
var literal = ""
initTokRender(r, n, renderFlags)
var kind = tkEof
var tokenPos = 0
var procTokenPos = 0
@@ -600,7 +608,9 @@ proc runAllExamples(d: PDoc) =
rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
# removeFile(outp.changeFileExt(ExeExt)) # it's in nimcache, no need to remove
proc quoted(a: string): string = result.addQuoted(a)
proc quoted(a: string): string =
result = ""
result.addQuoted(a)
proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): (string, int, int) =
# xxx expose in compiler/lineinfos.nim
@@ -726,7 +736,7 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var ItemPre,
let (rdoccmd, code) = prepareExample(d, n, topLevel)
var msg = "Example:"
if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd
var s: string
var s: string = ""
dispA(d.conf, s, "\n<p><strong class=\"examples_text\">$1</strong></p>\n",
"\n\n\\textbf{$1}\n", [msg])
dest.add s
@@ -942,14 +952,17 @@ proc genDeprecationMsg(d: PDoc, n: PNode): string =
if n[1].kind in {nkStrLit..nkTripleStrLit}:
result = getConfigVar(d.conf, "doc.deprecationmsg") % [
"label", "Deprecated:", "message", xmltree.escape(n[1].strVal)]
else:
result = ""
else:
doAssert false
raiseAssert "unreachable"
type DocFlags = enum
kDefault
kForceExport
proc genSeeSrc(d: PDoc, path: string, line: int): string =
result = ""
let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc")
if docItemSeeSrc.len > 0:
let path = relativeTo(AbsoluteFile path, AbsoluteDir getCurrentDir(), '/')
@@ -991,7 +1004,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
result.symKind = k.toHumanStr
if k in routineKinds:
var
paramTypes: seq[string]
paramTypes: seq[string] = @[]
renderParamTypes(paramTypes, n[paramsPos], toNormalize=true)
let paramNames = renderParamNames(n[paramsPos], toNormalize=true)
# In some rare cases (system.typeof) parameter type is not set for default:
@@ -1016,8 +1029,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
genNode = n[miscPos][1] # FIXME: what is index 1?
if genNode != nil:
var literal = ""
var r: TSrcGen
initTokRender(r, genNode, {renderNoBody, renderNoComments,
var r: TSrcGen = initTokRender(genNode, {renderNoBody, renderNoComments,
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
var kind = tkEof
while true:
@@ -1038,15 +1050,14 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
var result = ""
var literal, plainName = ""
var kind = tkEof
var comm: ItemPre
var comm: ItemPre = default(ItemPre)
if n.kind in routineDefs:
getAllRunnableExamples(d, n, comm)
else:
comm.add genRecComment(d, n)
var r: TSrcGen
# Obtain the plain rendered string for hyperlink titles.
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments,
var r: TSrcGen = initTokRender(n, {renderNoBody, renderNoComments, renderDocComments,
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
while true:
getNextTok(r, kind, literal)
@@ -1154,7 +1165,7 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false):
renderFlags = {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing}
if nonExports:
renderFlags.incl renderNonExportedFields
initTokRender(r, n, renderFlags)
r = initTokRender(n, renderFlags)
result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
"col": %n.info.col}
if comm != nil:
@@ -1186,9 +1197,9 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false):
result.json["signature"]["genericParams"] = newJArray()
for genericParam in n[genericParamsPos]:
var param = %{"name": %($genericParam)}
if genericParam.sym.typ.sons.len > 0:
if genericParam.sym.typ.len > 0:
param["types"] = newJArray()
for kind in genericParam.sym.typ.sons:
for kind in genericParam.sym.typ:
param["types"].add %($kind)
result.json["signature"]["genericParams"].add param
if optGenIndex in d.conf.globalOptions:
@@ -1283,6 +1294,8 @@ proc documentNewEffect(cache: IdentCache; n: PNode): PNode =
let s = n[namePos].sym
if tfReturnsNew in s.typ.flags:
result = newIdentNode(getIdent(cache, "new"), n.info)
else:
result = nil
proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
let spec = effectSpec(x, effectType)
@@ -1305,6 +1318,8 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id
result = newTreeI(nkExprColonExpr, n.info,
newIdentNode(getIdent(cache, $effectType), n.info), effects)
else:
result = nil
proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode =
let s = n[namePos].sym
@@ -1318,6 +1333,8 @@ proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName
if effects.len > 0:
result = newTreeI(nkExprColonExpr, n.info,
newIdentNode(getIdent(cache, pragmaName), n.info), effects)
else:
result = nil
proc documentRaises*(cache: IdentCache; n: PNode) =
if n[namePos].kind != nkSym: return
@@ -1391,7 +1408,7 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags
of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept"
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n[0])
of nkCallKinds:
var comm: ItemPre
var comm: ItemPre = default(ItemPre)
getAllRunnableExamples(d, n, comm)
if comm.len != 0: d.modDescPre.add(comm)
else: discard
@@ -1500,7 +1517,7 @@ proc finishGenerateDoc*(d: var PDoc) =
overloadChoices.sort(cmp)
var nameContent = ""
for item in overloadChoices:
var itemDesc: string
var itemDesc: string = ""
renderItemPre(d, item.descRst, itemDesc)
nameContent.add(
getConfigVar(d.conf, "doc.item") % (
@@ -1526,7 +1543,7 @@ proc finishGenerateDoc*(d: var PDoc) =
for i, entry in d.jEntriesPre:
if entry.rst != nil:
let resolved = resolveSubs(d.sharedState, entry.rst)
var str: string
var str: string = ""
renderRstToOut(d[], resolved, str)
entry.json[entry.rstField] = %str
d.jEntriesPre[i].rst = nil
@@ -1641,7 +1658,7 @@ proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) =
for plainName in overloadableNames.sorted(cmpDecimalsIgnoreCase):
var overloadChoices = d.tocTable[kind][plainName]
overloadChoices.sort(cmp)
var content: string
var content: string = ""
for item in overloadChoices:
content.add item.content
d.toc2[kind].add getConfigVar(d.conf, "doc.section.toc2") % [
@@ -1672,7 +1689,7 @@ proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile):
proc genOutFile(d: PDoc, groupedToc = false): string =
var
code, content: string
code, content: string = ""
title = ""
var j = 0
var toc = ""
@@ -1781,7 +1798,7 @@ proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) =
proc writeOutputJson*(d: PDoc, useWarning = false) =
runAllExamples(d)
var modDesc: string
var modDesc: string = ""
for desc in d.modDescFinal:
modDesc &= desc
let content = %*{"orig": d.filename,
@@ -1789,11 +1806,11 @@ proc writeOutputJson*(d: PDoc, useWarning = false) =
"moduleDescription": modDesc,
"entries": d.jEntriesFinal}
if optStdout in d.conf.globalOptions:
write(stdout, $content)
writeLine(stdout, $content)
else:
let dir = d.destFile.splitFile.dir
createDir(dir)
var f: File
var f: File = default(File)
if open(f, d.destFile, fmWrite):
write(f, $content)
close(f)

View File

@@ -39,10 +39,12 @@ template closeImpl(body: untyped) {.dirty.} =
discard
proc closeDoc*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
result = nil
closeImpl:
writeOutput(g.doc, useWarning, groupedToc)
proc closeJson*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
result = nil
closeImpl:
writeOutputJson(g.doc, useWarning)

View File

@@ -14,7 +14,7 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGener
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
res.typ = getSysType(g, info, tyString)
result.typ = newType(tyProc, nextTypeId idgen, t.owner)
result.typ = newType(tyProc, idgen, t.owner)
result.typ.n = newNodeI(nkFormalParams, info)
rawAddSon(result.typ, res.typ)
result.typ.n.add newNodeI(nkEffectList, info)
@@ -56,6 +56,7 @@ proc searchObjCaseImpl(obj: PNode; field: PSym): PNode =
if obj.kind == nkRecCase and obj[0].kind == nkSym and obj[0].sym == field:
result = obj
else:
result = nil
for x in obj:
result = searchObjCaseImpl(x, field)
if result != nil: break
@@ -75,7 +76,7 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
res.typ = getSysType(g, info, tyUInt8)
result.typ = newType(tyProc, nextTypeId idgen, t.owner)
result.typ = newType(tyProc, idgen, t.owner)
result.typ.n = newNodeI(nkFormalParams, info)
rawAddSon(result.typ, res.typ)
result.typ.n.add newNodeI(nkEffectList, info)

View File

@@ -10,7 +10,8 @@
## This module contains support code for new-styled error
## handling via an `nkError` node kind.
import ast, renderer, options, strutils, types
import ast, renderer, options, types
import std/strutils
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -40,7 +41,8 @@ proc newError*(wrongNode: PNode; k: ErrorKind; args: varargs[PNode]): PNode =
let innerError = errorSubNode(wrongNode)
if innerError != nil:
return innerError
result = newNodeIT(nkError, wrongNode.info, newType(tyError, ItemId(module: -1, item: -1), nil))
var idgen = idGeneratorForPackage(-1'i32)
result = newNodeIT(nkError, wrongNode.info, newType(tyError, idgen, nil))
result.add wrongNode
result.add newIntNode(nkIntLit, ord(k))
for a in args: result.add a
@@ -50,7 +52,8 @@ proc newError*(wrongNode: PNode; msg: string): PNode =
let innerError = errorSubNode(wrongNode)
if innerError != nil:
return innerError
result = newNodeIT(nkError, wrongNode.info, newType(tyError, ItemId(module: -1, item: -1), nil))
var idgen = idGeneratorForPackage(-1'i32)
result = newNodeIT(nkError, wrongNode.info, newType(tyError, idgen, nil))
result.add wrongNode
result.add newIntNode(nkIntLit, ord(CustomError))
result.add newStrNode(msg, wrongNode.info)

View File

@@ -9,9 +9,11 @@
## This file implements the FFI part of the evaluator for Nim code.
import ast, types, options, tables, dynlib, msgs, lineinfos
from os import getAppFilename
import pkg/libffi
import ast, types, options, msgs, lineinfos
from std/os import getAppFilename
import libffi/libffi
import std/[tables, dynlib]
when defined(windows):
const libcDll = "msvcrt.dll"
@@ -37,9 +39,10 @@ else:
var gExeHandle = loadLib()
proc getDll(conf: ConfigRef, cache: var TDllCache; dll: string; info: TLineInfo): pointer =
result = nil
if dll in cache:
return cache[dll]
var libs: seq[string]
var libs: seq[string] = @[]
libCandidates(dll, libs)
for c in libs:
result = loadLib(c)
@@ -61,7 +64,7 @@ proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode =
let lib = sym.annex
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
globalError(conf, sym.info, "dynlib needs to be a string lit")
var theAddr: pointer
var theAddr: pointer = nil
if (lib.isNil or lib.kind == libHeader) and not gExeHandle.isNil:
libPathMsg = "current exe: " & getAppFilename() & " nor libc: " & libcDll
# first try this exe itself:
@@ -108,6 +111,7 @@ proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI
of ccStdCall: result = when defined(windows) and defined(x86): STDCALL else: DEFAULT_ABI
of ccCDecl: result = DEFAULT_ABI
else:
result = default(TABI)
globalError(conf, info, "cannot map calling convention to FFI")
template rd(typ, p: untyped): untyped = (cast[ptr typ](p))[]
@@ -132,6 +136,8 @@ proc packSize(conf: ConfigRef, v: PNode, typ: PType): int =
result = sizeof(pointer)
elif v.len != 0:
result = v.len * packSize(conf, v[0], typ[1])
else:
result = 0
else:
result = getSize(conf, typ).int
@@ -140,6 +146,7 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer)
proc getField(conf: ConfigRef, n: PNode; position: int): PSym =
case n.kind
of nkRecList:
result = nil
for i in 0..<n.len:
result = getField(conf, n[i], position)
if result != nil: return
@@ -154,7 +161,8 @@ proc getField(conf: ConfigRef, n: PNode; position: int): PSym =
else: internalError(conf, n.info, "getField(record case branch)")
of nkSym:
if n.sym.position == position: result = n.sym
else: discard
else: result = nil
else: result = nil
proc packObject(conf: ConfigRef, x: PNode, typ: PType, res: pointer) =
internalAssert conf, x.kind in {nkObjConstr, nkPar, nkTupleConstr}
@@ -356,6 +364,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
of 4: awi(nkIntLit, rd(int32, x).BiggestInt)
of 8: awi(nkIntLit, rd(int64, x).BiggestInt)
else:
result = nil
globalError(conf, n.info, "cannot map value from FFI (tyEnum, tySet)")
of tyFloat: awf(nkFloatLit, rd(float, x))
of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
@@ -381,6 +390,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
n[0] = unpack(conf, p, typ.lastSon, n[0])
result = n
else:
result = nil
globalError(conf, n.info, "cannot map value from FFI " & typeToString(typ))
of tyObject, tyTuple:
result = unpackObject(conf, x, typ, n)
@@ -398,6 +408,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
result = unpack(conf, x, typ.lastSon, n)
else:
# XXX what to do with 'array' here?
result = nil
globalError(conf, n.info, "cannot map value from FFI " & typeToString(typ))
proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode =
@@ -424,7 +435,7 @@ proc callForeignFunction*(conf: ConfigRef, call: PNode): PNode =
internalAssert conf, call[0].kind == nkPtrLit
var cif: TCif
var sig: ParamList
var sig: ParamList = default(ParamList)
# use the arguments' types for varargs support:
for i in 1..<call.len:
sig[i-1] = mapType(conf, call[i].typ)
@@ -436,7 +447,7 @@ proc callForeignFunction*(conf: ConfigRef, call: PNode): PNode =
mapType(conf, typ[0]), sig) != OK:
globalError(conf, call.info, "error in FFI call")
var args: ArgList
var args: ArgList = default(ArgList)
let fn = cast[pointer](call[0].intVal)
for i in 1..<call.len:
var t = call[i].typ
@@ -464,7 +475,7 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
internalAssert conf, fn.kind == nkPtrLit
var cif: TCif
var sig: ParamList
var sig: ParamList = default(ParamList)
for i in 0..len-1:
var aTyp = args[i+start].typ
if aTyp.isNil:
@@ -478,7 +489,7 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
mapType(conf, fntyp[0]), sig) != OK:
globalError(conf, info, "error in FFI call")
var cargs: ArgList
var cargs: ArgList = default(ArgList)
let fn = cast[pointer](fn.intVal)
for i in 0..len-1:
let t = args[i+start].typ

View File

@@ -9,8 +9,8 @@
## Template evaluation engine. Now hygienic.
import
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents, trees
import options, ast, astalgo, msgs, renderer, lineinfos, idents, trees
import std/strutils
type
TemplCtx = object
@@ -187,7 +187,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
ctx.genSymOwner = genSymOwner
ctx.config = conf
ctx.ic = ic
initIdTable(ctx.mapping)
ctx.mapping = initIdTable()
ctx.instID = instID[]
ctx.idgen = idgen

131
compiler/expanddefaults.nim Normal file
View File

@@ -0,0 +1,131 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import lineinfos, ast, types
proc caseObjDefaultBranch*(obj: PNode; branch: Int128): int =
result = 0
for i in 1 ..< obj.len:
for j in 0 .. obj[i].len - 2:
if obj[i][j].kind == nkRange:
let x = getOrdValue(obj[i][j][0])
let y = getOrdValue(obj[i][j][1])
if branch >= x and branch <= y:
return i
elif getOrdValue(obj[i][j]) == branch:
return i
if obj[i].len == 1:
# else branch
return i
return 1
template newZero(t: PType; info: TLineInfo; k = nkIntLit): PNode = newNodeIT(k, info, t)
proc expandDefault*(t: PType; info: TLineInfo): PNode
proc expandField(s: PSym; info: TLineInfo): PNode =
result = newNodeIT(nkExprColonExpr, info, s.typ)
result.add newSymNode(s)
result.add expandDefault(s.typ, info)
proc expandDefaultN(n: PNode; info: TLineInfo; res: PNode) =
case n.kind
of nkRecList:
for i in 0..<n.len:
expandDefaultN(n[i], info, res)
of nkRecCase:
res.add expandField(n[0].sym, info)
var branch = Zero
let constOrNil = n[0].sym.astdef
if constOrNil != nil:
branch = getOrdValue(constOrNil)
let selectedBranch = caseObjDefaultBranch(n, branch)
let b = lastSon(n[selectedBranch])
expandDefaultN b, info, res
of nkSym:
res.add expandField(n.sym, info)
else:
discard
proc expandDefaultObj(t: PType; info: TLineInfo; res: PNode) =
if t[0] != nil:
expandDefaultObj(t[0], info, res)
expandDefaultN(t.n, info, res)
proc expandDefault(t: PType; info: TLineInfo): PNode =
case t.kind
of tyInt: result = newZero(t, info, nkIntLit)
of tyInt8: result = newZero(t, info, nkInt8Lit)
of tyInt16: result = newZero(t, info, nkInt16Lit)
of tyInt32: result = newZero(t, info, nkInt32Lit)
of tyInt64: result = newZero(t, info, nkInt64Lit)
of tyUInt: result = newZero(t, info, nkUIntLit)
of tyUInt8: result = newZero(t, info, nkUInt8Lit)
of tyUInt16: result = newZero(t, info, nkUInt16Lit)
of tyUInt32: result = newZero(t, info, nkUInt32Lit)
of tyUInt64: result = newZero(t, info, nkUInt64Lit)
of tyFloat: result = newZero(t, info, nkFloatLit)
of tyFloat32: result = newZero(t, info, nkFloat32Lit)
of tyFloat64: result = newZero(t, info, nkFloat64Lit)
of tyFloat128: result = newZero(t, info, nkFloat64Lit)
of tyChar: result = newZero(t, info, nkCharLit)
of tyBool: result = newZero(t, info, nkIntLit)
of tyEnum:
# Could use low(T) here to finally fix old language quirks
result = newZero(t, info, nkIntLit)
of tyRange:
# Could use low(T) here to finally fix old language quirks
result = expandDefault(t[0], info)
of tyVoid: result = newZero(t, info, nkEmpty)
of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned:
result = expandDefault(t.lastSon, info)
of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
if t.len > 0:
result = expandDefault(t.lastSon, info)
else:
result = newZero(t, info, nkEmpty)
of tyFromExpr:
if t.n != nil and t.n.typ != nil:
result = expandDefault(t.n.typ, info)
else:
result = newZero(t, info, nkEmpty)
of tyArray:
result = newZero(t, info, nkBracket)
let n = toInt64(lengthOrd(nil, t))
for i in 0..<n:
result.add expandDefault(t[1], info)
of tyPtr, tyRef, tyProc, tyPointer, tyCstring:
result = newZero(t, info, nkNilLit)
of tyVar, tyLent:
let e = t.lastSon
if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
# skip the modifier, `var openArray` is a (ptr, len) pair too:
result = expandDefault(e, info)
else:
result = newZero(t.lastSon, info, nkNilLit)
of tySet:
result = newZero(t, info, nkCurly)
of tyObject:
result = newNodeIT(nkObjConstr, info, t)
result.add newNodeIT(nkType, info, t)
expandDefaultObj(t, info, result)
of tyTuple:
result = newZero(t, info, nkTupleConstr)
for it in t:
result.add expandDefault(it, info)
of tyVarargs, tyOpenArray, tySequence, tyUncheckedArray:
result = newZero(t, info, nkBracket)
of tyString:
result = newZero(t, info, nkStrLit)
of tyNone, tyEmpty, tyUntyped, tyTyped, tyTypeDesc,
tyNil, tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
result = newZero(t, info, nkEmpty) # bug indicator

View File

@@ -19,7 +19,7 @@ import std/[os, osproc, streams, sequtils, times, strtabs, json, jsonutils, suga
import std / strutils except addf
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
import std/syncio
import ../dist/checksums/src/checksums/sha1
@@ -33,6 +33,7 @@ type
hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax
hasDeclspec, # CC has __declspec(X)
hasAttribute, # CC has __attribute__((X))
hasBuiltinUnreachable # CC has __builtin_unreachable
TInfoCCProps* = set[TInfoCCProp]
TInfoCC* = tuple[
name: string, # the short name of the compiler
@@ -95,7 +96,7 @@ compiler gcc:
produceAsm: gnuAsmListing,
cppXsupport: "-std=gnu++17 -funsigned-char",
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
hasAttribute})
hasAttribute, hasBuiltinUnreachable})
# GNU C and C++ Compiler
compiler nintendoSwitchGCC:
@@ -122,7 +123,7 @@ compiler nintendoSwitchGCC:
produceAsm: gnuAsmListing,
cppXsupport: "-std=gnu++17 -funsigned-char",
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
hasAttribute})
hasAttribute, hasBuiltinUnreachable})
# LLVM Frontend for GCC/G++
compiler llvmGcc:
@@ -318,7 +319,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
var fullSuffix = suffix
case conf.backend
of backendCpp, backendJs, backendObjc: fullSuffix = "." & $conf.backend & suffix
of backendC: discard
of backendC, backendNir: discard
of backendInvalid:
# during parsing of cfg files; we don't know the backend yet, no point in
# guessing wrong thing
@@ -486,6 +487,10 @@ proc vccplatform(conf: ConfigRef): string =
of cpuArm: " --platform:arm"
of cpuAmd64: " --platform:amd64"
else: ""
else:
result = ""
else:
result = ""
proc getLinkOptions(conf: ConfigRef): string =
result = conf.linkOptions & " " & conf.linkOptionsCmd & " "
@@ -534,7 +539,7 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool =
# NOTE: should we need the full version, use -dumpfullversion
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except IOError, OSError, ValueError: ("", 1)
if exitCode == 0:
var major: int
var major: int = 0
discard parseInt(s, major)
result = major >= 5
else:
@@ -644,7 +649,7 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
let hashFile = toGeneratedFile(conf, conf.mangleModuleName(cfile.cname).AbsoluteFile, "sha1")
let currentHash = footprint(conf, cfile)
var f: File
var f: File = default(File)
if open(f, hashFile.string, fmRead):
let oldHash = parseSecureHash(f.readLine())
close(f)
@@ -779,6 +784,7 @@ template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body
raise
proc getExtraCmds(conf: ConfigRef; output: AbsoluteFile): seq[string] =
result = @[]
when defined(macosx):
if optCDebug in conf.globalOptions and optGenStaticLib notin conf.globalOptions:
# if needed, add an option to skip or override location
@@ -861,6 +867,7 @@ proc hcrLinkTargetName(conf: ConfigRef, objFile: string, isMain = false): Absolu
result = conf.getNimcacheDir / RelativeFile(targetName)
proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string =
result = ""
if conf.hasHint(hintCC):
if optListCmd in conf.globalOptions or conf.verbosity > 1:
result = MsgKindToStr[hintCC] % (demangleModuleName(path.splitFile.name) & ": " & compileCmd)
@@ -883,15 +890,15 @@ proc preventLinkCmdMaxCmdLen(conf: ConfigRef, linkCmd: string) =
proc callCCompiler*(conf: ConfigRef) =
var
linkCmd: string
linkCmd: string = ""
extraCmds: seq[string]
if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
return # speed up that call if only compiling and no script shall be
# generated
#var c = cCompiler
var script: Rope = ""
var cmds: TStringSeq
var prettyCmds: TStringSeq
var cmds: TStringSeq = default(TStringSeq)
var prettyCmds: TStringSeq = default(TStringSeq)
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
for idx, it in conf.toCompile:
@@ -992,7 +999,7 @@ type BuildCache = object
depfiles: seq[(string, string)]
nimexe: string
proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) =
proc writeJsonBuildInstructions*(conf: ConfigRef) =
var linkFiles = collect(for it in conf.externalToLink:
var it = it
if conf.noAbsolutePaths: it = it.extractFilename
@@ -1013,21 +1020,18 @@ proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) =
currentDir: getCurrentDir())
if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"):
bcache.cmdline = conf.commandLine
for it in conf.m.fileInfos:
bcache.depfiles = collect(for it in conf.m.fileInfos:
let path = it.fullPath.string
if isAbsolute(path): # TODO: else?
if path in deps:
bcache.depfiles.add (path, deps[path])
else: # backup for configs etc.
bcache.depfiles.add (path, $secureHashFile(path))
(path, $secureHashFile(path)))
bcache.nimexe = hashNimExe()
conf.jsonBuildFile = conf.jsonBuildInstructionsFile
conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty)
proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile): bool =
result = false
if not fileExists(jsonFile) or not fileExists(conf.absOutFile): return true
var bcache: BuildCache
var bcache: BuildCache = default(BuildCache)
try: bcache.fromJson(jsonFile.string.parseFile)
except IOError, OSError, ValueError:
stderr.write "Warning: JSON processing failed for: $#\n" % jsonFile.string
@@ -1043,7 +1047,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
if $secureHashFile(file) != hash: return true
proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
var bcache: BuildCache
var bcache: BuildCache = default(BuildCache)
try: bcache.fromJson(jsonFile.string.parseFile)
except ValueError, KeyError, JsonKindError:
let e = getCurrentException()
@@ -1056,7 +1060,8 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
globalError(conf, gCmdLineInfo,
"jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " %
[outputCurrent, output, jsonFile.string])
var cmds, prettyCmds: TStringSeq
var cmds: TStringSeq = default(TStringSeq)
var prettyCmds: TStringSeq= default(TStringSeq)
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
for (name, cmd) in bcache.compile:
cmds.add cmd
@@ -1066,6 +1071,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
for cmd in bcache.extraCmds: execExternalProgram(conf, cmd, hintExecuting)
proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope =
result = ""
for it in list:
result.addf("--file:r\"$1\"$N", [rope(it.cname.string)])

View File

@@ -10,9 +10,11 @@
# This module implements Nim's standard template filter.
import
llstream, strutils, ast, msgs, options,
llstream, ast, msgs, options,
filters, lineinfos, pathutils
import std/strutils
type
TParseState = enum
psDirective, psTempl
@@ -201,17 +203,15 @@ proc parseLine(p: var TTmplParser) =
proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile,
call: PNode): PLLStream =
var p: TTmplParser
p.config = conf
p.info = newLineInfo(conf, filename, 0, 0)
p.outp = llStreamOpen("")
p.inp = stdin
p.subsChar = charArg(conf, call, "subschar", 1, '$')
p.nimDirective = charArg(conf, call, "metachar", 2, '#')
p.emit = strArg(conf, call, "emit", 3, "result.add")
p.conc = strArg(conf, call, "conc", 4, " & ")
p.toStr = strArg(conf, call, "tostring", 5, "$")
p.x = newStringOfCap(120)
var p = TTmplParser(config: conf, info: newLineInfo(conf, filename, 0, 0),
outp: llStreamOpen(""), inp: stdin,
subsChar: charArg(conf, call, "subschar", 1, '$'),
nimDirective: charArg(conf, call, "metachar", 2, '#'),
emit: strArg(conf, call, "emit", 3, "result.add"),
conc: strArg(conf, call, "conc", 4, " & "),
toStr: strArg(conf, call, "tostring", 5, "$"),
x: newStringOfCap(120)
)
# do not process the first line which contains the directive:
if llStreamReadLine(p.inp, p.x):
inc p.info.line

View File

@@ -10,9 +10,11 @@
# This module implements Nim's simple filters and helpers for filters.
import
llstream, idents, strutils, ast, msgs, options,
llstream, idents, ast, msgs, options,
renderer, pathutils
import std/strutils
proc invalidPragma(conf: ConfigRef; n: PNode) =
localError(conf, n.info,
"'$1' not allowed here" % renderTree(n, {renderNoComments}))
@@ -29,23 +31,30 @@ proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode =
return n[i]
proc charArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: char): char =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind == nkCharLit: result = chr(int(x.intVal))
else: invalidPragma(conf, n)
else:
result = default(char)
invalidPragma(conf, n)
proc strArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: string): string =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal
else: invalidPragma(conf, n)
else:
result = ""
invalidPragma(conf, n)
proc boolArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: bool): bool =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "true") == 0: result = true
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false
else: invalidPragma(conf, n)
else:
result = false
invalidPragma(conf, n)
proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, call: PNode): PLLStream =
var pattern = strArg(conf, call, "startswith", 1, "")

View File

@@ -9,8 +9,9 @@
## Module that implements ``gorge`` for the compiler.
import msgs, os, osproc, streams, options,
lineinfos, pathutils
import msgs, options, lineinfos, pathutils
import std/[os, osproc, streams]
when defined(nimPreviewSlimSystem):
import std/syncio
@@ -29,10 +30,11 @@ proc readOutput(p: Process): (string, int) =
proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (string, int) =
let workingDir = parentDir(toFullPath(conf, info))
result = ("", 0)
if cache.len > 0:
let h = secureHash(cmd & "\t" & input & "\t" & cache)
let filename = toGeneratedFile(conf, AbsoluteFile("gorge_" & $h), "txt").string
var f: File
var f: File = default(File)
if optForceFullMake notin conf.globalOptions and open(f, filename):
result = (f.readAll, 0)
f.close

View File

@@ -51,6 +51,10 @@ proc isLet(n: PNode): bool =
elif n.sym.kind == skParam and skipTypes(n.sym.typ,
abstractInst).kind notin {tyVar}:
result = true
else:
result = false
else:
result = false
proc isVar(n: PNode): bool =
n.kind == nkSym and n.sym.kind in {skResult, skVar} and
@@ -136,6 +140,8 @@ proc neg(n: PNode; o: Operators): PNode =
result = a
elif b != nil:
result = b
else:
result = nil
else:
# leave not (a == 4) as it is
result = newNodeI(nkCall, n.info, 2)
@@ -330,6 +336,8 @@ proc usefulFact(n: PNode; o: Operators): PNode =
result = n
elif n[1].getMagic in someLen or n[2].getMagic in someLen:
result = n
else:
result = nil
of someLe+someLt:
if isLetLocation(n[1], true) or isLetLocation(n[2], true):
# XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1'
@@ -337,12 +345,18 @@ proc usefulFact(n: PNode; o: Operators): PNode =
elif n[1].getMagic in someLen or n[2].getMagic in someLen:
# XXX Rethink this whole idea of 'usefulFact' for semparallel
result = n
else:
result = nil
of mIsNil:
if isLetLocation(n[1], false) or isVar(n[1]):
result = n
else:
result = nil
of someIn:
if isLetLocation(n[1], true):
result = n
else:
result = nil
of mAnd:
let
a = usefulFact(n[1], o)
@@ -356,10 +370,14 @@ proc usefulFact(n: PNode; o: Operators): PNode =
result = a
elif b != nil:
result = b
else:
result = nil
of mNot:
let a = usefulFact(n[1], o)
if a != nil:
result = a.neg(o)
else:
result = nil
of mOr:
# 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
# with that knowledge...
@@ -376,6 +394,8 @@ proc usefulFact(n: PNode; o: Operators): PNode =
result[1] = a
result[2] = b
result = result.neg(o)
else:
result = nil
elif n.kind == nkSym and n.sym.kind == skLet:
# consider:
# let a = 2 < x
@@ -384,8 +404,12 @@ proc usefulFact(n: PNode; o: Operators): PNode =
# We make can easily replace 'a' by '2 < x' here:
if n.sym.astdef != nil:
result = usefulFact(n.sym.astdef, o)
else:
result = nil
elif n.kind == nkStmtListExpr:
result = usefulFact(n.lastSon, o)
else:
result = nil
type
TModel* = object
@@ -451,8 +475,9 @@ proc hasSubTree(n, x: PNode): bool =
of nkEmpty..nkNilLit:
result = n.sameTree(x)
of nkFormalParams:
discard
result = false
else:
result = false
for i in 0..<n.len:
if hasSubTree(n[i], x): return true
@@ -483,6 +508,8 @@ proc invalidateFacts*(m: var TModel, n: PNode) =
proc valuesUnequal(a, b: PNode): bool =
if a.isValue and b.isValue:
result = not sameValue(a, b)
else:
result = false
proc impliesEq(fact, eq: PNode): TImplication =
let (loc, val) = if isLocation(eq[1]): (1, 2) else: (2, 1)
@@ -493,16 +520,26 @@ proc impliesEq(fact, eq: PNode): TImplication =
# this is not correct; consider: a == b; a == 1 --> unknown!
if sameTree(fact[2], eq[val]): result = impYes
elif valuesUnequal(fact[2], eq[val]): result = impNo
else:
result = impUnknown
elif sameTree(fact[2], eq[loc]):
if sameTree(fact[1], eq[val]): result = impYes
elif valuesUnequal(fact[1], eq[val]): result = impNo
else:
result = impUnknown
else:
result = impUnknown
of mInSet:
# remember: mInSet is 'contains' so the set comes first!
if sameTree(fact[2], eq[loc]) and isValue(eq[val]):
if inSet(fact[1], eq[val]): result = impYes
else: result = impNo
of mNot, mOr, mAnd: assert(false, "impliesEq")
else: discard
else:
result = impUnknown
of mNot, mOr, mAnd:
result = impUnknown
assert(false, "impliesEq")
else: result = impUnknown
proc leImpliesIn(x, c, aSet: PNode): TImplication =
if c.kind in {nkCharLit..nkUInt64Lit}:
@@ -512,13 +549,19 @@ proc leImpliesIn(x, c, aSet: PNode): TImplication =
var value = newIntNode(c.kind, firstOrd(nil, x.typ))
# don't iterate too often:
if c.intVal - value.intVal < 1000:
var i, pos, neg: int
var i, pos, neg: int = 0
while value.intVal <= c.intVal:
if inSet(aSet, value): inc pos
else: inc neg
inc i; inc value.intVal
if pos == i: result = impYes
elif neg == i: result = impNo
else:
result = impUnknown
else:
result = impUnknown
else:
result = impUnknown
proc geImpliesIn(x, c, aSet: PNode): TImplication =
if c.kind in {nkCharLit..nkUInt64Lit}:
@@ -529,17 +572,23 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication =
let max = lastOrd(nil, x.typ)
# don't iterate too often:
if max - getInt(value) < toInt128(1000):
var i, pos, neg: int
var i, pos, neg: int = 0
while value.intVal <= max:
if inSet(aSet, value): inc pos
else: inc neg
inc i; inc value.intVal
if pos == i: result = impYes
elif neg == i: result = impNo
else: result = impUnknown
else:
result = impUnknown
else:
result = impUnknown
proc compareSets(a, b: PNode): TImplication =
if equalSets(nil, a, b): result = impYes
elif intersectSets(nil, a, b).len == 0: result = impNo
else: result = impUnknown
proc impliesIn(fact, loc, aSet: PNode): TImplication =
case fact[0].sym.magic
@@ -550,22 +599,32 @@ proc impliesIn(fact, loc, aSet: PNode): TImplication =
elif sameTree(fact[2], loc):
if inSet(aSet, fact[1]): result = impYes
else: result = impNo
else:
result = impUnknown
of mInSet:
if sameTree(fact[2], loc):
result = compareSets(fact[1], aSet)
else:
result = impUnknown
of someLe:
if sameTree(fact[1], loc):
result = leImpliesIn(fact[1], fact[2], aSet)
elif sameTree(fact[2], loc):
result = geImpliesIn(fact[2], fact[1], aSet)
else:
result = impUnknown
of someLt:
if sameTree(fact[1], loc):
result = leImpliesIn(fact[1], fact[2].pred, aSet)
elif sameTree(fact[2], loc):
# 4 < x --> 3 <= x
result = geImpliesIn(fact[2], fact[1].pred, aSet)
of mNot, mOr, mAnd: assert(false, "impliesIn")
else: discard
else:
result = impUnknown
of mNot, mOr, mAnd:
result = impUnknown
assert(false, "impliesIn")
else: result = impUnknown
proc valueIsNil(n: PNode): TImplication =
if n.kind == nkNilLit: impYes
@@ -577,13 +636,19 @@ proc impliesIsNil(fact, eq: PNode): TImplication =
of mIsNil:
if sameTree(fact[1], eq[1]):
result = impYes
else:
result = impUnknown
of someEq:
if sameTree(fact[1], eq[1]):
result = valueIsNil(fact[2].skipConv)
elif sameTree(fact[2], eq[1]):
result = valueIsNil(fact[1].skipConv)
of mNot, mOr, mAnd: assert(false, "impliesIsNil")
else: discard
else:
result = impUnknown
of mNot, mOr, mAnd:
result = impUnknown
assert(false, "impliesIsNil")
else: result = impUnknown
proc impliesGe(fact, x, c: PNode): TImplication =
assert isLocation(x)
@@ -594,32 +659,57 @@ proc impliesGe(fact, x, c: PNode): TImplication =
# fact: x = 4; question x >= 56? --> true iff 4 >= 56
if leValue(c, fact[2]): result = impYes
else: result = impNo
else:
result = impUnknown
elif sameTree(fact[2], x):
if isValue(fact[1]) and isValue(c):
if leValue(c, fact[1]): result = impYes
else: result = impNo
else:
result = impUnknown
else:
result = impUnknown
of someLt:
if sameTree(fact[1], x):
if isValue(fact[2]) and isValue(c):
# fact: x < 4; question N <= x? --> false iff N <= 4
if leValue(fact[2], c): result = impNo
else: result = impUnknown
# fact: x < 4; question 2 <= x? --> we don't know
else:
result = impUnknown
elif sameTree(fact[2], x):
# fact: 3 < x; question: N-1 < x ? --> true iff N-1 <= 3
if isValue(fact[1]) and isValue(c):
if leValue(c.pred, fact[1]): result = impYes
else: result = impUnknown
else:
result = impUnknown
else:
result = impUnknown
of someLe:
if sameTree(fact[1], x):
if isValue(fact[2]) and isValue(c):
# fact: x <= 4; question x >= 56? --> false iff 4 <= 56
if leValue(fact[2], c): result = impNo
# fact: x <= 4; question x >= 2? --> we don't know
else:
result = impUnknown
else:
result = impUnknown
elif sameTree(fact[2], x):
# fact: 3 <= x; question: x >= 2 ? --> true iff 2 <= 3
if isValue(fact[1]) and isValue(c):
if leValue(c, fact[1]): result = impYes
of mNot, mOr, mAnd: assert(false, "impliesGe")
else: discard
else: result = impUnknown
else:
result = impUnknown
else:
result = impUnknown
of mNot, mOr, mAnd:
result = impUnknown
assert(false, "impliesGe")
else: result = impUnknown
proc impliesLe(fact, x, c: PNode): TImplication =
if not isLocation(x):
@@ -634,35 +724,59 @@ proc impliesLe(fact, x, c: PNode): TImplication =
# fact: x = 4; question x <= 56? --> true iff 4 <= 56
if leValue(fact[2], c): result = impYes
else: result = impNo
else:
result = impUnknown
elif sameTree(fact[2], x):
if isValue(fact[1]) and isValue(c):
if leValue(fact[1], c): result = impYes
else: result = impNo
else:
result = impUnknown
else:
result = impUnknown
of someLt:
if sameTree(fact[1], x):
if isValue(fact[2]) and isValue(c):
# fact: x < 4; question x <= N? --> true iff N-1 <= 4
if leValue(fact[2], c.pred): result = impYes
else:
result = impUnknown
# fact: x < 4; question x <= 2? --> we don't know
else:
result = impUnknown
elif sameTree(fact[2], x):
# fact: 3 < x; question: x <= 1 ? --> false iff 1 <= 3
if isValue(fact[1]) and isValue(c):
if leValue(c, fact[1]): result = impNo
else: result = impUnknown
else:
result = impUnknown
else:
result = impUnknown
of someLe:
if sameTree(fact[1], x):
if isValue(fact[2]) and isValue(c):
# fact: x <= 4; question x <= 56? --> true iff 4 <= 56
if leValue(fact[2], c): result = impYes
else: result = impUnknown
# fact: x <= 4; question x <= 2? --> we don't know
else:
result = impUnknown
elif sameTree(fact[2], x):
# fact: 3 <= x; question: x <= 2 ? --> false iff 2 < 3
if isValue(fact[1]) and isValue(c):
if leValue(c, fact[1].pred): result = impNo
else:result = impUnknown
else:
result = impUnknown
else:
result = impUnknown
of mNot, mOr, mAnd: assert(false, "impliesLe")
else: discard
of mNot, mOr, mAnd:
result = impUnknown
assert(false, "impliesLe")
else: result = impUnknown
proc impliesLt(fact, x, c: PNode): TImplication =
# x < 3 same as x <= 2:
@@ -674,6 +788,8 @@ proc impliesLt(fact, x, c: PNode): TImplication =
let q = x.pred
if q != x:
result = impliesLe(fact, q, c)
else:
result = impUnknown
proc `~`(x: TImplication): TImplication =
case x
@@ -725,6 +841,7 @@ proc factImplies(fact, prop: PNode): TImplication =
proc doesImply*(facts: TModel, prop: PNode): TImplication =
assert prop.kind in nkCallKinds
result = impUnknown
for f in facts.s:
# facts can be invalidated, in which case they are 'nil':
if not f.isNil:
@@ -753,7 +870,7 @@ template isSub(x): untyped = x.getMagic in someSub
template isVal(x): untyped = x.kind in {nkCharLit..nkUInt64Lit}
template isIntVal(x, y): untyped = x.intVal == y
import macros
import std/macros
macro `=~`(x: PNode, pat: untyped): bool =
proc m(x, pat, conds: NimNode) =
@@ -900,6 +1017,7 @@ proc applyReplacements(n: PNode; rep: TReplacements): PNode =
proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
# now check for inferrable facts: a <= b and b <= c implies a <= c
result = impUnknown
for i in 0..m.s.high:
let fact = m.s[i]
if fact != nil and fact.getMagic in someLe:
@@ -980,8 +1098,8 @@ proc addFactLt*(m: var TModel; a, b: PNode) =
addFactLe(m, a, bb)
proc settype(n: PNode): PType =
result = newType(tySet, ItemId(module: -1, item: -1), n.typ.owner)
var idgen: IdGenerator
var idgen = idGeneratorForPackage(-1'i32)
result = newType(tySet, idgen, n.typ.owner)
addSonSkipIntLit(result, n.typ, idgen)
proc buildOf(it, loc: PNode; o: Operators): PNode =

View File

@@ -17,9 +17,11 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
# we need to ensure that the resulting AST is semchecked. However, it's
# awful to semcheck before macro invocation, so we don't and treat
# templates and macros as immediate in this context.
var rule: string
if c.config.hasHint(hintPattern):
rule = renderTree(n, {renderNoComments})
var rule: string =
if c.config.hasHint(hintPattern):
renderTree(n, {renderNoComments})
else:
""
let s = n[0].sym
case s.kind
of skMacro:
@@ -70,7 +72,7 @@ proc hlo(c: PContext, n: PNode): PNode =
else:
if n.kind in {nkFastAsgn, nkAsgn, nkSinkAsgn, nkIdentDefs, nkVarTuple} and
n[0].kind == nkSym and
{sfGlobal, sfPure} * n[0].sym.flags == {sfGlobal, sfPure}:
{sfGlobal, sfPure} <= n[0].sym.flags:
# do not optimize 'var g {.global} = re(...)' again!
return n
result = applyPatterns(c, n)

View File

@@ -1,7 +1,8 @@
## A BiTable is a table that can be seen as an optimized pair
## of `(Table[LitId, Val], Table[Val, LitId])`.
import hashes, rodfiles
import std/hashes
import rodfiles
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -13,6 +14,8 @@ type
vals: seq[T] # indexed by LitId
keys: seq[LitId] # indexed by hash(val)
proc initBiTable*[T](): BiTable[T] = BiTable[T](vals: @[], keys: @[])
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = (h + 1) and maxHash
@@ -33,9 +36,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
result = (length * 2 < counter * 3) or (length - counter < 4)
const
idStart = 256 ##
## Ids do not start with 0 but with this value. The IR needs it.
## TODO: explain why
idStart = 1
template idToIdx(x: LitId): int = x.int - idStart
@@ -118,6 +119,12 @@ proc load*[T](f: var RodFile; t: var BiTable[T]) =
loadSeq(f, t.vals)
loadSeq(f, t.keys)
proc sizeOnDisc*(t: BiTable[string]): int =
result = 4
for x in t.vals:
result += x.len + 4
result += t.keys.len * sizeof(LitId)
when isMainModule:
var t: BiTable[string]

View File

@@ -18,7 +18,7 @@
## also doing cross-module dependency tracking and DCE that we don't need
## anymore. DCE is now done as prepass over the entire packed module graph.
import std/packedsets, algorithm, tables
import std/[packedsets, algorithm, tables]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -50,10 +50,9 @@ proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var Alive
let n = unpackTree(g, m.module.position, m.fromDisk.topLevel, p)
cgen.genTopLevelStmt(bmod, n)
let disps = finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
if disps != nil:
for disp in disps:
genProcAux(bmod, disp.sym)
finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
for disp in getDispatchers(g):
genProcAux(bmod, disp)
m.fromDisk.backendFlags = cgen.whichInitProcs(bmod)
proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) =
@@ -101,7 +100,7 @@ proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool
var f2 = rodfiles.open(asymFile.string)
f2.loadHeader()
f2.loadSection aliveSymsSection
var oldData: seq[int32]
var oldData: seq[int32] = @[]
f2.loadSeq(oldData)
f2.close
if f2.err == ok and oldData == s:
@@ -147,12 +146,12 @@ proc generateCode*(g: ModuleGraph) =
var alive = computeAliveSyms(g.packed, g.config)
when false:
for i in 0..high(g.packed):
for i in 0..<len(g.packed):
echo i, " is of status ", g.packed[i].status, " ", toFullPath(g.config, FileIndex(i))
# First pass: Setup all the backend modules for all the modules that have
# changed:
for i in 0..high(g.packed):
for i in 0..<len(g.packed):
# case statement here to enforce exhaustive checks.
case g.packed[i].status
of undefined:
@@ -174,7 +173,7 @@ proc generateCode*(g: ModuleGraph) =
let mainModuleIdx = g.config.projectMainIdx2.int
# We need to generate the main module last, because only then
# all init procs have been registered:
for i in 0..high(g.packed):
for i in 0..<len(g.packed):
if i != mainModuleIdx:
genPackedModule(g, i, alive)
if mainModuleIdx >= 0:

View File

@@ -40,10 +40,14 @@ proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): boo
if ({sfExportc, sfCompilerProc} * flags != {}) or
(symPtr.kind == skMethod):
result = true
else:
result = false
# XXX: This used to be a condition to:
# (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
if sfCompilerProc in flags:
c.compilerProcs[g[c.thisModule].fromDisk.strings[symPtr.name]] = (c.thisModule, symId)
else:
result = false
template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty
@@ -105,13 +109,13 @@ proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: N
discard "ignore non-sym atoms"
of nkSym:
# This symbol is alive and everything its body references.
followLater(c, g, c.thisModule, n.operand)
followLater(c, g, c.thisModule, tree[n].soperand)
of nkModuleRef:
let (n1, n2) = sons2(tree, n)
assert n1.kind == nkInt32Lit
assert n2.kind == nkInt32Lit
assert n1.kind == nkNone
assert n2.kind == nkNone
let m = n1.litId
let item = n2.operand
let item = tree[n2].soperand
let otherModule = toFileIndexCached(c.decoder, g, c.thisModule, m).int
followLater(c, g, otherModule, item)
of nkMacroDef, nkTemplateDef, nkTypeSection, nkTypeOfExpr,
@@ -127,7 +131,7 @@ proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: N
rangeCheckAnalysis(c, g, tree, n)
of nkProcDef, nkConverterDef, nkMethodDef, nkFuncDef, nkIteratorDef:
if n.firstSon.kind == nkSym and isNotGeneric(n):
let item = n.firstSon.operand
let item = tree[n.firstSon].soperand
if isExportedToC(c, g, item):
# This symbol is alive and everything its body references.
followLater(c, g, c.thisModule, item)
@@ -149,7 +153,7 @@ proc computeAliveSyms*(g: PackedModuleGraph; conf: ConfigRef): AliveSyms =
var c = AliveContext(stack: @[], decoder: PackedDecoder(config: conf),
thisModule: -1, alive: newSeq[IntSet](g.len),
options: conf.options)
for i in countdown(high(g), 0):
for i in countdown(len(g)-1, 0):
if g[i].status != undefined:
c.thisModule = i
for p in allNodes(g[i].fromDisk.topLevel):

View File

@@ -7,15 +7,17 @@
# distribution, for details about the copyright.
#
import hashes, tables, intsets
import std/[hashes, tables, intsets, monotimes]
import packed_ast, bitabs, rodfiles
import ".." / [ast, idents, lineinfos, msgs, ropes, options,
pathutils, condsyms, packages, modulepaths]
#import ".." / [renderer, astalgo]
from os import removeFile, isAbsolute
from std/os import removeFile, isAbsolute
import ../../dist/checksums/src/checksums/sha1
import ".." / nir / nirlineinfos
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions, formatfloat]
@@ -41,16 +43,18 @@ type
bodies*: PackedTree # other trees. Referenced from typ.n and sym.ast by their position.
#producedGenerics*: Table[GenericKey, SymId]
exports*: seq[(LitId, int32)]
hidden*: seq[(LitId, int32)]
reexports*: seq[(LitId, PackedItemId)]
hidden: seq[(LitId, int32)]
reexports: seq[(LitId, PackedItemId)]
compilerProcs*: seq[(LitId, int32)]
converters*, methods*, trmacros*, pureEnums*: seq[int32]
typeInstCache*: seq[(PackedItemId, PackedItemId)]
procInstCache*: seq[PackedInstantiation]
attachedOps*: seq[(PackedItemId, TTypeAttachedOp, PackedItemId)]
methodsPerType*: seq[(PackedItemId, int, PackedItemId)]
methodsPerGenericType*: seq[(PackedItemId, int, PackedItemId)]
enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
methodsPerType*: seq[(PackedItemId, PackedItemId)]
dispatchers*: seq[PackedItemId]
emittedTypeInfo*: seq[string]
backendFlags*: set[ModuleBackendFlag]
@@ -60,6 +64,7 @@ type
strings*: BiTable[string] # we could share these between modules.
numbers*: BiTable[BiggestInt] # we also store floats in here so
# that we can assure that every bit is kept
man*: LineInfoManager
cfg: PackedConfig
@@ -75,37 +80,36 @@ type
symMarker*: IntSet #Table[ItemId, SymId] # ItemId.item -> SymId
config*: ConfigRef
proc toString*(tree: PackedTree; n: NodePos; m: PackedModule; nesting: int;
proc toString*(tree: PackedTree; pos: NodePos; m: PackedModule; nesting: int;
result: var string) =
let pos = n.int
if result.len > 0 and result[^1] notin {' ', '\n'}:
result.add ' '
result.add $tree[pos].kind
case tree.nodes[pos].kind
of nkNone, nkEmpty, nkNilLit, nkType: discard
case tree[pos].kind
of nkEmpty, nkNilLit, nkType: discard
of nkIdent, nkStrLit..nkTripleStrLit:
result.add " "
result.add m.strings[LitId tree.nodes[pos].operand]
result.add m.strings[LitId tree[pos].uoperand]
of nkSym:
result.add " "
result.add m.strings[m.syms[tree.nodes[pos].operand].name]
result.add m.strings[m.syms[tree[pos].soperand].name]
of directIntLit:
result.add " "
result.addInt tree.nodes[pos].operand
result.addInt tree[pos].soperand
of externSIntLit:
result.add " "
result.addInt m.numbers[LitId tree.nodes[pos].operand]
result.addInt m.numbers[LitId tree[pos].uoperand]
of externUIntLit:
result.add " "
result.addInt cast[uint64](m.numbers[LitId tree.nodes[pos].operand])
result.addInt cast[uint64](m.numbers[LitId tree[pos].uoperand])
of nkFloatLit..nkFloat128Lit:
result.add " "
result.addFloat cast[BiggestFloat](m.numbers[LitId tree.nodes[pos].operand])
result.addFloat cast[BiggestFloat](m.numbers[LitId tree[pos].uoperand])
else:
result.add "(\n"
for i in 1..(nesting+1)*2: result.add ' '
for child in sonsReadonly(tree, n):
for child in sonsReadonly(tree, pos):
toString(tree, child, m, nesting + 1, result)
result.add "\n"
for i in 1..nesting*2: result.add ' '
@@ -231,10 +235,14 @@ proc addImportFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex)
m.imports.add toLitId(f, c, m)
proc addHidden*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
assert s.kind != skUnknown
let nameId = getOrIncl(m.strings, s.name.s)
m.hidden.add((nameId, s.itemId.item))
assert s.itemId.module == c.thisModule
proc addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
assert s.kind != skUnknown
assert s.itemId.module == c.thisModule
let nameId = getOrIncl(m.strings, s.name.s)
m.exports.add((nameId, s.itemId.item))
@@ -253,6 +261,8 @@ proc addMethod*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
m.methods.add s.itemId.item
proc addReexport*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
assert s.kind != skUnknown
if s.kind == skModule: return
let nameId = getOrIncl(m.strings, s.name.s)
m.reexports.add((nameId, PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m),
item: s.itemId.item)))
@@ -284,7 +294,8 @@ proc toLitId(x: BiggestInt; m: var PackedModule): LitId =
result = getOrIncl(m.numbers, x)
proc toPackedInfo(x: TLineInfo; c: var PackedEncoder; m: var PackedModule): PackedLineInfo =
PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c, m))
pack(m.man, toLitId(x.fileIndex, c, m), x.line.int32, x.col.int32)
#PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c, m))
proc safeItemId(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId {.inline.} =
## given a symbol, produce an ItemId with the correct properties
@@ -336,7 +347,7 @@ proc storeTypeLater(t: PType; c: var PackedEncoder; m: var PackedModule): Packed
proc storeSymLater(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId =
if s.isNil: return nilItemId
assert s.itemId.module >= 0
assert s.itemId.module >= 0
assert s.itemId.item >= 0
result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item)
if s.itemId.module == c.thisModule:
# the sym belongs to this module, so serialize it here, eventually.
@@ -359,7 +370,7 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI
paddingAtEnd: t.paddingAtEnd)
storeNode(p, t, n)
p.typeInst = t.typeInst.storeType(c, m)
for kid in items t.sons:
for kid in items t:
p.types.add kid.storeType(c, m)
c.addMissing t.sym
p.sym = t.sym.safeItemId(c, m)
@@ -413,6 +424,7 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
p.annex = toPackedLib(s.annex, c, m)
when hasFFI:
p.cname = toLitId(s.cname, m)
p.instantiatedFrom = s.instantiatedFrom.safeItemId(c, m)
# fill the reserved slot, nothing else:
m.syms[s.itemId.item] = p
@@ -420,53 +432,59 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
## add a remote symbol reference to the tree
let info = n.info.toPackedInfo(c, m)
ir.nodes.add PackedNode(kind: nkModuleRef, operand: 3.int32, # spans 3 nodes in total
typeId: storeTypeLater(n.typ, c, m), info: info)
ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
operand: toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
operand: n.sym.itemId.item)
if n.typ != n.sym.typ:
ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total
info = info,
typeId = storeTypeLater(n.typ, c, m))
else:
ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total
info = info)
ir.addNode(kind = nkNone, info = info,
operand = toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
ir.addNode(kind = nkNone, info = info,
operand = n.sym.itemId.item)
proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
## serialize a node into the tree
if n == nil:
ir.nodes.add PackedNode(kind: nkNilRodNode, flags: {}, operand: 1)
ir.addNode(kind = nkNilRodNode, operand = 1, info = NoLineInfo)
return
let info = toPackedInfo(n.info, c, m)
case n.kind
of nkNone, nkEmpty, nkNilLit, nkType:
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, operand: 0,
typeId: storeTypeLater(n.typ, c, m), info: info)
ir.addNode(kind = n.kind, flags = n.flags, operand = 0,
typeId = storeTypeLater(n.typ, c, m), info = info)
of nkIdent:
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32 getOrIncl(m.strings, n.ident.s),
typeId: storeTypeLater(n.typ, c, m), info: info)
ir.addNode(kind = n.kind, flags = n.flags,
operand = int32 getOrIncl(m.strings, n.ident.s),
typeId = storeTypeLater(n.typ, c, m), info = info)
of nkSym:
if n.sym.itemId.module == c.thisModule:
# it is a symbol that belongs to the module we're currently
# packing:
let id = n.sym.storeSymLater(c, m).item
ir.nodes.add PackedNode(kind: nkSym, flags: n.flags, operand: id,
typeId: storeTypeLater(n.typ, c, m), info: info)
if n.typ != n.sym.typ:
ir.addNode(kind = nkSym, flags = n.flags, operand = id,
info = info,
typeId = storeTypeLater(n.typ, c, m))
else:
ir.addNode(kind = nkSym, flags = n.flags, operand = id,
info = info)
else:
# store it as an external module reference:
addModuleRef(n, ir, c, m)
of directIntLit:
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32(n.intVal),
typeId: storeTypeLater(n.typ, c, m), info: info)
of externIntLit:
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32 getOrIncl(m.numbers, n.intVal),
typeId: storeTypeLater(n.typ, c, m), info: info)
ir.addNode(kind = n.kind, flags = n.flags,
operand = int32 getOrIncl(m.numbers, n.intVal),
typeId = storeTypeLater(n.typ, c, m), info = info)
of nkStrLit..nkTripleStrLit:
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32 getOrIncl(m.strings, n.strVal),
typeId: storeTypeLater(n.typ, c, m), info: info)
ir.addNode(kind = n.kind, flags = n.flags,
operand = int32 getOrIncl(m.strings, n.strVal),
typeId = storeTypeLater(n.typ, c, m), info = info)
of nkFloatLit..nkFloat128Lit:
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32 getOrIncl(m.numbers, cast[BiggestInt](n.floatVal)),
typeId: storeTypeLater(n.typ, c, m), info: info)
ir.addNode(kind = n.kind, flags = n.flags,
operand = int32 getOrIncl(m.numbers, cast[BiggestInt](n.floatVal)),
typeId = storeTypeLater(n.typ, c, m), info = info)
else:
let patchPos = ir.prepare(n.kind, n.flags,
storeTypeLater(n.typ, c, m), info)
@@ -491,8 +509,8 @@ proc toPackedProcDef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var
# do not serialize the body of the proc, it's unnecessary since
# n[0].sym.ast has the sem'checked variant of it which is what
# everybody should use instead.
ir.nodes.add PackedNode(kind: nkEmpty, flags: {}, operand: 0,
typeId: nilItemId, info: info)
ir.addNode(kind = nkEmpty, flags = {}, operand = 0,
typeId = nilItemId, info = info)
ir.patch patchPos
proc toPackedNodeIgnoreProcDefs(n: PNode, encoder: var PackedEncoder; m: var PackedModule) =
@@ -565,6 +583,20 @@ proc toRodFile*(conf: ConfigRef; f: AbsoluteFile; ext = RodExt): AbsoluteFile =
result = changeFileExt(completeGeneratedFilePath(conf,
mangleModuleName(conf, f).AbsoluteFile), ext)
const
BenchIC* = false
when BenchIC:
var gloadBodies: MonoTime
template bench(x, body) =
let start = getMonoTime()
body
x = x + (getMonoTime() - start)
else:
template bench(x, body) = body
proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef;
ignoreConfig = false): RodFileError =
var f = rodfiles.open(filename.string)
@@ -589,40 +621,48 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef
loadTabSection stringsSection, m.strings
loadSeqSection checkSumsSection, m.includes
if not includesIdentical(m, config):
if config.cmd != cmdM and not includesIdentical(m, config):
f.err = includeFileChanged
loadSeqSection depsSection, m.imports
loadTabSection numbersSection, m.numbers
bench gloadBodies:
loadSeqSection exportsSection, m.exports
loadSeqSection hiddenSection, m.hidden
loadSeqSection reexportsSection, m.reexports
loadTabSection numbersSection, m.numbers
loadSeqSection compilerProcsSection, m.compilerProcs
loadSeqSection exportsSection, m.exports
loadSeqSection hiddenSection, m.hidden
loadSeqSection reexportsSection, m.reexports
loadSeqSection trmacrosSection, m.trmacros
loadSeqSection compilerProcsSection, m.compilerProcs
loadSeqSection convertersSection, m.converters
loadSeqSection methodsSection, m.methods
loadSeqSection pureEnumsSection, m.pureEnums
loadSeqSection trmacrosSection, m.trmacros
loadSeqSection toReplaySection, m.toReplay.nodes
loadSeqSection topLevelSection, m.topLevel.nodes
loadSeqSection bodiesSection, m.bodies.nodes
loadSeqSection symsSection, m.syms
loadSeqSection typesSection, m.types
loadSeqSection convertersSection, m.converters
loadSeqSection methodsSection, m.methods
loadSeqSection pureEnumsSection, m.pureEnums
loadSeqSection typeInstCacheSection, m.typeInstCache
loadSeqSection procInstCacheSection, m.procInstCache
loadSeqSection attachedOpsSection, m.attachedOps
loadSeqSection methodsPerTypeSection, m.methodsPerType
loadSeqSection enumToStringProcsSection, m.enumToStringProcs
loadSeqSection typeInfoSection, m.emittedTypeInfo
loadTabSection toReplaySection, m.toReplay
loadTabSection topLevelSection, m.topLevel
f.loadSection backendFlagsSection
f.loadPrim m.backendFlags
loadTabSection bodiesSection, m.bodies
loadSeqSection symsSection, m.syms
loadSeqSection typesSection, m.types
loadSeqSection typeInstCacheSection, m.typeInstCache
loadSeqSection procInstCacheSection, m.procInstCache
loadSeqSection attachedOpsSection, m.attachedOps
loadSeqSection methodsPerGenericTypeSection, m.methodsPerGenericType
loadSeqSection enumToStringProcsSection, m.enumToStringProcs
loadSeqSection methodsPerTypeSection, m.methodsPerType
loadSeqSection dispatchersSection, m.dispatchers
loadSeqSection typeInfoSection, m.emittedTypeInfo
f.loadSection backendFlagsSection
f.loadPrim m.backendFlags
f.loadSection sideChannelSection
f.load m.man
close(f)
result = f.err
@@ -671,10 +711,10 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
storeSeqSection methodsSection, m.methods
storeSeqSection pureEnumsSection, m.pureEnums
storeSeqSection toReplaySection, m.toReplay.nodes
storeSeqSection topLevelSection, m.topLevel.nodes
storeTabSection toReplaySection, m.toReplay
storeTabSection topLevelSection, m.topLevel
storeSeqSection bodiesSection, m.bodies.nodes
storeTabSection bodiesSection, m.bodies
storeSeqSection symsSection, m.syms
storeSeqSection typesSection, m.types
@@ -682,13 +722,18 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
storeSeqSection typeInstCacheSection, m.typeInstCache
storeSeqSection procInstCacheSection, m.procInstCache
storeSeqSection attachedOpsSection, m.attachedOps
storeSeqSection methodsPerTypeSection, m.methodsPerType
storeSeqSection methodsPerGenericTypeSection, m.methodsPerGenericType
storeSeqSection enumToStringProcsSection, m.enumToStringProcs
storeSeqSection methodsPerTypeSection, m.methodsPerType
storeSeqSection dispatchersSection, m.dispatchers
storeSeqSection typeInfoSection, m.emittedTypeInfo
f.storeSection backendFlagsSection
f.storePrim m.backendFlags
f.storeSection sideChannelSection
f.store m.man
close(f)
encoder.disable()
if f.err != ok:
@@ -730,13 +775,29 @@ type
# PackedItemId so that it works with reexported symbols too
# ifaceHidden includes private symbols
PackedModuleGraph* = seq[LoadedModule] # indexed by FileIndex
type
PackedModuleGraph* = object
pm*: seq[LoadedModule] # indexed by FileIndex
when BenchIC:
depAnalysis: MonoTime
loadBody: MonoTime
loadSym, loadType, loadBodies: MonoTime
when BenchIC:
proc echoTimes*(m: PackedModuleGraph) =
echo "analysis: ", m.depAnalysis, " loadBody: ", m.loadBody, " loadSym: ",
m.loadSym, " loadType: ", m.loadType, " all bodies: ", gloadBodies
template `[]`*(m: PackedModuleGraph; i: int): LoadedModule = m.pm[i]
template len*(m: PackedModuleGraph): int = m.pm.len
proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t: PackedItemId): PType
proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym
proc toFileIndexCached*(c: var PackedDecoder; g: PackedModuleGraph; thisModule: int; f: LitId): FileIndex =
if c.lastLit == f and c.lastModule == thisModule:
if f == LitId(0):
result = InvalidFileIdx
elif c.lastLit == f and c.lastModule == thisModule:
result = c.lastFile
else:
result = toFileIndex(f, g[thisModule].fromDisk, c.config)
@@ -747,8 +808,9 @@ proc toFileIndexCached*(c: var PackedDecoder; g: PackedModuleGraph; thisModule:
proc translateLineInfo(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
x: PackedLineInfo): TLineInfo =
assert g[thisModule].status in {loaded, storing, stored}
result = TLineInfo(line: x.line, col: x.col,
fileIndex: toFileIndexCached(c, g, thisModule, x.file))
let (fileId, line, col) = unpack(g[thisModule].fromDisk.man, x)
result = TLineInfo(line: line.uint16, col: col.int16,
fileIndex: toFileIndexCached(c, g, thisModule, fileId))
proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
tree: PackedTree; n: NodePos): PNode =
@@ -762,14 +824,13 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
result.flags = n.flags
case k
of nkEmpty, nkNilLit, nkType:
of nkNone, nkEmpty, nkNilLit, nkType:
discard
of nkIdent:
result.ident = getIdent(c.cache, g[thisModule].fromDisk.strings[n.litId])
of nkSym:
result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree.nodes[n.int].operand))
of directIntLit:
result.intVal = tree.nodes[n.int].operand
result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree[n].soperand))
if result.typ == nil: result.typ = result.sym.typ
of externIntLit:
result.intVal = g[thisModule].fromDisk.numbers[n.litId]
of nkStrLit..nkTripleStrLit:
@@ -778,10 +839,11 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
result.floatVal = cast[BiggestFloat](g[thisModule].fromDisk.numbers[n.litId])
of nkModuleRef:
let (n1, n2) = sons2(tree, n)
assert n1.kind == nkInt32Lit
assert n2.kind == nkInt32Lit
assert n1.kind == nkNone
assert n2.kind == nkNone
transitionNoneToSym(result)
result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand))
result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree[n2].soperand))
if result.typ == nil: result.typ = result.sym.typ
else:
for n0 in sonsReadonly(tree, n):
result.addAllowNil loadNodes(c, g, thisModule, tree, n0)
@@ -813,6 +875,7 @@ proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; thisModule:
proc loadProcBody(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
tree: PackedTree; n: NodePos): PNode =
result = nil
var i = 0
for n0 in sonsReadonly(tree, n):
if i == bodyPos:
@@ -875,12 +938,27 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
if externalName != "":
result.loc.r = rope externalName
result.loc.flags = s.locFlags
result.instantiatedFrom = loadSym(c, g, si, s.instantiatedFrom)
proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
fileIdx: FileIndex; cachedModules: var seq[FileIndex]): bool
proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
fileIdx: FileIndex; m: var LoadedModule)
proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym =
if s == nilItemId:
result = nil
else:
let si = moduleIndex(c, g, thisModule, s)
if si >= g.len:
g.pm.setLen(si+1)
if g[si].status == undefined and c.config.cmd == cmdM:
var cachedModules: seq[FileIndex] = @[]
discard needsRecompile(g, c.config, c.cache, FileIndex(si), cachedModules)
for m in cachedModules:
loadToReplayNodes(g, c.config, c.cache, m, g[int m])
assert g[si].status in {loaded, storing, stored}
if not g[si].symsInit:
g[si].symsInit = true
@@ -895,6 +973,7 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s:
else:
result = g[si].module
assert result != nil
g[si].syms[s.item] = result
else:
result = g[si].syms[s.item]
@@ -915,8 +994,10 @@ proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
for op, item in pairs t.attachedOps:
result.attachedOps[op] = loadSym(c, g, si, item)
result.typeInst = loadType(c, g, si, t.typeInst)
var sons = newSeq[PType]()
for son in items t.types:
result.sons.add loadType(c, g, si, son)
sons.add loadType(c, g, si, son)
result.setSons(sons)
loadAstBody(t, n)
when false:
for gen, id in items t.methods:
@@ -939,9 +1020,11 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t
# store it here early on, so that recursions work properly:
g[si].types[t.item] = result
typeBodyFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item, result)
#assert result.itemId.item == t.item, $(result.itemId.item, t.item)
assert result.itemId.item > 0, $(result.itemId.item, t.item)
else:
result = g[si].types[t.item]
assert result.itemId.item > 0
assert result.itemId.item > 0, "2"
proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
fileIdx: FileIndex; m: var LoadedModule) =
@@ -991,30 +1074,37 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache
# Does the file belong to the fileIdx need to be recompiled?
let m = int(fileIdx)
if m >= g.len:
g.setLen(m+1)
g.pm.setLen(m+1)
case g[m].status
of undefined:
g[m].status = loading
let fullpath = msgs.toFullPath(conf, fileIdx)
let rod = toRodFile(conf, AbsoluteFile fullpath)
let err = loadRodFile(rod, g[m].fromDisk, conf)
let err = loadRodFile(rod, g[m].fromDisk, conf, ignoreConfig = conf.cmd == cmdM)
if err == ok:
result = optForceFullMake in conf.globalOptions
# check its dependencies:
for dep in g[m].fromDisk.imports:
let fid = toFileIndex(dep, g[m].fromDisk, conf)
# Warning: we need to traverse the full graph, so
# do **not use break here**!
if needsRecompile(g, conf, cache, fid, cachedModules):
result = true
if not result:
if conf.cmd == cmdM:
setupLookupTables(g, conf, cache, fileIdx, g[m])
cachedModules.add fileIdx
g[m].status = loaded
result = false
else:
g[m] = LoadedModule(status: outdated, module: g[m].module)
result = optForceFullMake in conf.globalOptions
# check its dependencies:
let imp = g[m].fromDisk.imports
for dep in imp:
let fid = toFileIndex(dep, g[m].fromDisk, conf)
# Warning: we need to traverse the full graph, so
# do **not use break here**!
if needsRecompile(g, conf, cache, fid, cachedModules):
result = true
if not result:
setupLookupTables(g, conf, cache, fileIdx, g[m])
cachedModules.add fileIdx
g[m].status = loaded
else:
g.pm[m] = LoadedModule(status: outdated, module: g[m].module)
else:
loadError(err, rod, conf)
g[m].status = outdated
@@ -1029,12 +1119,13 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache
proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
fileIdx: FileIndex; cachedModules: var seq[FileIndex]): PSym =
## Returns 'nil' if the module needs to be recompiled.
if needsRecompile(g, conf, cache, fileIdx, cachedModules):
result = nil
else:
result = g[int fileIdx].module
assert result != nil
assert result.position == int(fileIdx)
bench g.depAnalysis:
if needsRecompile(g, conf, cache, fileIdx, cachedModules):
result = nil
else:
result = g[int fileIdx].module
assert result != nil
assert result.position == int(fileIdx)
for m in cachedModules:
loadToReplayNodes(g, conf, cache, m, g[int m])
@@ -1048,46 +1139,49 @@ template setupDecoder() {.dirty.} =
proc loadProcBody*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; s: PSym): PNode =
let mId = s.itemId.module
var decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
lastFile: FileIndex(-1),
config: config,
cache: cache)
let pos = g[mId].fromDisk.syms[s.itemId.item].ast
assert pos != emptyNodeId
result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos)
bench g.loadBody:
let mId = s.itemId.module
var decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
lastFile: FileIndex(-1),
config: config,
cache: cache)
let pos = g[mId].fromDisk.syms[s.itemId.item].ast
assert pos != emptyNodeId
result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos)
proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
if id.item < g[module].types.len:
result = g[module].types[id.item]
else:
result = nil
if result == nil:
var decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
lastFile: FileIndex(-1),
config: config,
cache: cache)
result = loadType(decoder, g, module, id)
bench g.loadType:
if id.item < g[module].types.len:
result = g[module].types[id.item]
else:
result = nil
if result == nil:
var decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
lastFile: FileIndex(-1),
config: config,
cache: cache)
result = loadType(decoder, g, module, id)
proc loadSymFromId*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: int; id: PackedItemId): PSym =
if id.item < g[module].syms.len:
result = g[module].syms[id.item]
else:
result = nil
if result == nil:
var decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
lastFile: FileIndex(-1),
config: config,
cache: cache)
result = loadSym(decoder, g, module, id)
bench g.loadSym:
if id.item < g[module].syms.len:
result = g[module].syms[id.item]
else:
result = nil
if result == nil:
var decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
lastFile: FileIndex(-1),
config: config,
cache: cache)
result = loadSym(decoder, g, module, id)
proc translateId*(id: PackedItemId; g: PackedModuleGraph; thisModule: int; config: ConfigRef): ItemId =
if id.module == LitId(0):
@@ -1147,9 +1241,11 @@ proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache;
if it.i < it.values.len:
result = loadSym(it.decoder, g, int(module), it.values[it.i])
inc it.i
else:
result = nil
proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: FileIndex, importHidden: bool): PSym =
g: var PackedModuleGraph; module: FileIndex; importHidden: bool): PSym =
it.decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
@@ -1164,11 +1260,15 @@ proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
if it.i < it.values.len:
result = loadSym(it.decoder, g, int(module), it.values[it.i])
inc it.i
else:
result = nil
proc nextRodIter*(it: var RodIter; g: var PackedModuleGraph): PSym =
if it.i < it.values.len:
result = loadSym(it.decoder, g, it.module, it.values[it.i])
inc it.i
else:
result = nil
iterator interfaceSymbols*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: FileIndex;
@@ -1201,12 +1301,12 @@ proc searchForCompilerproc*(m: LoadedModule; name: string): int32 =
# ------------------------- .rod file viewer ---------------------------------
proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
var m: PackedModule
var m: PackedModule = PackedModule()
let err = loadRodFile(rodfile, m, config, ignoreConfig=true)
if err != ok:
config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err
when true:
when false:
echo "exports:"
for ex in m.exports:
echo " ", m.strings[ex[0]], " local ID: ", ex[1]
@@ -1222,13 +1322,32 @@ proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
for ex in m.hidden:
echo " ", m.strings[ex[0]], " local ID: ", ex[1]
echo "all symbols"
for i in 0..high(m.syms):
if m.syms[i].name != LitId(0):
echo " ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind
else:
echo " <anon symbol?> local ID: ", i, " kind ", m.syms[i].kind
when false:
echo "all symbols"
for i in 0..high(m.syms):
if m.syms[i].name != LitId(0):
echo " ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind
else:
echo " <anon symbol?> local ID: ", i, " kind ", m.syms[i].kind
echo "symbols: ", m.syms.len, " types: ", m.types.len,
" top level nodes: ", m.topLevel.nodes.len, " other nodes: ", m.bodies.nodes.len,
" top level nodes: ", m.topLevel.len, " other nodes: ", m.bodies.len,
" strings: ", m.strings.len, " numbers: ", m.numbers.len
echo "SIZES:"
echo "symbols: ", m.syms.len * sizeof(PackedSym), " types: ", m.types.len * sizeof(PackedType),
" top level nodes: ", m.topLevel.len * sizeof(PackedNode),
" other nodes: ", m.bodies.len * sizeof(PackedNode),
" strings: ", sizeOnDisc(m.strings)
when false:
var tt = 0
var fc = 0
for x in m.topLevel:
if x.kind == nkSym or x.typeId == nilItemId: inc tt
if x.flags == {}: inc fc
for x in m.bodies:
if x.kind == nkSym or x.typeId == nilItemId: inc tt
if x.flags == {}: inc fc
let total = float(m.topLevel.len + m.bodies.len)
echo "nodes with nil type: ", tt, " in % ", tt.float / total
echo "nodes with empty flags: ", fc.float / total

View File

@@ -10,7 +10,7 @@
## Integrity checking for a set of .rod files.
## The set must cover a complete Nim project.
import sets
import std/sets
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -72,15 +72,16 @@ proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) =
c.thisModule = oldThisModule
proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
if tree[n.int].typeId != nilItemId:
checkType(c, tree[n.int].typeId)
let t = findType(tree, n)
if t != nilItemId:
checkType(c, t)
case n.kind
of nkEmpty, nkNilLit, nkType, nkNilRodNode:
discard
of nkIdent:
assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
of nkSym:
checkLocalSym(c, tree.nodes[n.int].operand)
checkLocalSym(c, tree[n].soperand)
of directIntLit:
discard
of externIntLit, nkFloatLit..nkFloat128Lit:
@@ -89,9 +90,9 @@ proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
of nkModuleRef:
let (n1, n2) = sons2(tree, n)
assert n1.kind == nkInt32Lit
assert n2.kind == nkInt32Lit
checkForeignSym(c, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand))
assert n1.kind == nkNone
assert n2.kind == nkNone
checkForeignSym(c, PackedItemId(module: n1.litId, item: tree[n2].soperand))
else:
for n0 in sonsReadonly(tree, n):
checkNode(c, tree, n0)
@@ -134,13 +135,15 @@ proc checkModule(c: var CheckedContext; m: PackedModule) =
typeInstCache*: seq[(PackedItemId, PackedItemId)]
procInstCache*: seq[PackedInstantiation]
attachedOps*: seq[(TTypeAttachedOp, PackedItemId, PackedItemId)]
methodsPerType*: seq[(PackedItemId, int, PackedItemId)]
methodsPerGenericType*: seq[(PackedItemId, int, PackedItemId)]
enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
methodsPerType*: seq[(PackedItemId, PackedItemId)]
dispatchers*: seq[PackedItemId]
]#
proc checkIntegrity*(g: ModuleGraph) =
var c = CheckedContext(g: g)
for i in 0..high(g.packed):
for i in 0..<len(g.packed):
# case statement here to enforce exhaustive checks.
case g.packed[i].status
of undefined:
@@ -150,4 +153,3 @@ proc checkIntegrity*(g: ModuleGraph) =
of stored, storing, outdated, loaded:
c.thisModule = int32 i
checkModule(c, g.packed[i].fromDisk)

View File

@@ -11,59 +11,70 @@
## IDE-like features. It uses the set of .rod files to accomplish
## its task. The set must cover a complete Nim project.
import sets
import std/sets
from os import nil
from std/os import nil
from std/private/miscdollars import toLocation
when defined(nimPreviewSlimSystem):
import std/assertions
import ".." / [ast, modulegraphs, msgs, options]
import ".." / nir / nirlineinfos
import packed_ast, bitabs, ic
type
UnpackedLineInfo = object
file: LitId
line, col: int
NavContext = object
g: ModuleGraph
thisModule: int32
trackPos: PackedLineInfo
trackPos: UnpackedLineInfo
alreadyEmitted: HashSet[string]
outputSep: char # for easier testing, use short filenames and spaces instead of tabs.
proc isTracked(current, trackPos: PackedLineInfo, tokenLen: int): bool =
if current.file == trackPos.file and current.line == trackPos.line:
proc isTracked(man: LineInfoManager; current: PackedLineInfo, trackPos: UnpackedLineInfo, tokenLen: int): bool =
let (currentFile, currentLine, currentCol) = man.unpack(current)
if currentFile == trackPos.file and currentLine == trackPos.line:
let col = trackPos.col
if col >= current.col and col < current.col+tokenLen:
return true
if col >= currentCol and col < currentCol+tokenLen:
result = true
else:
result = false
else:
result = false
proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool =
result = s.name != LitId(0) and
isTracked(info, c.trackPos, c.g.packed[c.thisModule].fromDisk.strings[s.name].len)
isTracked(c.g.packed[c.thisModule].fromDisk.man, info, c.trackPos, c.g.packed[c.thisModule].fromDisk.strings[s.name].len)
proc searchForeignSym(c: var NavContext; s: ItemId; info: PackedLineInfo): bool =
let name = c.g.packed[s.module].fromDisk.syms[s.item].name
result = name != LitId(0) and
isTracked(info, c.trackPos, c.g.packed[s.module].fromDisk.strings[name].len)
isTracked(c.g.packed[c.thisModule].fromDisk.man, info, c.trackPos, c.g.packed[s.module].fromDisk.strings[name].len)
const
EmptyItemId = ItemId(module: -1'i32, item: -1'i32)
proc search(c: var NavContext; tree: PackedTree): ItemId =
# We use the linear representation here directly:
for i in 0..high(tree.nodes):
case tree.nodes[i].kind
for i in 0..<len(tree):
let i = NodePos(i)
case tree[i].kind
of nkSym:
let item = tree.nodes[i].operand
if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.syms[item], tree.nodes[i].info):
let item = tree[i].soperand
if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.syms[item], tree[i].info):
return ItemId(module: c.thisModule, item: item)
of nkModuleRef:
if tree.nodes[i].info.line == c.trackPos.line and tree.nodes[i].info.file == c.trackPos.file:
let (n1, n2) = sons2(tree, NodePos i)
let (currentFile, currentLine, currentCol) = c.g.packed[c.thisModule].fromDisk.man.unpack(tree[i].info)
if currentLine == c.trackPos.line and currentFile == c.trackPos.file:
let (n1, n2) = sons2(tree, i)
assert n1.kind == nkInt32Lit
assert n2.kind == nkInt32Lit
let pId = PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand)
let pId = PackedItemId(module: n1.litId, item: tree[n2].soperand)
let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config)
if searchForeignSym(c, itemId, tree.nodes[i].info):
if searchForeignSym(c, itemId, tree[i].info):
return itemId
else: discard
return EmptyItemId
@@ -73,36 +84,38 @@ proc isDecl(tree: PackedTree; n: NodePos): bool =
const declarativeNodes = procDefs + {nkMacroDef, nkTemplateDef,
nkLetSection, nkVarSection, nkUsingStmt, nkConstSection, nkTypeSection,
nkIdentDefs, nkEnumTy, nkVarTuple}
result = n.int >= 0 and tree[n.int].kind in declarativeNodes
result = n.int >= 0 and tree[n].kind in declarativeNodes
proc usage(c: var NavContext; info: PackedLineInfo; isDecl: bool) =
let (fileId, line, col) = unpack(c.g.packed[c.thisModule].fromDisk.man, info)
var m = ""
var file = c.g.packed[c.thisModule].fromDisk.strings[info.file]
var file = c.g.packed[c.thisModule].fromDisk.strings[fileId]
if c.outputSep == ' ':
file = os.extractFilename file
toLocation(m, file, info.line.int, info.col.int + ColOffset)
toLocation(m, file, line, col + ColOffset)
if not c.alreadyEmitted.containsOrIncl(m):
msgWriteln c.g.config, (if isDecl: "def" else: "usage") & c.outputSep & m
proc list(c: var NavContext; tree: PackedTree; sym: ItemId) =
for i in 0..high(tree.nodes):
case tree.nodes[i].kind
for i in 0..<len(tree):
let i = NodePos(i)
case tree[i].kind
of nkSym:
let item = tree.nodes[i].operand
let item = tree[i].soperand
if sym.item == item and sym.module == c.thisModule:
usage(c, tree.nodes[i].info, isDecl(tree, parent(NodePos i)))
usage(c, tree[i].info, isDecl(tree, parent(i)))
of nkModuleRef:
let (n1, n2) = sons2(tree, NodePos i)
assert n1.kind == nkInt32Lit
assert n2.kind == nkInt32Lit
let pId = PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand)
let (n1, n2) = sons2(tree, i)
assert n1.kind == nkNone
assert n2.kind == nkNone
let pId = PackedItemId(module: n1.litId, item: tree[n2].soperand)
let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config)
if itemId.item == sym.item and sym.module == itemId.module:
usage(c, tree.nodes[i].info, isDecl(tree, parent(NodePos i)))
usage(c, tree[i].info, isDecl(tree, parent(i)))
else: discard
proc searchForIncludeFile(g: ModuleGraph; fullPath: string): int =
for i in 0..high(g.packed):
for i in 0..<len(g.packed):
for k in 1..high(g.packed[i].fromDisk.includes):
# we start from 1 because the first "include" file is
# the module's filename.
@@ -134,7 +147,7 @@ proc nav(g: ModuleGraph) =
var c = NavContext(
g: g,
thisModule: int32 mid,
trackPos: PackedLineInfo(line: unpacked.line, col: unpacked.col, file: fileId),
trackPos: UnpackedLineInfo(line: unpacked.line.int, col: unpacked.col.int, file: fileId),
outputSep: if isDefined(g.config, "nimIcNavigatorTests"): ' ' else: '\t'
)
var symId = search(c, g.packed[mid].fromDisk.topLevel)
@@ -145,7 +158,7 @@ proc nav(g: ModuleGraph) =
localError(g.config, unpacked, "no symbol at this position")
return
for i in 0..high(g.packed):
for i in 0..<len(g.packed):
# case statement here to enforce exhaustive checks.
case g.packed[i].status
of undefined:
@@ -162,7 +175,7 @@ proc navUsages*(g: ModuleGraph) = nav(g)
proc navDefusages*(g: ModuleGraph) = nav(g)
proc writeRodFiles*(g: ModuleGraph) =
for i in 0..high(g.packed):
for i in 0..<len(g.packed):
case g.packed[i].status
of undefined, loading, stored, loaded:
discard "nothing to do"

View File

@@ -12,10 +12,12 @@
## use this representation directly in all the transformations,
## it is superior.
import hashes, tables, strtabs
import bitabs
import std/[hashes, tables, strtabs]
import bitabs, rodfiles
import ".." / [ast, options]
import ".." / nir / nirlineinfos
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -31,17 +33,12 @@ type
item*: int32 # same as the in-memory representation
const
nilItemId* = PackedItemId(module: LitId(0), item: -1.int32)
nilItemId* = PackedItemId(module: LitId(0), item: 0.int32)
const
emptyNodeId* = NodeId(-1)
type
PackedLineInfo* = object
line*: uint16
col*: int16
file*: LitId
PackedLib* = object
kind*: TLibKind
generated*: bool
@@ -71,6 +68,7 @@ type
when hasFFI:
cname*: LitId
constraint*: NodeId
instantiatedFrom*: PackedItemId
PackedType* = object
kind*: TTypeKind
@@ -89,23 +87,35 @@ type
typeInst*: PackedItemId
nonUniqueId*: int32
PackedNode* = object # 28 bytes
kind*: TNodeKind
flags*: TNodeFlags
operand*: int32 # for kind in {nkSym, nkSymDef}: SymId
# for kind in {nkStrLit, nkIdent, nkNumberLit}: LitId
# for kind in nkInt32Lit: direct value
# for non-atom kinds: the number of nodes (for easy skipping)
typeId*: PackedItemId
PackedNode* = object # 8 bytes
x: uint32
info*: PackedLineInfo
PackedTree* = object ## usually represents a full Nim module
nodes*: seq[PackedNode]
nodes: seq[PackedNode]
withFlags: seq[(int32, TNodeFlags)]
withTypes: seq[(int32, PackedItemId)]
PackedInstantiation* = object
key*, sym*: PackedItemId
concreteTypes*: seq[PackedItemId]
const
NodeKindBits = 8'u32
NodeKindMask = (1'u32 shl NodeKindBits) - 1'u32
template kind*(n: PackedNode): TNodeKind = TNodeKind(n.x and NodeKindMask)
template uoperand*(n: PackedNode): uint32 = (n.x shr NodeKindBits)
template soperand*(n: PackedNode): int32 = int32(uoperand(n))
template toX(k: TNodeKind; operand: uint32): uint32 =
uint32(k) or (operand shl NodeKindBits)
template toX(k: TNodeKind; operand: LitId): uint32 =
uint32(k) or (operand.uint32 shl NodeKindBits)
template typeId*(n: PackedNode): PackedItemId = n.typ
proc `==`*(a, b: SymId): bool {.borrow.}
proc hash*(a: SymId): Hash {.borrow.}
@@ -117,68 +127,32 @@ proc newTreeFrom*(old: PackedTree): PackedTree =
result.nodes = @[]
when false: result.sh = old.sh
when false:
proc declareSym*(tree: var PackedTree; kind: TSymKind;
name: LitId; info: PackedLineInfo): SymId =
result = SymId(tree.sh.syms.len)
tree.sh.syms.add PackedSym(kind: kind, name: name, flags: {}, magic: mNone, info: info)
proc litIdFromName*(tree: PackedTree; name: string): LitId =
result = tree.sh.strings.getOrIncl(name)
proc add*(tree: var PackedTree; kind: TNodeKind; token: string; info: PackedLineInfo) =
tree.nodes.add PackedNode(kind: kind, info: info,
operand: int32 getOrIncl(tree.sh.strings, token))
proc add*(tree: var PackedTree; kind: TNodeKind; info: PackedLineInfo) =
tree.nodes.add PackedNode(kind: kind, operand: 0, info: info)
proc throwAwayLastNode*(tree: var PackedTree) =
tree.nodes.setLen(tree.nodes.len-1)
proc addIdent*(tree: var PackedTree; s: LitId; info: PackedLineInfo) =
tree.nodes.add PackedNode(kind: nkIdent, operand: int32(s), info: info)
tree.nodes.add PackedNode(x: toX(nkIdent, uint32(s)), info: info)
proc addSym*(tree: var PackedTree; s: int32; info: PackedLineInfo) =
tree.nodes.add PackedNode(kind: nkSym, operand: s, info: info)
proc addModuleId*(tree: var PackedTree; s: ModuleId; info: PackedLineInfo) =
tree.nodes.add PackedNode(kind: nkInt32Lit, operand: int32(s), info: info)
tree.nodes.add PackedNode(x: toX(nkSym, cast[uint32](s)), info: info)
proc addSymDef*(tree: var PackedTree; s: SymId; info: PackedLineInfo) =
tree.nodes.add PackedNode(kind: nkSym, operand: int32(s), info: info)
tree.nodes.add PackedNode(x: toX(nkSym, cast[uint32](s)), info: info)
proc isAtom*(tree: PackedTree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= nkNilLit
proc copyTree*(dest: var PackedTree; tree: PackedTree; n: NodePos) =
# and this is why the IR is superior. We can copy subtrees
# via a linear scan.
let pos = n.int
let L = if isAtom(tree, pos): 1 else: tree.nodes[pos].operand
let d = dest.nodes.len
dest.nodes.setLen(d + L)
for i in 0..<L:
dest.nodes[d+i] = tree.nodes[pos+i]
when false:
proc copySym*(dest: var PackedTree; tree: PackedTree; s: SymId): SymId =
result = SymId(dest.sh.syms.len)
assert int(s) < tree.sh.syms.len
let oldSym = tree.sh.syms[s.int]
dest.sh.syms.add oldSym
type
PatchPos = distinct int
when false:
proc prepare*(tree: var PackedTree; kind: TNodeKind; info: PackedLineInfo): PatchPos =
result = PatchPos tree.nodes.len
tree.nodes.add PackedNode(kind: kind, operand: 0, info: info)
proc addNode*(t: var PackedTree; kind: TNodeKind; operand: int32;
typeId: PackedItemId = nilItemId; info: PackedLineInfo;
flags: TNodeFlags = {}) =
t.nodes.add PackedNode(x: toX(kind, cast[uint32](operand)), info: info)
if flags != {}:
t.withFlags.add (t.nodes.len.int32 - 1, flags)
if typeId != nilItemId:
t.withTypes.add (t.nodes.len.int32 - 1, typeId)
proc prepare*(tree: var PackedTree; kind: TNodeKind; flags: TNodeFlags; typeId: PackedItemId; info: PackedLineInfo): PatchPos =
result = PatchPos tree.nodes.len
tree.nodes.add PackedNode(kind: kind, flags: flags, operand: 0, info: info,
typeId: typeId)
tree.addNode(kind = kind, flags = flags, operand = 0, info = info, typeId = typeId)
proc prepare*(dest: var PackedTree; source: PackedTree; sourcePos: NodePos): PatchPos =
result = PatchPos dest.nodes.len
@@ -186,26 +160,30 @@ proc prepare*(dest: var PackedTree; source: PackedTree; sourcePos: NodePos): Pat
proc patch*(tree: var PackedTree; pos: PatchPos) =
let pos = pos.int
assert tree.nodes[pos].kind > nkNilLit
let k = tree.nodes[pos].kind
assert k > nkNilLit
let distance = int32(tree.nodes.len - pos)
tree.nodes[pos].operand = distance
assert distance > 0
tree.nodes[pos].x = toX(k, cast[uint32](distance))
proc len*(tree: PackedTree): int {.inline.} = tree.nodes.len
proc `[]`*(tree: PackedTree; i: int): lent PackedNode {.inline.} =
tree.nodes[i]
proc `[]`*(tree: PackedTree; i: NodePos): lent PackedNode {.inline.} =
tree.nodes[i.int]
template rawSpan(n: PackedNode): int = int(uoperand(n))
proc nextChild(tree: PackedTree; pos: var int) {.inline.} =
if tree.nodes[pos].kind > nkNilLit:
assert tree.nodes[pos].operand > 0
inc pos, tree.nodes[pos].operand
assert tree.nodes[pos].uoperand > 0
inc pos, tree.nodes[pos].rawSpan
else:
inc pos
iterator sonsReadonly*(tree: PackedTree; n: NodePos): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > nkNilLit
let last = pos + tree.nodes[pos].operand
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last:
yield NodePos pos
@@ -226,7 +204,7 @@ iterator isons*(dest: var PackedTree; tree: PackedTree;
iterator sonsFrom1*(tree: PackedTree; n: NodePos): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > nkNilLit
let last = pos + tree.nodes[pos].operand
let last = pos + tree.nodes[pos].rawSpan
inc pos
if pos < last:
nextChild tree, pos
@@ -240,7 +218,7 @@ iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos =
inc count
var pos = n.int
assert tree.nodes[pos].kind > nkNilLit
let last = pos + tree.nodes[pos].operand
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last and count > 2:
yield NodePos pos
@@ -250,7 +228,7 @@ iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos =
proc parentImpl(tree: PackedTree; n: NodePos): NodePos =
# finding the parent of a node is rather easy:
var pos = n.int - 1
while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].operand - 1 < n.int)):
while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].rawSpan - 1 < n.int)):
dec pos
#assert pos >= 0, "node has no parent"
result = NodePos(pos)
@@ -276,20 +254,32 @@ proc firstSon*(tree: PackedTree; n: NodePos): NodePos {.inline.} =
proc kind*(tree: PackedTree; n: NodePos): TNodeKind {.inline.} =
tree.nodes[n.int].kind
proc litId*(tree: PackedTree; n: NodePos): LitId {.inline.} =
LitId tree.nodes[n.int].operand
LitId tree.nodes[n.int].uoperand
proc info*(tree: PackedTree; n: NodePos): PackedLineInfo {.inline.} =
tree.nodes[n.int].info
template typ*(n: NodePos): PackedItemId =
tree.nodes[n.int].typeId
template flags*(n: NodePos): TNodeFlags =
tree.nodes[n.int].flags
proc findType*(tree: PackedTree; n: NodePos): PackedItemId =
for x in tree.withTypes:
if x[0] == int32(n): return x[1]
if x[0] > int32(n): return nilItemId
return nilItemId
template operand*(n: NodePos): int32 =
tree.nodes[n.int].operand
proc findFlags*(tree: PackedTree; n: NodePos): TNodeFlags =
for x in tree.withFlags:
if x[0] == int32(n): return x[1]
if x[0] > int32(n): return {}
return {}
template typ*(n: NodePos): PackedItemId =
tree.findType(n)
template flags*(n: NodePos): TNodeFlags =
tree.findFlags(n)
template uoperand*(n: NodePos): uint32 =
tree.nodes[n.int].uoperand
proc span*(tree: PackedTree; pos: int): int {.inline.} =
if isAtom(tree, pos): 1 else: tree.nodes[pos].operand
if isAtom(tree, pos): 1 else: tree.nodes[pos].rawSpan
proc sons2*(tree: PackedTree; n: NodePos): (NodePos, NodePos) =
assert(not isAtom(tree, n.int))
@@ -305,6 +295,7 @@ proc sons3*(tree: PackedTree; n: NodePos): (NodePos, NodePos, NodePos) =
result = (NodePos a, NodePos b, NodePos c)
proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos =
result = default(NodePos)
if tree.nodes[n.int].kind > nkNilLit:
var count = 0
for child in sonsReadonly(tree, n):
@@ -318,64 +309,28 @@ when false:
template kind*(n: NodePos): TNodeKind = tree.nodes[n.int].kind
template info*(n: NodePos): PackedLineInfo = tree.nodes[n.int].info
template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].operand
template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].uoperand
template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].operand
template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].soperand
proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1)
when false:
# xxx `nkStrLit` or `nkStrLit..nkTripleStrLit:` below?
proc strLit*(tree: PackedTree; n: NodePos): lent string =
assert n.kind == nkStrLit
result = tree.sh.strings[LitId tree.nodes[n.int].operand]
proc strVal*(tree: PackedTree; n: NodePos): string =
assert n.kind == nkStrLit
result = tree.sh.strings[LitId tree.nodes[n.int].operand]
#result = cookedStrLit(raw)
proc filenameVal*(tree: PackedTree; n: NodePos): string =
case n.kind
of nkStrLit:
result = strVal(tree, n)
of nkIdent:
result = tree.sh.strings[n.litId]
of nkSym:
result = tree.sh.strings[tree.sh.syms[int n.symId].name]
else:
result = ""
proc identAsStr*(tree: PackedTree; n: NodePos): lent string =
assert n.kind == nkIdent
result = tree.sh.strings[LitId tree.nodes[n.int].operand]
const
externIntLit* = {nkCharLit,
nkIntLit,
nkInt8Lit,
nkInt16Lit,
nkInt32Lit,
nkInt64Lit,
nkUIntLit,
nkUInt8Lit,
nkUInt16Lit,
nkUInt32Lit,
nkUInt64Lit} # nkInt32Lit is missing by design!
nkUInt64Lit}
externSIntLit* = {nkIntLit, nkInt8Lit, nkInt16Lit, nkInt64Lit}
externSIntLit* = {nkIntLit, nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit}
externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit}
directIntLit* = nkInt32Lit
when false:
proc identIdImpl(tree: PackedTree; n: NodePos): LitId =
if n.kind == nkIdent:
result = n.litId
elif n.kind == nkSym:
result = tree.sh.syms[int n.symId].name
else:
result = LitId(0)
template identId*(n: NodePos): LitId = identIdImpl(tree, n)
directIntLit* = nkNone
template copyInto*(dest, n, body) =
let patchPos = prepare(dest, tree, n)
@@ -387,28 +342,8 @@ template copyIntoKind*(dest, kind, info, body) =
body
patch dest, patchPos
when false:
proc hasPragma*(tree: PackedTree; n: NodePos; pragma: string): bool =
let litId = tree.sh.strings.getKeyId(pragma)
if litId == LitId(0):
return false
assert n.kind == nkPragma
for ch0 in sonsReadonly(tree, n):
if ch0.kind == nkExprColonExpr:
if ch0.firstSon.identId == litId:
return true
elif ch0.identId == litId:
return true
proc getNodeId*(tree: PackedTree): NodeId {.inline.} = NodeId tree.nodes.len
when false:
proc produceError*(dest: var PackedTree; tree: PackedTree; n: NodePos; msg: string) =
let patchPos = prepare(dest, nkError, n.info)
dest.add nkStrLit, msg, n.info
copyTree(dest, tree, n)
patch dest, patchPos
iterator allNodes*(tree: PackedTree): NodePos =
var p = 0
while p < tree.len:
@@ -418,3 +353,13 @@ iterator allNodes*(tree: PackedTree): NodePos =
proc toPackedItemId*(item: int32): PackedItemId {.inline.} =
PackedItemId(module: LitId(0), item: item)
proc load*(f: var RodFile; t: var PackedTree) =
loadSeq f, t.nodes
loadSeq f, t.withFlags
loadSeq f, t.withTypes
proc store*(f: var RodFile; t: PackedTree) =
storeSeq f, t.nodes
storeSeq f, t.withFlags
storeSeq f, t.withTypes

View File

@@ -14,7 +14,7 @@
import ".." / [ast, modulegraphs, trees, extccomp, btrees,
msgs, lineinfos, pathutils, options, cgmeth]
import tables
import std/tables
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -103,6 +103,17 @@ proc replayBackendProcs*(g: ModuleGraph; module: int) =
let symId = FullId(module: tmp.module, packed: it[1])
g.enumToStringProcs[key] = LazySym(id: symId, sym: nil)
for it in mitems(g.packed[module].fromDisk.methodsPerType):
let key = translateId(it[0], g.packed, module, g.config)
let tmp = translateId(it[1], g.packed, module, g.config)
let symId = FullId(module: tmp.module, packed: it[1])
g.methodsPerType.mgetOrPut(key, @[]).add LazySym(id: symId, sym: nil)
for it in mitems(g.packed[module].fromDisk.dispatchers):
let tmp = translateId(it, g.packed, module, g.config)
let symId = FullId(module: tmp.module, packed: it)
g.dispatchers.add LazySym(id: symId, sym: nil)
proc replayGenericCacheInformation*(g: ModuleGraph; module: int) =
## We remember the generic instantiations a module performed
## in order to to avoid the code bloat that generic code tends
@@ -127,12 +138,12 @@ proc replayGenericCacheInformation*(g: ModuleGraph; module: int) =
module: module, sym: FullId(module: sym.module, packed: it.sym),
concreteTypes: concreteTypes, inst: nil)
for it in mitems(g.packed[module].fromDisk.methodsPerType):
for it in mitems(g.packed[module].fromDisk.methodsPerGenericType):
let key = translateId(it[0], g.packed, module, g.config)
let col = it[1]
let tmp = translateId(it[2], g.packed, module, g.config)
let symId = FullId(module: tmp.module, packed: it[2])
g.methodsPerType.mgetOrPut(key, @[]).add (col, LazySym(id: symId, sym: nil))
g.methodsPerGenericType.mgetOrPut(key, @[]).add (col, LazySym(id: symId, sym: nil))
replayBackendProcs(g, module)

View File

@@ -14,7 +14,7 @@
## compiler works and less a storage format, you're probably looking for
## the `ic` or `packed_ast` modules to understand the logical format.
from typetraits import supportsCopyMem
from std/typetraits import supportsCopyMem
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
@@ -92,11 +92,16 @@ type
typeInstCacheSection
procInstCacheSection
attachedOpsSection
methodsPerTypeSection
methodsPerGenericTypeSection
enumToStringProcsSection
methodsPerTypeSection
dispatchersSection
typeInfoSection # required by the backend
backendFlagsSection
aliveSymsSection # beware, this is stored in a `.alivesyms` file.
sideChannelSection
namespaceSection
symnamesSection
RodFileError* = enum
ok, tooBig, cannotOpen, ioFailure, wrongHeader, wrongSection, configMismatch,
@@ -109,8 +114,8 @@ type
# better than exceptions.
const
RodVersion = 1
cookie = [byte(0), byte('R'), byte('O'), byte('D'),
RodVersion = 2
defaultCookie = [byte(0), byte('R'), byte('O'), byte('D'),
byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(RodVersion)]
proc setError(f: var RodFile; err: RodFileError) {.inline.} =
@@ -206,16 +211,16 @@ proc loadSeq*[T](f: var RodFile; s: var seq[T]) =
for i in 0..<lenPrefix:
loadPrim(f, s[i])
proc storeHeader*(f: var RodFile) =
proc storeHeader*(f: var RodFile; cookie = defaultCookie) =
## stores the header which is described by `cookie`.
if f.err != ok: return
if f.f.writeBytes(cookie, 0, cookie.len) != cookie.len:
setError f, ioFailure
proc loadHeader*(f: var RodFile) =
proc loadHeader*(f: var RodFile; cookie = defaultCookie) =
## Loads the header which is described by `cookie`.
if f.err != ok: return
var thisCookie: array[cookie.len, byte]
var thisCookie: array[cookie.len, byte] = default(array[cookie.len, byte])
if f.f.readBytes(thisCookie, 0, thisCookie.len) != thisCookie.len:
setError f, ioFailure
elif thisCookie != cookie:
@@ -231,13 +236,14 @@ proc storeSection*(f: var RodFile; s: RodSection) =
proc loadSection*(f: var RodFile; expected: RodSection) =
## read the bytes value of s, sets and error if the section is incorrect.
if f.err != ok: return
var s: RodSection
var s: RodSection = default(RodSection)
loadPrim(f, s)
if expected != s and f.err == ok:
setError f, wrongSection
proc create*(filename: string): RodFile =
## create the file and open it for writing
result = default(RodFile)
if not open(result.f, filename, fmWrite):
setError result, cannotOpen
@@ -245,5 +251,6 @@ proc close*(f: var RodFile) = close(f.f)
proc open*(filename: string): RodFile =
## open the file for reading
result = default(RodFile)
if not open(result.f, filename, fmRead):
setError result, cannotOpen

View File

@@ -11,8 +11,8 @@
# An identifier is a shared immutable string that can be compared by its
# id. This module is essential for the compiler's performance.
import
hashes, wordrecg
import wordrecg
import std/hashes
when defined(nimPreviewSlimSystem):
import std/assertions

View File

@@ -10,10 +10,12 @@
## This module implements the symbol importing mechanism.
import
intsets, ast, astalgo, msgs, options, idents, lookups,
semdata, modulepaths, sigmatch, lineinfos, sets,
modulegraphs, wordrecg, tables
from strutils import `%`
ast, astalgo, msgs, options, idents, lookups,
semdata, modulepaths, sigmatch, lineinfos,
modulegraphs, wordrecg
from std/strutils import `%`, startsWith
from std/sequtils import addUnique
import std/[sets, tables, intsets]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -113,6 +115,7 @@ proc rawImportSymbol(c: PContext, s, origin: PSym; importSet: var IntSet) =
proc splitPragmas(c: PContext, n: PNode): (PNode, seq[TSpecialWord]) =
template bail = globalError(c.config, n.info, "invalid pragma")
result = (nil, @[])
if n.kind == nkPragmaExpr:
if n.len == 2 and n[1].kind == nkPragma:
result[0] = n[0]
@@ -228,11 +231,6 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; im
for i in 0..n.safeLen-1:
importForwarded(c, n[i], exceptSet, fromMod, importSet)
proc addUnique[T](x: var seq[T], y: sink T) {.noSideEffect.} =
for i in 0..high(x):
if x[i] == y: return
x.add y
proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym =
result = realModule
template createModuleAliasImpl(ident): untyped =
@@ -304,11 +302,18 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
var prefix = ""
if realModule.constraint != nil: prefix = realModule.constraint.strVal & "; "
message(c.config, n.info, warnDeprecated, prefix & realModule.name.s & " is deprecated")
let moduleName = getModuleName(c.config, n)
if belongsToStdlib(c.graph, result) and not startsWith(moduleName, stdPrefix) and
not startsWith(moduleName, "system/") and not startsWith(moduleName, "packages/"):
message(c.config, n.info, warnStdPrefix, realModule.name.s)
suggestSym(c.graph, n.info, result, c.graph.usageSym, false)
importStmtResult.add newSymNode(result, n.info)
#newStrNode(toFullPath(c.config, f), n.info)
else:
result = nil
proc afterImport(c: PContext, m: PSym) =
if isCachedModule(c.graph, m): return
# fixes bug #17510, for re-exported symbols
let realModuleId = c.importModuleMap[m.id]
for s in allSyms(c.graph, m):
@@ -344,11 +349,9 @@ proc evalImport*(c: PContext, n: PNode): PNode =
imp[lastPos] = x[1]
impAs[1] = imp
impAs[2] = x[2]
impAs.info = x[2].info
impMod(c, impAs, result)
else:
imp[lastPos] = x
imp.info = x.info
impMod(c, imp, result)
else:
impMod(c, it, result)

View File

@@ -14,11 +14,13 @@
## See doc/destructors.rst for a spec of the implemented rewrite rules
import
intsets, strtabs, ast, astalgo, msgs, renderer, magicsys, types, idents,
strutils, options, lowerings, tables, modulegraphs,
ast, astalgo, msgs, renderer, magicsys, types, idents,
options, lowerings, modulegraphs,
lineinfos, parampatterns, sighashes, liftdestructors, optimizer,
varpartitions, aliasanalysis, dfa, wordrecg
import std/[strtabs, tables, strutils, intsets]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -79,11 +81,11 @@ proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
proc nestedScope(parent: var Scope; body: PNode): Scope =
Scope(vars: @[], locals: @[], wasMoved: @[], final: @[], body: body, needsTry: false, parent: addr(parent))
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode
type
MoveOrCopyFlag = enum
IsDecl, IsExplicitSink
IsDecl, IsExplicitSink, IsReturn
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; flags: set[MoveOrCopyFlag] = {}): PNode
@@ -209,10 +211,12 @@ proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFr
m.add " a 'sink' parameter"
m.add "; routine: "
m.add c.owner.name.s
#m.add "\n\n"
#m.add renderTree(c.body, {renderIds})
localError(c.graph.config, ri.info, errGenerated, m)
proc makePtrType(c: var Con, baseType: PType): PType =
result = newType(tyPtr, nextTypeId c.idgen, c.owner)
result = newType(tyPtr, c.idgen, c.owner)
addSonSkipIntLit(result, baseType, c.idgen)
proc genOp(c: var Con; op: PSym; dest: PNode): PNode =
@@ -272,7 +276,7 @@ proc deepAliases(dest, ri: PNode): bool =
proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
if (c.inLoopCond == 0 and (isUnpackedTuple(dest) or IsDecl in flags or
(isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)))) or
isNoInit(dest):
isNoInit(dest) or IsReturn in flags:
# optimize sink call into a bitwise memcopy
result = newTree(nkFastAsgn, dest, ri)
else:
@@ -434,6 +438,7 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
proc isCapturedVar(n: PNode): bool =
let root = getRoot(n)
if root != nil: result = root.name.s[0] == ':'
else: result = false
proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
@@ -735,7 +740,9 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false,
result[^1] = maybeVoid(n[^1], s)
dec c.inUncheckedAssignSection, inUncheckedAssignSection
else: assert(false)
else:
result = nil
assert(false)
proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty:
@@ -762,7 +769,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
result.add copyNode(n[0])
s.needsTry = true
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode =
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode =
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt,
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}:
template process(child, s): untyped = p(child, c, s, mode)
@@ -948,7 +955,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
cycleCheck(n, c)
assert n[1].kind notin {nkAsgn, nkFastAsgn, nkSinkAsgn}
let flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
var flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
if inReturn:
flags.incl(IsReturn)
result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s, flags)
elif isDiscriminantField(n[0]):
result = c.genDiscriminantAsgn(s, n)
@@ -1032,7 +1041,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
of nkReturnStmt:
result = shallowCopy(n)
for i in 0..<n.len:
result[i] = p(n[i], c, s, mode)
result[i] = p(n[i], c, s, mode, inReturn=true)
s.needsTry = true
of nkCast:
result = shallowCopy(n)
@@ -1046,6 +1055,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
of nkGotoState, nkState, nkAsmStmt:
result = n
else:
result = nil
internalError(c.graph.config, n.info, "cannot inject destructors to node kind: " & $n.kind)
proc sameLocation*(a, b: PNode): bool =
@@ -1157,7 +1167,8 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
let snk = c.genSink(s, dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri):
isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri) and
not ({sfGlobal, sfPure} <= ri.sym.flags):
# Rule 3: `=sink`(x, z); wasMoved(z)
let snk = c.genSink(s, dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))

View File

@@ -71,6 +71,7 @@ Files: "testament"
Files: "nimsuggest"
Files: "nimsuggest/tests/*.nim"
Files: "changelogs/*.md"
Files: "ci/funs.sh"
[Lib]
Files: "lib"

View File

@@ -3,7 +3,7 @@
## hold all from `low(BiggestInt)` to `high(BiggestUInt)`, This
## type is for that purpose.
from math import trunc
from std/math import trunc
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -171,6 +171,7 @@ proc addToHex*(result: var string; arg: Int128) =
i -= 1
proc toHex*(arg: Int128): string =
result = ""
result.addToHex(arg)
proc inc*(a: var Int128, y: uint32 = 1) =
@@ -330,8 +331,8 @@ proc `*`*(a: Int128, b: int32): Int128 =
if b < 0:
result = -result
proc `*=`*(a: var Int128, b: int32): Int128 =
result = result * b
proc `*=`(a: var Int128, b: int32) =
a = a * b
proc makeInt128(high, low: uint64): Int128 =
result.udata[0] = cast[uint32](low)
@@ -357,9 +358,10 @@ proc `*`*(lhs, rhs: Int128): Int128 =
proc `*=`*(a: var Int128, b: Int128) =
a = a * b
import bitops
import std/bitops
proc fastLog2*(a: Int128): int =
result = 0
if a.udata[3] != 0:
return 96 + fastLog2(a.udata[3])
if a.udata[2] != 0:
@@ -571,4 +573,4 @@ proc maskBytes*(arg: Int128, numbytes: int): Int128 {.noinit.} =
of 8:
return maskUInt64(arg)
else:
assert(false, "masking only implemented for 1, 2, 4 and 8 bytes")
raiseAssert "masking only implemented for 1, 2, 4 and 8 bytes"

View File

@@ -11,7 +11,9 @@
## https://github.com/nim-lang/RFCs/issues/244 for more details.
import
ast, types, renderer, intsets
ast, types, renderer
import std/intsets
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -21,6 +23,7 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool
proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
case n.kind
of nkRecList:
result = false
for i in 0..<n.len:
result = canAliasN(arg, n[i], marker)
if result: return
@@ -36,7 +39,7 @@ proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
else: discard
of nkSym:
result = canAlias(arg, n.sym.typ, marker)
else: discard
else: result = false
proc canAlias(arg, ret: PType; marker: var IntSet): bool =
if containsOrIncl(marker, ret.id):
@@ -56,6 +59,7 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool =
else:
result = true
of tyTuple:
result = false
for i in 0..<ret.len:
result = canAlias(arg, ret[i], marker)
if result: break
@@ -184,10 +188,12 @@ proc checkIsolate*(n: PNode): bool =
return false
result = true
of nkIfStmt, nkIfExpr:
result = false
for it in n:
result = checkIsolate(it.lastSon)
if not result: break
of nkCaseStmt:
result = false
for i in 1..<n.len:
result = checkIsolate(n[i].lastSon)
if not result: break
@@ -197,6 +203,7 @@ proc checkIsolate*(n: PNode): bool =
result = checkIsolate(n[i].lastSon)
if not result: break
of nkBracket, nkTupleConstr, nkPar:
result = false
for it in n:
result = checkIsolate(it)
if not result: break

View File

@@ -32,17 +32,18 @@ import
ast, trees, magicsys, options,
nversion, msgs, idents, types,
ropes, ccgutils, wordrecg, renderer,
cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
cgmeth, lowerings, sighashes, modulegraphs, lineinfos,
transf, injectdestructors, sourcemap, astmsgs, backendpragmas
import pipelineutils
import json, sets, math, tables, intsets
import strutils except addf
import std/[json, sets, math, tables, intsets]
import std/strutils except addf
when defined(nimPreviewSlimSystem):
import std/[assertions, syncio]
import std/formatfloat
type
TJSGen = object of PPassContext
@@ -50,6 +51,7 @@ type
graph: ModuleGraph
config: ConfigRef
sigConflicts: CountTable[SigHash]
initProc: PProc
BModule = ref TJSGen
TJSTypeKind = enum # necessary JS "types"
@@ -136,17 +138,15 @@ template nested(p, body) =
dec p.extraIndent
proc newGlobals(): PGlobals =
new(result)
result.forwarded = @[]
result.generatedSyms = initIntSet()
result.typeInfoGenerated = initIntSet()
result = PGlobals(forwarded: @[],
generatedSyms: initIntSet(),
typeInfoGenerated: initIntSet()
)
proc initCompRes(r: var TCompRes) =
r.address = ""
r.res = ""
r.tmpLoc = ""
r.typ = etyNone
r.kind = resNone
proc initCompRes(): TCompRes =
result = TCompRes(address: "", res: "",
tmpLoc: "", typ: etyNone, kind: resNone
)
proc rdLoc(a: TCompRes): Rope {.inline.} =
if a.typ != etyBaseIndex:
@@ -158,6 +158,8 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
options: TOptions): PProc =
result = PProc(
blocks: @[],
optionsStack: if module.initProc != nil: module.initProc.optionsStack
else: @[],
options: options,
module: module,
procDef: procDef,
@@ -216,7 +218,8 @@ proc mapType(typ: PType): TJSTypeKind =
else: result = etyNone
of tyProc: result = etyProc
of tyCstring: result = etyString
of tyConcept, tyIterable: doAssert false
of tyConcept, tyIterable:
raiseAssert "unreachable"
proc mapType(p: PProc; typ: PType): TJSTypeKind =
result = mapType(typ)
@@ -345,8 +348,7 @@ proc isSimpleExpr(p: PProc; n: PNode): bool =
if n[i].kind notin {nkCommentStmt, nkEmpty}: return false
result = isSimpleExpr(p, n.lastSon)
else:
if n.isAtom:
result = true
result = n.isAtom
proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
inc(p.unique)
@@ -356,7 +358,7 @@ proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
assert r.kind == resNone
var x, y: TCompRes
var x, y: TCompRes = default(TCompRes)
if p.isSimpleExpr(a) and p.isSimpleExpr(b):
gen(p, a, x)
gen(p, b, y)
@@ -383,7 +385,7 @@ proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
assert r.kind == resNone
var x, y: TCompRes
var x, y: TCompRes = default(TCompRes)
if p.isSimpleExpr(a) and p.isSimpleExpr(b):
gen(p, a, x)
gen(p, b, y)
@@ -471,6 +473,7 @@ const # magic checked op; magic unchecked op;
proc needsTemp(p: PProc; n: PNode): bool =
# check if n contains a call to determine
# if a temp should be made to prevent multiple evals
result = false
if n.kind in nkCallKinds + {nkTupleConstr, nkObjConstr, nkBracket, nkCurly}:
return true
for c in n:
@@ -506,8 +509,8 @@ proc maybeMakeTempAssignable(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rop
elif x.tmpLoc != "" and n.kind == nkBracketExpr:
# genArrayAddr
var
address, index: TCompRes
first: Int128
address, index: TCompRes = default(TCompRes)
first: Int128 = Zero
gen(p, n[0], address)
gen(p, n[1], index)
let (m1, tmp1) = maybeMakeTemp(p, n[0], address)
@@ -539,7 +542,7 @@ template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string,
# $1 and $2 in the `frmt` string bind to lhs and rhs of the expr,
# if $3 or $4 are present they will be substituted with temps for
# lhs and rhs respectively
var x, y: TCompRes
var x, y: TCompRes = default(TCompRes)
useMagic(p, magic)
gen(p, n[1], x)
gen(p, n[2], y)
@@ -569,7 +572,7 @@ proc signedTrimmer(size: BiggestInt): string =
proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
reassign: static[bool] = false) =
var x, y: TCompRes
var x, y: TCompRes = default(TCompRes)
gen(p, n[1], x)
gen(p, n[2], y)
let size = n[1].typ.skipTypes(abstractRange).size
@@ -608,8 +611,8 @@ template unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
var
x, y: TCompRes
xLoc, yLoc: Rope
x, y: TCompRes = default(TCompRes)
xLoc, yLoc: Rope = ""
let i = ord(optOverflowCheck notin p.options)
useMagic(p, jsMagics[op][i])
if n.len > 2:
@@ -673,8 +676,38 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
applyFormat("modInt64($1, $2)", "$1 % $2")
else:
applyFormat("modInt($1, $2)", "Math.trunc($1 % $2)")
of mSucc: applyFormat("addInt($1, $2)", "($1 + $2)")
of mPred: applyFormat("subInt($1, $2)", "($1 - $2)")
of mSucc:
let typ = n[1].typ.skipTypes(abstractVarRange)
case typ.kind
of tyUInt..tyUInt32:
binaryUintExpr(p, n, r, "+")
of tyUInt64:
if optJsBigInt64 in p.config.globalOptions:
applyFormat("BigInt.asUintN(64, $1 + BigInt($2))")
else: binaryUintExpr(p, n, r, "+")
elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
if optOverflowCheck notin p.options:
applyFormat("BigInt.asIntN(64, $1 + BigInt($2))")
else: binaryExpr(p, n, r, "addInt64", "addInt64($1, BigInt($2))")
else:
if optOverflowCheck notin p.options: applyFormat("$1 + $2")
else: binaryExpr(p, n, r, "addInt", "addInt($1, $2)")
of mPred:
let typ = n[1].typ.skipTypes(abstractVarRange)
case typ.kind
of tyUInt..tyUInt32:
binaryUintExpr(p, n, r, "-")
of tyUInt64:
if optJsBigInt64 in p.config.globalOptions:
applyFormat("BigInt.asUintN(64, $1 - BigInt($2))")
else: binaryUintExpr(p, n, r, "-")
elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
if optOverflowCheck notin p.options:
applyFormat("BigInt.asIntN(64, $1 - BigInt($2))")
else: binaryExpr(p, n, r, "subInt64", "subInt64($1, BigInt($2))")
else:
if optOverflowCheck notin p.options: applyFormat("$1 - $2")
else: binaryExpr(p, n, r, "subInt", "subInt($1, $2)")
of mAddF64: applyFormat("($1 + $2)", "($1 + $2)")
of mSubF64: applyFormat("($1 - $2)", "($1 - $2)")
of mMulF64: applyFormat("($1 * $2)", "($1 * $2)")
@@ -800,7 +833,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
if mapType(n[1].typ) != etyBaseIndex:
arithAux(p, n, r, op)
else:
var x, y: TCompRes
var x, y: TCompRes = default(TCompRes)
gen(p, n[1], x)
gen(p, n[2], y)
r.res = "($# == $# && $# == $#)" % [x.address, y.address, x.res, y.res]
@@ -833,7 +866,7 @@ proc genLineDir(p: PProc, n: PNode) =
p.previousFileName = currentFileName
proc genWhileStmt(p: PProc, n: PNode) =
var cond: TCompRes
var cond: TCompRes = default(TCompRes)
internalAssert p.config, isEmptyType(n.typ)
genLineDir(p, n)
inc(p.unique)
@@ -928,6 +961,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
elif it.kind == nkType:
throwObj = it
else:
throwObj = nil
internalError(p.config, n.info, "genTryStmt")
if orExpr != "": orExpr.add("||")
@@ -968,7 +1002,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
proc genRaiseStmt(p: PProc, n: PNode) =
if n[0].kind != nkEmpty:
var a: TCompRes
var a: TCompRes = default(TCompRes)
gen(p, n[0], a)
let typ = skipTypes(n[0].typ, abstractPtrs)
genLineDir(p, n)
@@ -982,7 +1016,7 @@ proc genRaiseStmt(p: PProc, n: PNode) =
proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
var
a, b, cond, stmt: TCompRes
a, b, cond, stmt: TCompRes = default(TCompRes)
genLineDir(p, n)
gen(p, n[0], cond)
let typeKind = skipTypes(n[0].typ, abstractVar).kind
@@ -1116,7 +1150,7 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
if false:
discard
else:
var r: TCompRes
var r = default(TCompRes)
gen(p, it, r)
if it.typ.kind == tyPointer:
@@ -1132,13 +1166,13 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
p.body.add(r.rdLoc)
else:
var r: TCompRes
var r: TCompRes = default(TCompRes)
gen(p, it, r)
p.body.add(r.rdLoc)
p.body.add "\L"
proc genIf(p: PProc, n: PNode, r: var TCompRes) =
var cond, stmt: TCompRes
var cond, stmt: TCompRes = default(TCompRes)
var toClose = 0
if not isEmptyType(n.typ):
r.kind = resVal
@@ -1175,6 +1209,7 @@ proc generateHeader(p: PProc, typ: PType): Rope =
result.add("_Idx")
proc countJsParams(typ: PType): int =
result = 0
for i in 1..<typ.n.len:
assert(typ.n[i].kind == nkSym)
var param = typ.n[i].sym
@@ -1198,7 +1233,7 @@ proc needsNoCopy(p: PProc; y: PNode): bool =
{tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned} + IntegralTypes))
proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
var a, b: TCompRes
var a, b: TCompRes = default(TCompRes)
var xtyp = mapType(p, x.typ)
# disable `[]=` for cstring
@@ -1277,7 +1312,7 @@ proc genFastAsgn(p: PProc, n: PNode) =
genAsgnAux(p, n[0], n[1], noCopyNeeded=noCopy)
proc genSwap(p: PProc, n: PNode) =
var a, b: TCompRes
var a, b: TCompRes = default(TCompRes)
gen(p, n[1], a)
gen(p, n[2], b)
var tmp = p.getTemp(false)
@@ -1295,10 +1330,12 @@ proc getFieldPosition(p: PProc; f: PNode): int =
case f.kind
of nkIntLit..nkUInt64Lit: result = int(f.intVal)
of nkSym: result = f.sym.position
else: internalError(p.config, f.info, "genFieldPosition")
else:
result = 0
internalError(p.config, f.info, "genFieldPosition")
proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
var a: TCompRes = default(TCompRes)
r.typ = etyBaseIndex
let b = if n.kind == nkHiddenAddr: n[0] else: n
gen(p, b[0], a)
@@ -1362,10 +1399,10 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
internalAssert p.config, disc.kind == skField
if disc.loc.r == "": disc.loc.r = mangleName(p.module, disc)
var setx: TCompRes
var setx: TCompRes = default(TCompRes)
gen(p, checkExpr[1], setx)
var obj: TCompRes
var obj: TCompRes = default(TCompRes)
gen(p, accessExpr[0], obj)
# Avoid evaluating the LHS twice (one to read the discriminant and one to read
# the field)
@@ -1391,8 +1428,8 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
var
a, b: TCompRes
first: Int128
a, b: TCompRes = default(TCompRes)
first: Int128 = Zero
r.typ = etyBaseIndex
let m = if n.kind == nkHiddenAddr: n[0] else: n
gen(p, m[0], a)
@@ -1639,7 +1676,7 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
if t == etyObject or it.typ.kind == tyLent:
gen(p, it, r)
else:
var a: TCompRes
var a: TCompRes = default(TCompRes)
gen(p, it, a)
r.kind = a.kind
r.typ = mapType(p, n.typ)
@@ -1656,7 +1693,7 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
internalError(p.config, n.info, "genDeref")
proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
var a: TCompRes = default(TCompRes)
gen(p, n, a)
if a.typ == etyBaseIndex:
r.res.add(a.address)
@@ -1666,7 +1703,7 @@ proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) =
r.res.add(a.res)
proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes; emitted: ptr int = nil) =
var a: TCompRes
var a: TCompRes = default(TCompRes)
gen(p, n, a)
if skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs} and
a.typ == etyBaseIndex:
@@ -1790,7 +1827,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
r.address = ""
r.typ = etyNone
r.res.add(".")
var op: TCompRes
var op: TCompRes = default(TCompRes)
gen(p, n[0], op)
r.res.add(op.res)
genArgs(p, n, r, 2)
@@ -1938,7 +1975,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
result.add("}")
if indirect: result = "[$1]" % [result]
of tyObject:
var initList: Rope
var initList: Rope = ""
createObjInitList(p, t, initIntSet(), initList)
result = ("({$1})") % [initList]
if indirect: result = "[$1]" % [result]
@@ -1965,7 +2002,7 @@ template returnType: untyped = ""
proc genVarInit(p: PProc, v: PSym, n: PNode) =
var
a: TCompRes
a: TCompRes = default(TCompRes)
s: Rope
varCode: string
varName = mangleName(p.module, v)
@@ -2066,7 +2103,7 @@ proc genConstant(p: PProc, c: PSym) =
p.body = oldBody
proc genNew(p: PProc, n: PNode) =
var a: TCompRes
var a: TCompRes = default(TCompRes)
gen(p, n[1], a)
var t = skipTypes(n[1].typ, abstractVar)[0]
if mapType(t) == etyObject:
@@ -2077,7 +2114,7 @@ proc genNew(p: PProc, n: PNode) =
lineF(p, "$1 = [[$2], 0];$n", [a.rdLoc, createVar(p, t, false)])
proc genNewSeq(p: PProc, n: PNode) =
var x, y: TCompRes
var x, y: TCompRes = default(TCompRes)
gen(p, n[1], x)
gen(p, n[2], y)
let t = skipTypes(n[1].typ, abstractVar)[0]
@@ -2095,7 +2132,7 @@ proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
else: internalError(p.config, n.info, "genOrd")
proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
var a: TCompRes = default(TCompRes)
gen(p, n[1], a)
r.kind = resExpr
@@ -2120,7 +2157,7 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = "") =
useMagic(p, magic)
r.res.add(magic & "(")
var a: TCompRes
var a: TCompRes = default(TCompRes)
gen(p, n[1], a)
if magic == "reprAny":
@@ -2167,7 +2204,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
r.kind = resExpr
proc genOf(p: PProc, n: PNode, r: var TCompRes) =
var x: TCompRes
var x: TCompRes = default(TCompRes)
let t = skipTypes(n[2].typ,
abstractVarRange+{tyRef, tyPtr, tyLent, tyTypeDesc, tyOwned})
gen(p, n[1], x)
@@ -2183,7 +2220,7 @@ proc genDefault(p: PProc, n: PNode; r: var TCompRes) =
r.kind = resExpr
proc genReset(p: PProc, n: PNode) =
var x: TCompRes
var x: TCompRes = default(TCompRes)
useMagic(p, "genericReset")
gen(p, n[1], x)
if x.typ == etyBaseIndex:
@@ -2194,7 +2231,7 @@ proc genReset(p: PProc, n: PNode) =
genTypeInfo(p, n[1].typ), tmp])
proc genMove(p: PProc; n: PNode; r: var TCompRes) =
var a: TCompRes
var a: TCompRes = default(TCompRes)
r.kind = resVal
r.res = p.getTemp()
gen(p, n[1], a)
@@ -2203,14 +2240,14 @@ proc genMove(p: PProc; n: PNode; r: var TCompRes) =
#lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
proc genDup(p: PProc; n: PNode; r: var TCompRes) =
var a: TCompRes
var a: TCompRes = default(TCompRes)
r.kind = resVal
r.res = p.getTemp()
gen(p, n[1], a)
lineF(p, "$1 = $2;$n", [r.rdLoc, a.rdLoc])
proc genJSArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
var a: TCompRes = default(TCompRes)
r.res = rope("[")
r.kind = resExpr
for i in 0 ..< n.len:
@@ -2241,7 +2278,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
binaryExpr(p, n, r, "addChar",
"addChar($1, $2);")
of mAppendStrStr:
var lhs, rhs: TCompRes
var lhs, rhs: TCompRes = default(TCompRes)
gen(p, n[1], lhs)
gen(p, n[2], rhs)
@@ -2254,7 +2291,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
r.res = "$1.push.apply($3, $2);" % [a, rhs.rdLoc, tmp]
r.kind = resExpr
of mAppendSeqElem:
var x, y: TCompRes
var x, y: TCompRes = default(TCompRes)
gen(p, n[1], x)
gen(p, n[2], y)
if mapType(n[2].typ) == etyBaseIndex:
@@ -2282,7 +2319,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
if mapType(n[1].typ) != etyBaseIndex:
unaryExpr(p, n, r, "", "($1 == null)")
else:
var x: TCompRes
var x: TCompRes = default(TCompRes)
gen(p, n[1], x)
r.res = "($# == null && $# === 0)" % [x.address, x.res]
of mEnumToStr: genRepr(p, n, r)
@@ -2293,7 +2330,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
if n[1].kind == nkBracket:
genJSArrayConstr(p, n[1], r)
else:
var x: TCompRes
var x: TCompRes = default(TCompRes)
gen(p, n[1], x)
useMagic(p, "nimCopy")
r.res = "nimCopy(null, $1, $2)" % [x.rdLoc, genTypeInfo(p, n.typ)]
@@ -2302,7 +2339,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mDestroy, mTrace: discard "ignore calls to the default destructor"
of mOrd: genOrd(p, n, r)
of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
var x: TCompRes
var x: TCompRes = default(TCompRes)
gen(p, n[1], x)
if skipTypes(n[1].typ, abstractInst).kind == tyCstring:
let (a, tmp) = maybeMakeTemp(p, n[1], x)
@@ -2311,7 +2348,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
r.res = "($1).length" % [x.rdLoc]
r.kind = resExpr
of mHigh:
var x: TCompRes
var x: TCompRes = default(TCompRes)
gen(p, n[1], x)
if skipTypes(n[1].typ, abstractInst).kind == tyCstring:
let (a, tmp) = maybeMakeTemp(p, n[1], x)
@@ -2343,7 +2380,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of tyUInt64:
if optJsBigInt64 in p.config.globalOptions:
binaryExpr(p, n, r, "", "$1 = BigInt.asUintN(64, $3 - BigInt($2))", true)
else: binaryUintExpr(p, n, r, "+", true)
else: binaryUintExpr(p, n, r, "-", true)
elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
if optOverflowCheck notin p.options:
binaryExpr(p, n, r, "", "$1 = BigInt.asIntN(64, $3 - BigInt($2))", true)
@@ -2356,7 +2393,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
"""if ($1.length < $2) { for (var i = $3.length; i < $4; ++i) $3.push(0); }
else {$3.length = $4; }""")
of mSetLengthSeq:
var x, y: TCompRes
var x, y: TCompRes = default(TCompRes)
gen(p, n[1], x)
gen(p, n[2], y)
let t = skipTypes(n[1].typ, abstractVar)[0]
@@ -2395,7 +2432,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
genCall(p, n, r)
of mSlice:
# arr.slice([begin[, end]]): 'end' is exclusive
var x, y, z: TCompRes
var x, y, z: TCompRes = default(TCompRes)
gen(p, n[1], x)
gen(p, n[2], y)
gen(p, n[3], z)
@@ -2413,7 +2450,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
var
a, b: TCompRes
a, b: TCompRes = default(TCompRes)
useMagic(p, "setConstr")
r.res = rope("setConstr(")
r.kind = resExpr
@@ -2450,7 +2487,7 @@ proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
# generate typed array
# for example Nim generates `new Uint8Array([1, 2, 3])` for `[byte(1), 2, 3]`
# TODO use `set` or loop to initialize typed array which improves performances in some situations
var a: TCompRes
var a: TCompRes = default(TCompRes)
r.res = "new $1([" % [rope(jsTyp)]
r.kind = resExpr
for i in 0 ..< n.len:
@@ -2462,7 +2499,7 @@ proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
genJSArrayConstr(p, n, r)
proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
var a: TCompRes = default(TCompRes)
r.res = rope("{")
r.kind = resExpr
for i in 0..<n.len:
@@ -2481,9 +2518,9 @@ proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
r.res.add("}")
proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
var a: TCompRes = default(TCompRes)
r.kind = resExpr
var initList : Rope
var initList : Rope = ""
var fieldIDs = initIntSet()
let nTyp = n.typ.skipTypes(abstractInst)
for i in 1..<n.len:
@@ -2557,16 +2594,23 @@ proc upConv(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n[0], r) # XXX
proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
var a, b: TCompRes
var a, b: TCompRes = default(TCompRes)
gen(p, n[0], r)
let src = skipTypes(n[0].typ, abstractVarRange)
let dest = skipTypes(n.typ, abstractVarRange)
if src.kind in {tyInt64, tyUInt64} and dest.kind notin {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
r.res = "Number($1)" % [r.res]
if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and
checkUnsignedConversions notin p.config.legacyFeatures):
discard "XXX maybe emit masking instructions here"
if optRangeCheck notin p.options:
return
elif dest.kind in {tyUInt..tyUInt64} and checkUnsignedConversions notin p.config.legacyFeatures:
if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
r.res = "BigInt.asUintN($1, $2)" % [$(dest.size * 8), r.res]
else:
r.res = "BigInt.asUintN($1, BigInt($2))" % [$(dest.size * 8), r.res]
if not (dest.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions):
r.res = "Number($1)" % [r.res]
else:
if src.kind in {tyInt64, tyUInt64} and dest.kind notin {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
# we do a range check anyway, so it's ok if the number gets rounded
r.res = "Number($1)" % [r.res]
gen(p, n[1], a)
gen(p, n[2], b)
useMagic(p, "chckRange")
@@ -2643,9 +2687,10 @@ proc optionalLine(p: Rope): Rope =
proc genProc(oldProc: PProc, prc: PSym): Rope =
## Generate a JS procedure ('function').
result = ""
var
resultSym: PSym
a: TCompRes
a: TCompRes = default(TCompRes)
#if gVerbosity >= 3:
# echo "BEGIN generating code for: " & prc.name.s
var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
@@ -2673,7 +2718,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
else:
returnStmt = "return $#;$n" % [a.res]
var transformedBody = transformBody(p.module.graph, p.module.idgen, prc, dontUseCache)
var transformedBody = transformBody(p.module.graph, p.module.idgen, prc, {})
if sfInjectDestructors in prc.flags:
transformedBody = injectDestructorCalls(p.module.graph, p.module.idgen, prc, transformedBody)
@@ -2725,7 +2770,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
# echo "END generated code for: " & prc.name.s
proc genStmt(p: PProc, n: PNode) =
var r: TCompRes
var r: TCompRes = default(TCompRes)
gen(p, n, r)
if r.res != "": lineF(p, "$#;$n", [r.res])
@@ -2856,7 +2901,11 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.res = rope"Infinity"
of fcNegInf:
r.res = rope"-Infinity"
else: r.res = rope(f.toStrMaxPrecision)
else:
if n.typ.skipTypes(abstractVarRange).kind == tyFloat32:
r.res.addFloatRoundtrip(f.float32)
else:
r.res.addFloatRoundtrip(f)
r.kind = resExpr
of nkCallKinds:
if isEmptyType(n.typ):
@@ -2957,13 +3006,11 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
proc newModule(g: ModuleGraph; module: PSym): BModule =
## Create a new JS backend module node.
new(result)
result.module = module
result.sigConflicts = initCountTable[SigHash]()
if g.backend == nil:
g.backend = newGlobals()
result.graph = g
result.config = g.config
result = BModule(module: module, sigConflicts: initCountTable[SigHash](),
graph: g, config: g.config
)
if sfSystemModule in module.flags:
PGlobals(g.backend).inSystem = true
@@ -3036,6 +3083,7 @@ proc processJSCodeGen*(b: PPassContext, n: PNode): PNode =
if m.module == nil: internalError(m.config, n.info, "myProcess")
let globals = PGlobals(m.graph.backend)
var p = newInitProc(globals, m)
m.initProc = p
p.unique = globals.unique
genModule(p, n)
p.g.code.add(p.locals)
@@ -3049,9 +3097,8 @@ proc wholeCode(graph: ModuleGraph; m: BModule): Rope =
var p = newInitProc(globals, m)
attachProc(p, prc)
var disp = generateMethodDispatchers(graph, m.idgen)
for i in 0..<disp.len:
let prc = disp[i].sym
generateIfMethodDispatchers(graph, m.idgen)
for prc in getDispatchers(graph):
if not globals.generatedSyms.containsOrIncl(prc.id):
var p = newInitProc(globals, m)
attachProc(p, prc)

View File

@@ -10,10 +10,12 @@
# This file implements lambda lifting for the transformator.
import
intsets, strutils, options, ast, astalgo, msgs,
idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos,
options, ast, astalgo, msgs,
idents, renderer, types, magicsys, lowerings, modulegraphs, lineinfos,
transf, liftdestructors, typeallowed
import std/[strutils, tables, intsets]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -133,10 +135,10 @@ proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator)
var n = newNodeI(nkRange, iter.info)
n.add newIntNode(nkIntLit, -1)
n.add newIntNode(nkIntLit, 0)
result = newType(tyRange, nextTypeId(idgen), iter)
result = newType(tyRange, idgen, iter)
result.n = n
var intType = nilOrSysInt(g)
if intType.isNil: intType = newType(tyInt, nextTypeId(idgen), iter)
if intType.isNil: intType = newType(tyInt, idgen, iter)
rawAddSon(result, intType)
proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym =
@@ -187,6 +189,8 @@ proc getEnvParam*(routine: PSym): PSym =
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
result = hidden.sym
assert sfFromGeneric in result.flags
else:
result = nil
proc interestingVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and
@@ -199,6 +203,8 @@ proc illegalCapture(s: PSym): bool {.inline.} =
proc isInnerProc(s: PSym): bool =
if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and s.magic == mNone:
result = s.skipGenericOwner.kind in routineKinds
else:
result = false
proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
# Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
@@ -293,33 +299,34 @@ proc freshVarForClosureIter*(g: ModuleGraph; s: PSym; idgen: IdGenerator; owner:
proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
let s = n.sym
let isEnv = s.name.id == getIdent(g.cache, ":env").id
if illegalCapture(s):
localError(g.config, n.info,
("'$1' is of type <$2> which cannot be captured as it would violate memory" &
" safety, declared here: $3; using '-d:nimNoLentIterators' helps in some cases." &
" Consider using a <ref $2> which can be captured.") %
[s.name.s, typeToString(s.typ), g.config$s.info])
elif not (owner.typ.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags):
elif not (owner.typ.isClosure or owner.isNimcall and not owner.isExplicitCallConv or isEnv):
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
[s.name.s, owner.name.s, $owner.typ.callConv])
incl(owner.typ.flags, tfCapturesEnv)
owner.typ.callConv = ccClosure
if not isEnv:
owner.typ.callConv = ccClosure
type
DetectionPass = object
processed, capturedVars: IntSet
ownerToType: Table[int, PType]
somethingToDo: bool
inTypeOf: bool
graph: ModuleGraph
idgen: IdGenerator
proc initDetectionPass(g: ModuleGraph; fn: PSym; idgen: IdGenerator): DetectionPass =
result.processed = initIntSet()
result.capturedVars = initIntSet()
result.ownerToType = initTable[int, PType]()
result.processed.incl(fn.id)
result.graph = g
result.idgen = idgen
result = DetectionPass(processed: toIntSet([fn.id]),
capturedVars: initIntSet(), ownerToType: initTable[int, PType](),
graph: g, idgen: idgen
)
discard """
proc outer =
@@ -335,7 +342,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
info: TLineInfo): PType =
result = c.ownerToType.getOrDefault(owner.id)
if result.isNil:
result = newType(tyRef, nextTypeId(c.idgen), owner)
result = newType(tyRef, c.idgen, owner)
let obj = createEnvObj(c.graph, c.idgen, owner, info)
rawAddSon(result, obj)
c.ownerToType[owner.id] = result
@@ -343,7 +350,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
proc asOwnedRef(c: var DetectionPass; t: PType): PType =
if optOwnedRefs in c.graph.config.globalOptions:
assert t.kind == tyRef
result = newType(tyOwned, nextTypeId(c.idgen), t.owner)
result = newType(tyOwned, c.idgen, t.owner)
result.flags.incl tfHasOwned
result.rawAddSon t
else:
@@ -352,7 +359,7 @@ proc asOwnedRef(c: var DetectionPass; t: PType): PType =
proc getEnvTypeForOwnerUp(c: var DetectionPass; owner: PSym;
info: TLineInfo): PType =
var r = c.getEnvTypeForOwner(owner, info)
result = newType(tyPtr, nextTypeId(c.idgen), owner)
result = newType(tyPtr, c.idgen, owner)
rawAddSon(result, r.skipTypes({tyOwned, tyRef, tyPtr}))
proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
@@ -413,6 +420,9 @@ Consider:
"""
proc isTypeOf(n: PNode): bool =
n.kind == nkSym and n.sym.magic in {mTypeOf, mType}
proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
var cp = getEnvParam(fn)
let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner
@@ -441,15 +451,18 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
if innerProc:
if s.isIterator: c.somethingToDo = true
if not c.processed.containsOrIncl(s.id):
let body = transformBody(c.graph, c.idgen, s, useCache)
let body = transformBody(c.graph, c.idgen, s, {useCache})
detectCapturedVars(body, s, c)
let ow = s.skipGenericOwner
let innerClosure = innerProc and s.typ.callConv == ccClosure and not s.isIterator
let interested = interestingVar(s)
if ow == owner:
if owner.isIterator:
c.somethingToDo = true
addClosureParam(c, owner, n.info)
if interestingIterVar(s):
if not c.capturedVars.containsOrIncl(s.id):
if not c.capturedVars.contains(s.id):
if not c.inTypeOf: c.capturedVars.incl(s.id)
let obj = getHiddenParam(c.graph, owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
#let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef, tyPtr})
@@ -458,7 +471,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
else:
discard addField(obj, s, c.graph.cache, c.idgen)
# direct or indirect dependency:
elif (innerProc and not s.isIterator and s.typ.callConv == ccClosure) or interestingVar(s):
elif innerClosure or interested:
discard """
proc outer() =
var x: int
@@ -475,10 +488,12 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
addClosureParam(c, owner, n.info)
#echo "capturing ", n.info
# variable 's' is actually captured:
if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id):
let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr})
#getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
discard addField(obj, s, c.graph.cache, c.idgen)
if interestingVar(s):
if not c.capturedVars.contains(s.id):
if not c.inTypeOf: c.capturedVars.incl(s.id)
let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr})
#getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
discard addField(obj, s, c.graph.cache, c.idgen)
# create required upFields:
var w = owner.skipGenericOwner
if isInnerProc(w) or owner.isIterator:
@@ -510,9 +525,14 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
detectCapturedVars(n[namePos], owner, c)
of nkReturnStmt:
detectCapturedVars(n[0], owner, c)
of nkIdentDefs:
detectCapturedVars(n[^1], owner, c)
else:
if n.isCallExpr and n[0].isTypeOf:
c.inTypeOf = true
for i in 0..<n.len:
detectCapturedVars(n[i], owner, c)
c.inTypeOf = false
type
LiftingPass = object
@@ -522,9 +542,8 @@ type
unownedEnvVars: Table[int, PNode] # only required for --newruntime
proc initLiftingPass(fn: PSym): LiftingPass =
result.processed = initIntSet()
result.processed.incl(fn.id)
result.envVars = initTable[int, PNode]()
result = LiftingPass(processed: toIntSet([fn.id]),
envVars: initTable[int, PNode]())
proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
let s = n.sym
@@ -711,6 +730,7 @@ proc symToClosure(n: PNode; owner: PSym; d: var DetectionPass;
# direct dependency, so use the outer's env variable:
result = makeClosure(d.graph, d.idgen, s, setupEnvVar(owner, d, c, n.info), n.info)
else:
result = nil
let available = getHiddenParam(d.graph, owner)
let wanted = getHiddenParam(d.graph, s).typ
# ugh: call through some other inner proc;
@@ -737,7 +757,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
# echo renderTree(s.getBody, {renderIds})
let oldInContainer = c.inContainer
c.inContainer = 0
var body = transformBody(d.graph, d.idgen, s, dontUseCache)
var body = transformBody(d.graph, d.idgen, s, {})
body = liftCapturedVars(body, s, d, c)
if c.envVars.getOrDefault(s.id).isNil:
s.transformedBody = body
@@ -792,6 +812,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
of nkTypeOfExpr:
result = n
else:
if n.isCallExpr and n[0].isTypeOf:
return
if owner.isIterator:
if nfLL in n.flags:
# special case 'when nimVm' due to bug #3636:
@@ -859,7 +881,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; flags: TransformFlags): PNode =
# XXX backend == backendJs does not suffice! The compiletime stuff needs
# the transformation even when compiling to JS ...
@@ -868,7 +890,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 and force notin flags):
# ignore forward declaration:
result = body
@@ -936,7 +958,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
result = newNodeI(nkStmtList, body.info)
# static binding?
var env: PSym
var env: PSym = nil
let op = call[0]
if op.kind == nkSym and op.sym.isIterator:
# createClosure()

View File

@@ -16,8 +16,10 @@
# DOS or Macintosh text files, even when it is not the native format.
import
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
wordrecg, lineinfos, pathutils, parseutils
options, msgs, platform, idents, nimlexbase, llstream,
wordrecg, lineinfos, pathutils
import std/[hashes, parseutils, strutils]
when defined(nimPreviewSlimSystem):
import std/[assertions, formatfloat]
@@ -120,7 +122,6 @@ type
# this is needed because scanning comments
# needs so much look-ahead
currLineIndent*: int
strongSpaces*, allowTabs*: bool
errorHandler*: ErrorHandler
cache*: IdentCache
when defined(nimsuggest):
@@ -148,9 +149,11 @@ proc isNimIdentifier*(s: string): bool =
var i = 1
while i < sLen:
if s[i] == '_': inc(i)
if i < sLen and s[i] notin SymChars: return
if i < sLen and s[i] notin SymChars: return false
inc(i)
result = true
else:
result = false
proc `$`*(tok: Token): string =
case tok.tokType
@@ -172,32 +175,6 @@ proc printTok*(conf: ConfigRef; tok: Token) =
# xxx factor with toLocation
msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" & $tok.tokType & " " & $tok)
proc initToken*(L: var Token) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
L.spacing = {}
L.literal = ""
L.fNumber = 0.0
L.base = base10
L.ident = nil
when defined(nimpretty):
L.commentOffsetA = 0
L.commentOffsetB = 0
proc fillToken(L: var Token) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
L.spacing = {}
setLen(L.literal, 0)
L.fNumber = 0.0
L.base = base10
L.ident = nil
when defined(nimpretty):
L.commentOffsetA = 0
L.commentOffsetB = 0
proc openLexer*(lex: var Lexer, fileIdx: FileIndex, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef) =
openBaseLexer(lex, inputstream)
@@ -537,8 +514,8 @@ proc getNumber(L: var Lexer, result: var Token) =
of floatTypes:
result.fNumber = parseFloat(result.literal)
of tkUInt64Lit, tkUIntLit:
var iNumber: uint64
var len: int
var iNumber: uint64 = uint64(0)
var len: int = 0
try:
len = parseBiggestUInt(result.literal, iNumber)
except ValueError:
@@ -547,8 +524,8 @@ proc getNumber(L: var Lexer, result: var Token) =
raise newException(ValueError, "invalid integer: " & result.literal)
result.iNumber = cast[int64](iNumber)
else:
var iNumber: int64
var len: int
var iNumber: int64 = int64(0)
var len: int = 0
try:
len = parseBiggestInt(result.literal, iNumber)
except ValueError:
@@ -794,7 +771,7 @@ proc getString(L: var Lexer, tok: var Token, mode: StringMode) =
if mode != normal: tok.tokType = tkRStrLit
else: tok.tokType = tkStrLit
while true:
var c = L.buf[pos]
let c = L.buf[pos]
if c == '\"':
if mode != normal and L.buf[pos+1] == '\"':
inc(pos, 2)
@@ -820,7 +797,7 @@ proc getCharacter(L: var Lexer; tok: var Token) =
tokenBegin(tok, L.bufpos)
let startPos = L.bufpos
inc(L.bufpos) # skip '
var c = L.buf[L.bufpos]
let c = L.buf[L.bufpos]
case c
of '\0'..pred(' '), '\'':
lexMessage(L, errGenerated, "invalid character literal")
@@ -938,7 +915,7 @@ proc getOperator(L: var Lexer, tok: var Token) =
tokenBegin(tok, pos)
var h: Hash = 0
while true:
var c = L.buf[pos]
let c = L.buf[pos]
if c in OpChars:
h = h !& ord(c)
inc(pos)
@@ -1006,22 +983,6 @@ proc getPrecedence*(tok: Token): int =
of tkOr, tkXor, tkPtr, tkRef: result = 3
else: return -10
proc newlineFollows*(L: Lexer): bool =
var pos = L.bufpos
while true:
case L.buf[pos]
of ' ', '\t':
inc(pos)
of CR, LF:
result = true
break
of '#':
inc(pos)
if L.buf[pos] == '#': inc(pos)
if L.buf[pos] != '[': return true
else:
break
proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
isDoc: bool) =
var pos = start
@@ -1113,9 +1074,7 @@ proc scanComment(L: var Lexer, tok: var Token) =
toStrip = 0
else: # found first non-whitespace character
stripInit = true
var lastBackslash = -1
while L.buf[pos] notin {CR, LF, nimlexbase.EndOfFile}:
if L.buf[pos] == '\\': lastBackslash = pos+1
tok.literal.add(L.buf[pos])
inc(pos)
tokenEndIgnore(tok, pos)
@@ -1158,7 +1117,7 @@ proc skip(L: var Lexer, tok: var Token) =
inc(pos)
tok.spacing.incl(tsLeading)
of '\t':
if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead")
lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead")
inc(pos)
of CR, LF:
tokenEndPrevious(tok, pos)
@@ -1226,7 +1185,7 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
L.previousToken.line = tok.line.uint16
L.previousToken.col = tok.col.int16
fillToken(tok)
reset(tok)
if L.indentAhead >= 0:
tok.indent = L.indentAhead
L.currLineIndent = L.indentAhead
@@ -1238,7 +1197,7 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
if tok.tokType == tkComment:
L.indentAhead = L.currLineIndent
return
var c = L.buf[L.bufpos]
let c = L.buf[L.bufpos]
tok.line = L.lineNumber
tok.col = getColNumber(L, L.bufpos)
if c in SymStartChars - {'r', 'R'} - UnicodeOperatorStartChars:
@@ -1394,9 +1353,9 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef): int =
var lex: Lexer
var tok: Token
initToken(tok)
result = 0
var lex: Lexer = default(Lexer)
var tok: Token = default(Token)
openLexer(lex, fileIdx, inputstream, cache, config)
var prevToken = tkEof
while tok.tokType != tkEof:
@@ -1409,11 +1368,11 @@ proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
proc getPrecedence*(ident: PIdent): int =
## assumes ident is binary operator already
var tok: Token
initToken(tok)
tok.ident = ident
tok.tokType =
if tok.ident.id in ord(tokKeywordLow) - ord(tkSymbol)..ord(tokKeywordHigh) - ord(tkSymbol):
TokType(tok.ident.id + ord(tkSymbol))
else: tkOpr
let
tokType =
if ident.id in ord(tokKeywordLow) - ord(tkSymbol)..ord(tokKeywordHigh) - ord(tkSymbol):
TokType(ident.id + ord(tkSymbol))
else: tkOpr
tok = Token(ident: ident, tokType: tokType)
getPrecedence(tok)

View File

@@ -11,8 +11,9 @@
## (`=sink`, `=copy`, `=destroy`, `=deepCopy`, `=wasMoved`, `=dup`).
import modulegraphs, lineinfos, idents, ast, renderer, semdata,
sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils
sighashes, lowerings, options, types, msgs, magicsys, ccgutils
import std/tables
from trees import isCaseObj
when defined(nimPreviewSlimSystem):
@@ -301,7 +302,7 @@ proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
result.add newSymNode(op)
if sfNeverRaises notin op.flags:
c.canRaise = true
if op.typ.sons[1].kind == tyVar:
if op.typ[1].kind == tyVar:
result.add genAddr(c, x)
else:
result.add x
@@ -366,6 +367,8 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen)
body.add newHookCall(c, op, x, y)
result = true
else:
result = false
elif tfHasAsgn in t.flags:
var op: PSym
if sameType(t, c.asgnForType):
@@ -395,6 +398,8 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
assert op.ast[genericParamsPos].kind == nkEmpty
body.add newHookCall(c, op, x, y)
result = true
else:
result = false
proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
let t = orig.skipTypes(abstractInst - {tyDistinct})
@@ -434,6 +439,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add destructorCall(c, op, x)
result = true
else:
result = false
#result = addDestructorCall(c, t, body, x)
of attachedAsgn, attachedSink, attachedTrace:
var op = getAttachedOp(c.g, t, c.kind)
@@ -454,6 +461,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add newDeepCopyCall(c, op, x, y)
result = true
else:
result = false
of attachedWasMoved:
var op = getAttachedOp(c.g, t, attachedWasMoved)
@@ -468,6 +477,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add genWasMovedCall(c, op, x)
result = true
else:
result = false
of attachedDup:
var op = getAttachedOp(c.g, t, attachedDup)
@@ -482,6 +493,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add newDupCall(c, op, x, y)
result = true
else:
result = false
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
@@ -541,6 +554,14 @@ proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
else:
body.sons.setLen counterIdx
proc checkSelfAssignment(c: var TLiftCtx; t: PType; body, x, y: PNode) =
var cond = callCodegenProc(c.g, "sameSeqPayload", c.info,
newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x),
newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y)
)
cond.typ = getSysType(c.g, c.info, tyBool)
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
of attachedDup:
@@ -548,10 +569,13 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
forallElements(c, t, body, x, y)
of attachedAsgn, attachedDeepCopy:
# we generate:
# if x.p == y.p:
# return
# setLen(dest, y.len)
# var i = 0
# while i < y.len: dest[i] = y[i]; inc(i)
# This is usually more efficient than a destroy/create pair.
checkSelfAssignment(c, t, body, x, y)
body.add setLenSeqCall(c, t, x, y)
forallElements(c, t, body, x, y)
of attachedSink:
@@ -1011,7 +1035,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of tyOrdinal, tyRange, tyInferred,
tyGenericInst, tyAlias, tySink:
fillBody(c, lastSon(t), body, x, y)
of tyConcept, tyIterable: doAssert false
of tyConcept, tyIterable: raiseAssert "unreachable"
proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
kind: TTypeAttachedOp; info: TLineInfo;
@@ -1033,7 +1057,7 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
res.typ = typ
src.typ = typ
result.typ = newType(tyProc, nextTypeId idgen, owner)
result.typ = newType(tyProc, idgen, owner)
result.typ.n = newNodeI(nkFormalParams, info)
rawAddSon(result.typ, res.typ)
result.typ.n.add newNodeI(nkEffectList, info)
@@ -1058,7 +1082,7 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
incl result.flags, sfGeneratedOp
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator): PSym =
info: TLineInfo; idgen: IdGenerator; isDiscriminant = false): PSym =
if kind == attachedDup:
return symDupPrototype(g, typ, owner, kind, info, idgen)
@@ -1068,7 +1092,8 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"),
idgen, result, info)
if kind == attachedDestructor and typ.kind in {tyRef, tyString, tySequence} and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
if kind == attachedDestructor and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
((g.config.isDefined("nimPreviewNonVarDestructor") and not isDiscriminant) or typ.kind in {tyRef, tyString, tySequence}):
dest.typ = typ
else:
dest.typ = makeVarType(typ.owner, typ, idgen)
@@ -1078,7 +1103,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
else:
src.typ = typ
result.typ = newProcType(info, nextTypeId(idgen), owner)
result.typ = newProcType(info, idgen, owner)
result.typ.addParam dest
if kind notin {attachedDestructor, attachedWasMoved}:
result.typ.addParam src
@@ -1161,7 +1186,8 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym,
info: TLineInfo; idgen: IdGenerator): PSym =
assert(typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject)
result = symPrototype(g, field.typ, typ.owner, attachedDestructor, info, idgen)
# discrimantor assignments needs pointers to destroy fields; alas, we cannot use non-var destructor here
result = symPrototype(g, field.typ, typ.owner, attachedDestructor, info, idgen, isDiscriminant = true)
var a = TLiftCtx(info: info, g: g, kind: attachedDestructor, asgnForType: typ, idgen: idgen,
fn: result)
a.asgnForType = typ
@@ -1248,7 +1274,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
# bug #15122: We need to produce all prototypes before entering the
# mind boggling recursion. Hacks like these imply we should rewrite
# this module.
var generics: array[attachedWasMoved..attachedTrace, bool]
var generics: array[attachedWasMoved..attachedTrace, bool] = default(array[attachedWasMoved..attachedTrace, bool])
for k in attachedWasMoved..lastAttached:
generics[k] = getAttachedOp(g, canon, k) != nil
if not generics[k]:

View File

@@ -10,9 +10,11 @@
## This module implements the '.liftLocals' pragma.
import
strutils, options, ast, msgs,
options, ast, msgs,
idents, renderer, types, lowerings, lineinfos
import std/strutils
from pragmas import getPragmaVal
from wordrecg import wLiftLocals
@@ -49,6 +51,7 @@ proc liftLocals(n: PNode; i: int; c: var Ctx) =
liftLocals(it, i, c)
proc lookupParam(params, dest: PNode): PSym =
result = nil
if dest.kind != nkIdent: return nil
for i in 1..<params.len:
if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:

View File

@@ -7,10 +7,11 @@
# distribution, for details about the copyright.
#
## This module contains the ``TMsgKind`` enum as well as the
## ``TLineInfo`` object.
## This module contains the `TMsgKind` enum as well as the
## `TLineInfo` object.
import ropes, tables, pathutils, hashes
import ropes, pathutils
import std/[hashes, tables]
const
explanationsBaseUrl* = "https://nim-lang.github.io/Nim"
@@ -91,6 +92,7 @@ type
warnStmtListLambda = "StmtListLambda",
warnBareExcept = "BareExcept",
warnImplicitDefaultValue = "ImplicitDefaultValue",
warnStdPrefix = "StdPrefix"
warnUser = "User",
# hints
hintSuccess = "Success", hintSuccessX = "SuccessX",
@@ -104,10 +106,10 @@ type
hintPattern = "Pattern", hintExecuting = "Exec", hintLinking = "Link", hintDependency = "Dependency",
hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace",
hintGCStats = "GCStats", hintGlobalVar = "GlobalVar", hintExpandMacro = "ExpandMacro",
hintAmbiguousEnum = "AmbiguousEnum",
hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext",
hintMsgOrigin = "MsgOrigin", # since 1.3.5
hintDeclaredLoc = "DeclaredLoc", # since 1.5.1
hintUnknownHint = "UnknownHint"
const
MsgKindToStr*: array[TMsgKind, string] = [
@@ -185,7 +187,7 @@ const
warnAnyEnumConv: "$1",
warnHoleEnumConv: "$1",
warnCstringConv: "$1",
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future",
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; Use a `cast` operation like `cast[cstring](x)`; this will become a compile time error in the future",
warnEffect: "$1",
warnCastSizes: "$1", # deadcode
warnAboveMaxSizeSet: "$1",
@@ -194,6 +196,7 @@ const
warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead",
warnBareExcept: "$1",
warnImplicitDefaultValue: "$1",
warnStdPrefix: "$1 needs the 'std' prefix",
warnUser: "$1",
hintSuccess: "operation successful: $#",
# keep in sync with `testament.isSuccess`
@@ -225,12 +228,12 @@ const
hintGCStats: "$1",
hintGlobalVar: "global variable declared here",
hintExpandMacro: "expanded macro: $1",
hintAmbiguousEnum: "$1",
hintUser: "$1",
hintUserRaw: "$1",
hintExtendedContext: "$1",
hintMsgOrigin: "$1",
hintDeclaredLoc: "$1",
hintUnknownHint: "unknown hint: $1"
]
const
@@ -248,7 +251,8 @@ type
TNoteKinds* = set[TNoteKind]
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept}
result = default(array[0..3, TNoteKinds])
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept, warnStdPrefix}
result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
result[1] = result[2] - {warnProveField, warnProveIndex,
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
@@ -310,7 +314,7 @@ proc `==`*(a, b: FileIndex): bool {.borrow.}
proc hash*(i: TLineInfo): Hash =
hash (i.line.int, i.col.int, i.fileIndex.int)
proc raiseRecoverableError*(msg: string) {.noinline.} =
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
raise newException(ERecoverableError, msg)
const
@@ -341,9 +345,8 @@ type
proc initMsgConfig*(): MsgConfig =
result.msgContext = @[]
result.lastError = unknownLineInfo
result.filenameToIndexTbl = initTable[string, FileIndex]()
result.fileInfos = @[]
result.errorOutputs = {eStdOut, eStdErr}
result = MsgConfig(msgContext: @[], lastError: unknownLineInfo,
filenameToIndexTbl: initTable[string, FileIndex](),
fileInfos: @[], errorOutputs: {eStdOut, eStdErr}
)
result.filenameToIndexTbl["???"] = FileIndex(-1)

View File

@@ -19,10 +19,12 @@ const
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
proc identLen*(line: string, start: int): int =
result = 0
while start+result < line.len and line[start+result] in Letters:
inc result
proc `=~`(s: string, a: openArray[string]): bool =
result = false
for x in a:
if s.startsWith(x): return true

View File

@@ -19,7 +19,7 @@ when defined(nimPreviewSlimSystem):
const hasRstdin = (defined(nimUseLinenoise) or defined(useLinenoise) or defined(useGnuReadline)) and
not defined(windows)
when hasRstdin: import rdstdin
when hasRstdin: import std/rdstdin
type
TLLRepl* = proc (s: PLLStream, buf: pointer, bufLen: int): int
@@ -40,33 +40,22 @@ type
PLLStream* = ref TLLStream
proc llStreamOpen*(data: string): PLLStream =
new(result)
result.s = data
result.kind = llsString
proc llStreamOpen*(data: sink string): PLLStream =
PLLStream(kind: llsString, s: data)
proc llStreamOpen*(f: File): PLLStream =
new(result)
result.f = f
result.kind = llsFile
PLLStream(kind: llsFile, f: f)
proc llStreamOpen*(filename: AbsoluteFile, mode: FileMode): PLLStream =
new(result)
result.kind = llsFile
result = PLLStream(kind: llsFile)
if not open(result.f, filename.string, mode): result = nil
proc llStreamOpen*(): PLLStream =
new(result)
result.kind = llsNone
PLLStream(kind: llsNone)
proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int
proc llStreamOpenStdIn*(r: TLLRepl = llReadFromStdin, onPrompt: OnPrompt = nil): PLLStream =
new(result)
result.kind = llsStdIn
result.s = ""
result.lineOffset = -1
result.repl = r
result.onPrompt = onPrompt
PLLStream(kind: llsStdIn, s: "", lineOffset: -1, repl: r, onPrompt: onPrompt)
proc llStreamClose*(s: PLLStream) =
case s.kind
@@ -89,6 +78,8 @@ proc endsWith*(x: string, s: set[char]): bool =
while i >= 0 and x[i] == ' ': dec(i)
if i >= 0 and x[i] in s:
result = true
else:
result = false
const
LineContinuationOprs = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^',
@@ -104,6 +95,7 @@ proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs))
proc countTriples(s: string): int =
result = 0
var i = 0
while i+2 < s.len:
if s[i] == '"' and s[i+1] == '"' and s[i+2] == '"':

View File

@@ -14,8 +14,10 @@ when defined(nimPreviewSlimSystem):
import std/assertions
import
intsets, ast, astalgo, idents, semdata, types, msgs, options,
renderer, lineinfos, modulegraphs, astmsgs, sets, wordrecg
ast, astalgo, idents, semdata, types, msgs, options,
renderer, lineinfos, modulegraphs, astmsgs, wordrecg
import std/[intsets, sets]
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
@@ -72,7 +74,7 @@ proc addUniqueSym*(scope: PScope, s: PSym): PSym =
proc openScope*(c: PContext): PScope {.discardable.} =
result = PScope(parent: c.currentScope,
symbols: newStrTable(),
symbols: initStrTable(),
depthLevel: c.scopeDepth + 1)
c.currentScope = result
@@ -254,6 +256,41 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy
if s.kind in filter:
result.add s
proc isAmbiguous*(c: PContext, s: PIdent, filter: TSymKinds, sym: var PSym): bool =
result = false
block outer:
for scope in allScopes(c.currentScope):
var ti: TIdentIter
var candidate = initIdentIter(ti, scope.symbols, s)
var scopeHasCandidate = false
while candidate != nil:
if candidate.kind in filter:
if scopeHasCandidate:
# 2 candidates in same scope, ambiguous
return true
else:
scopeHasCandidate = true
sym = candidate
candidate = nextIdentIter(ti, scope.symbols)
if scopeHasCandidate:
# scope had a candidate but wasn't ambiguous
return false
var importsHaveCandidate = false
var marked = initIntSet()
for im in c.imports.mitems:
for s in symbols(im, marked, s, c.graph):
if s.kind in filter:
if importsHaveCandidate:
# 2 candidates among imports, ambiguous
return true
else:
importsHaveCandidate = true
sym = s
if importsHaveCandidate:
# imports had a candidate but wasn't ambiguous
return false
proc errorSym*(c: PContext, n: PNode): PSym =
## creates an error symbol to avoid cascading errors (for IDE support)
var m = n
@@ -298,7 +335,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
var it: TTabIter
var s = initTabIter(it, scope.symbols)
var missingImpls = 0
var unusedSyms: seq[tuple[sym: PSym, key: string]]
var unusedSyms: seq[tuple[sym: PSym, key: string]] = @[]
while s != nil:
if sfForward in s.flags and s.kind notin {skType, skModule}:
# too many 'implementation of X' errors are annoying
@@ -404,7 +441,7 @@ proc openShadowScope*(c: PContext) =
## opens a shadow scope, just like any other scope except the depth is the
## same as the parent -- see `isShadowScope`.
c.currentScope = PScope(parent: c.currentScope,
symbols: newStrTable(),
symbols: initStrTable(),
depthLevel: c.scopeDepth)
proc closeShadowScope*(c: PContext) =
@@ -429,7 +466,7 @@ proc mergeShadowScope*(c: PContext) =
c.addInterfaceDecl(sym)
import std/editdistance, heapqueue
import std/[editdistance, heapqueue]
type SpellCandidate = object
dist: int
@@ -458,7 +495,7 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) =
for (sym, depth, isLocal) in allSyms(c):
let depth = -depth - 1
let dist = editDistance(name0, sym.name.s.nimIdentNormalize)
var msg: string
var msg: string = ""
msg.add "\n ($1, $2): '$3'" % [$dist, $depth, sym.name.s]
list.push SpellCandidate(dist: dist, depth: depth, msg: msg, sym: sym)
@@ -488,6 +525,7 @@ proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PS
var err = "ambiguous identifier: '" & s.name.s & "'"
var i = 0
var ignoredModules = 0
result = nil
for candidate in importedItems(c, s.name):
if i == 0: err.add " -- use one of the following:\n"
else: err.add "\n"
@@ -560,7 +598,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
if result == nil: result = errorUndeclaredIdentifierHint(c, n, ident)
else:
internalError(c.config, n.info, "lookUp")
return
return nil
if amb:
#contains(c.ambiguousSymbols, result.id):
result = errorUseQualifier(c, n.info, result, amb)
@@ -586,6 +624,8 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
amb = candidates.len > 1
if amb and checkAmbiguity in flags:
errorUseQualifier(c, n.info, candidates)
else:
result = nil
if result == nil:
let candidates = allPureEnumFields(c, ident)
if candidates.len > 0:
@@ -641,6 +681,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.marked = initIntSet()
case n.kind
of nkIdent, nkAccQuoted:
result = nil
var ident = considerQuotedIdent(c, n)
var scope = c.currentScope
o.mode = oimNoQualifier
@@ -664,6 +705,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = n.sym
o.mode = oimDone
of nkDotExpr:
result = nil
o.mode = oimOtherModule
o.m = qualifiedLookUp(c, n[0], {checkUndeclared, checkModule})
if o.m != nil and o.m.kind == skModule:
@@ -693,7 +735,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.symChoiceIndex = 1
o.marked = initIntSet()
incl(o.marked, result.id)
else: discard
else: result = nil
when false:
if result != nil and result.kind == skStub: loadStub(result)
@@ -708,6 +750,7 @@ proc lastOverloadScope*(o: TOverloadIter): int =
else: result = -1
proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = nil
assert o.currentScope == nil
var idx = o.importIdx+1
o.importIdx = c.imports.len # assume the other imported modules lack this symbol too
@@ -720,6 +763,7 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym
inc idx
proc symChoiceExtension(o: var TOverloadIter; c: PContext; n: PNode): PSym =
result = nil
assert o.currentScope == nil
while o.importIdx < c.imports.len:
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph)
@@ -782,6 +826,8 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
break
if result != nil:
incl o.marked, result.id
else:
result = nil
of oimSymChoiceLocalLookup:
if o.currentScope != nil:
result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked)
@@ -805,13 +851,16 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
if result == nil:
inc o.importIdx
result = symChoiceExtension(o, c, n)
else:
result = nil
when false:
if result != nil and result.kind == skStub: loadStub(result)
proc pickSym*(c: PContext, n: PNode; kinds: set[TSymKind];
flags: TSymFlags = {}): PSym =
var o: TOverloadIter
result = nil
var o: TOverloadIter = default(TOverloadIter)
var a = initOverloadIter(o, c, n)
while a != nil:
if a.kind in kinds and flags <= a.flags:

View File

@@ -122,25 +122,6 @@ proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
proc newTryFinally*(body, final: PNode): PNode =
result = newTree(nkHiddenTryStmt, body, newTree(nkFinally, final))
proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
let value = n.lastSon
result = newNodeI(nkStmtList, n.info)
var temp = newSym(skTemp, getIdent(g.cache, "_"), idgen, owner, value.info, owner.options)
var v = newNodeI(nkLetSection, value.info)
let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
vpart[0] = tempAsNode
vpart[1] = newNodeI(nkTupleClassTy, value.info)
vpart[2] = value
v.add vpart
result.add(v)
let lhs = n[0]
for i in 0..<lhs.len:
result.add newAsgnStmt(lhs[i], newTupleAccessRaw(tempAsNode, i))
proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
result = newNodeI(nkStmtList, n.info)
# note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
@@ -163,7 +144,7 @@ proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNod
result.add newFastAsgnStmt(n[2], tempAsNode)
proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo; final=true): PType =
result = newType(tyObject, nextTypeId(idgen), owner)
result = newType(tyObject, idgen, owner)
if final:
rawAddSon(result, nil)
incl result.flags, tfFinal
@@ -339,7 +320,7 @@ proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
proc genAddrOf*(n: PNode; idgen: IdGenerator; typeKind = tyPtr): PNode =
result = newNodeI(nkAddr, n.info, 1)
result[0] = n
result.typ = newType(typeKind, nextTypeId(idgen), n.typ.owner)
result.typ = newType(typeKind, idgen, n.typ.owner)
result.typ.rawAddSon(n.typ)
proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =

View File

@@ -18,7 +18,7 @@ export createMagic
proc nilOrSysInt*(g: ModuleGraph): PType = g.sysTypes[tyInt]
proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType =
result = newType(kind, nextTypeId(g.idgen), g.systemModule)
result = newType(kind, g.idgen, g.systemModule)
result.size = size
result.align = size.int16
@@ -27,9 +27,10 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
if result == nil:
localError(g.config, info, "system module needs: " & name)
result = newSym(skError, getIdent(g.cache, name), g.idgen, g.systemModule, g.systemModule.info, {})
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
result.typ = newType(tyError, g.idgen, g.systemModule)
proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
result = nil
let id = getIdent(g.cache, name)
for r in systemModuleSyms(g, id):
if r.magic == m:
@@ -39,7 +40,7 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy
if result != nil: return result
localError(g.config, info, "system module needs: " & name)
result = newSym(skError, id, g.idgen, g.systemModule, g.systemModule.info, {})
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
result.typ = newType(tyError, g.idgen, g.systemModule)
proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType =
result = getSysSym(g, info, name).typ
@@ -80,8 +81,8 @@ proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType =
proc resetSysTypes*(g: ModuleGraph) =
g.systemModule = nil
initStrTable(g.compilerprocs)
initStrTable(g.exposed)
g.compilerprocs = initStrTable()
g.exposed = initStrTable()
for i in low(g.sysTypes)..high(g.sysTypes):
g.sysTypes[i] = nil
@@ -92,16 +93,23 @@ proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType =
proc skipIntLit*(t: PType; id: IdGenerator): PType {.inline.} =
if t.n != nil and t.kind in {tyInt, tyFloat}:
result = copyType(t, nextTypeId(id), t.owner)
result = copyType(t, id, t.owner)
result.n = nil
else:
result = t
proc addSonSkipIntLit*(father, son: PType; id: IdGenerator) =
let s = son.skipIntLit(id)
father.sons.add(s)
father.add(s)
propagateToOwner(father, s)
proc makeVarType*(owner: PSym; baseType: PType; idgen: IdGenerator; kind = tyVar): PType =
if baseType.kind == kind:
result = baseType
else:
result = newType(kind, idgen, owner)
addSonSkipIntLit(result, baseType, idgen)
proc getCompilerProc*(g: ModuleGraph; name: string): PSym =
let ident = getIdent(g.cache, name)
result = strTableGet(g.compilerprocs, ident)
@@ -123,7 +131,7 @@ proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) =
proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym =
strTableGet(g.exposed, getIdent(g.cache, name))
proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed)
proc resetNimScriptSymbols*(g: ModuleGraph) = g.exposed = initStrTable()
proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
case t.kind
@@ -145,7 +153,17 @@ proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
of tyProc:
result = getSysMagic(g, info, "==", mEqProc)
else:
result = nil
globalError(g.config, info,
"can't find magic equals operator for type kind " & $t.kind)
proc makePtrType*(baseType: PType; idgen: IdGenerator): PType =
result = newType(tyPtr, idgen, baseType.owner)
addSonSkipIntLit(result, baseType, idgen)
proc makeAddr*(n: PNode; idgen: IdGenerator): PNode =
if n.kind == nkHiddenAddr:
result = n
else:
result = newTree(nkHiddenAddr, n)
result.typ = makePtrType(n.typ, idgen)

View File

@@ -22,12 +22,13 @@ import
modules,
modulegraphs, lineinfos, pathutils, vmprofiler
# ensure NIR compiles:
import nir / nir
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
import ic / [cbackend, integrity, navigator]
from ic / ic import rodViewer
import ic / [cbackend, integrity, navigator, ic]
import ../dist/checksums/src/checksums/sha1
@@ -47,6 +48,9 @@ proc writeDepsFile(g: ModuleGraph) =
f.writeLine(toFullPath(g.config, k))
f.close()
proc writeNinjaFile(g: ModuleGraph) =
discard "to implement"
proc writeCMakeDepsFile(conf: ConfigRef) =
## write a list of C files for build systems like CMake.
## only updated when the C file list changes.
@@ -56,7 +60,7 @@ proc writeCMakeDepsFile(conf: ConfigRef) =
for it in conf.toCompile: cfiles.add(it.cname.string)
let fileset = cfiles.toCountTable()
# read old cfiles list
var fl: File
var fl: File = default(File)
var prevset = initCountTable[string]()
if open(fl, fname.string, fmRead):
for line in fl.lines: prevset.inc(line)
@@ -115,7 +119,7 @@ when not defined(leanCompiler):
setPipeLinePass(graph, Docgen2JsonPass)
of HtmlExt:
setPipeLinePass(graph, Docgen2Pass)
else: doAssert false, $ext
else: raiseAssert $ext
compilePipelineProject(graph)
proc commandCompileToC(graph: ModuleGraph) =
@@ -151,12 +155,32 @@ proc commandCompileToC(graph: ModuleGraph) =
extccomp.callCCompiler(conf)
# for now we do not support writing out a .json file with the build instructions when HCR is on
if not conf.hcrOn:
extccomp.writeJsonBuildInstructions(conf, graph.cachedFiles)
extccomp.writeJsonBuildInstructions(conf)
if optGenScript in graph.config.globalOptions:
writeDepsFile(graph)
if optGenCDeps in graph.config.globalOptions:
writeCMakeDepsFile(conf)
proc commandCompileToNir(graph: ModuleGraph) =
let conf = graph.config
extccomp.initVars(conf)
if conf.symbolFiles == disabledSf:
if {optRun, optForceFullMake} * conf.globalOptions == {optRun}:
if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile):
# nothing changed
graph.config.notes = graph.config.mainPackageNotes
return
if not extccomp.ccHasSaneOverflow(conf):
conf.symbols.defineSymbol("nimEmulateOverflowChecks")
if conf.symbolFiles == disabledSf:
setPipeLinePass(graph, NirPass)
else:
setPipeLinePass(graph, SemPass)
compilePipelineProject(graph)
writeNinjaFile(graph)
proc commandJsonScript(graph: ModuleGraph) =
extccomp.runJsonBuildInstructions(graph.config, graph.config.jsonBuildInstructionsFile)
@@ -173,13 +197,16 @@ proc commandCompileToJS(graph: ModuleGraph) =
if optGenScript in conf.globalOptions:
writeDepsFile(graph)
proc commandInteractive(graph: ModuleGraph) =
proc commandInteractive(graph: ModuleGraph; useNir: bool) =
graph.config.setErrorMaxHighMaybe
initDefines(graph.config.symbols)
defineSymbol(graph.config.symbols, "nimscript")
if useNir:
defineSymbol(graph.config.symbols, "noSignalHandler")
else:
defineSymbol(graph.config.symbols, "nimscript")
# note: seems redundant with -d:nimHasLibFFI
when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
setPipeLinePass(graph, InterpreterPass)
setPipeLinePass(graph, if useNir: NirReplPass else: InterpreterPass)
compilePipelineSystemModule(graph)
if graph.config.commandArgs.len > 0:
discard graph.compilePipelineModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
@@ -196,8 +223,7 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
if stream != nil:
var
L: Lexer
tok: Token
initToken(tok)
tok: Token = default(Token)
openLexer(L, f, stream, cache, config)
while true:
rawGetTok(L, tok)
@@ -267,7 +293,9 @@ proc mainCommand*(graph: ModuleGraph) =
# and it has added this define implictly, so we must undo that here.
# A better solution might be to fix system.nim
undefSymbol(conf.symbols, "useNimRtl")
of backendInvalid: doAssert false
of backendNir:
if conf.exc == excNone: conf.exc = excGoto
of backendInvalid: raiseAssert "unreachable"
proc compileToBackend() =
customizeForBackend(conf.backend)
@@ -277,7 +305,8 @@ proc mainCommand*(graph: ModuleGraph) =
of backendCpp: commandCompileToC(graph)
of backendObjc: commandCompileToC(graph)
of backendJs: commandCompileToJS(graph)
of backendInvalid: doAssert false
of backendNir: commandCompileToNir(graph)
of backendInvalid: raiseAssert "unreachable"
template docLikeCmd(body) =
when defined(leanCompiler):
@@ -304,7 +333,10 @@ proc mainCommand*(graph: ModuleGraph) =
## process all commands
case conf.cmd
of cmdBackends: compileToBackend()
of cmdBackends:
compileToBackend()
when BenchIC:
echoTimes graph.packed
of cmdTcc:
when hasTinyCBackend:
extccomp.setCC(conf, "tcc", unknownLineInfo)
@@ -400,6 +432,10 @@ proc mainCommand*(graph: ModuleGraph) =
for it in conf.searchPaths: msgWriteln(conf, it.string)
of cmdCheck:
commandCheck(graph)
of cmdM:
graph.config.symbolFiles = v2Sf
setUseIc(graph.config.symbolFiles != disabledSf)
commandCheck(graph)
of cmdParse:
wantMainModule(conf)
discard parseFile(conf.projectMainIdx, cache, conf)
@@ -407,7 +443,7 @@ proc mainCommand*(graph: ModuleGraph) =
wantMainModule(conf)
commandView(graph)
#msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!")
of cmdInteractive: commandInteractive(graph)
of cmdInteractive: commandInteractive(graph, isDefined(conf, "nir"))
of cmdNimscript:
if conf.projectIsCmd or conf.projectIsStdin: discard
elif not fileExists(conf.projectFull):

View File

@@ -11,11 +11,12 @@
## represents a complete Nim project. Single modules can either be kept in RAM
## or stored in a rod-file.
import std/[intsets, tables, hashes, strtabs]
import std/[intsets, tables, hashes]
import ../dist/checksums/src/checksums/md5
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
import ic / [packed_ast, ic]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -66,6 +67,8 @@ type
CgenPass
EvalPass
InterpreterPass
NirPass
NirReplPass
GenDependPass
Docgen2TexPass
Docgen2JsonPass
@@ -79,8 +82,9 @@ type
typeInstCache*: Table[ItemId, seq[LazyType]] # A symbol's ItemId.
procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId.
attachedOps*: array[TTypeAttachedOp, Table[ItemId, LazySym]] # Type ID, destructors, etc.
methodsPerType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods
memberProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached member procs (only c++, virtual and ctor so far)
methodsPerGenericType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods
memberProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached member procs (only c++, virtual,member and ctor so far).
initializersPerType*: Table[ItemId, PNode] # Type ID, AST call to the default ctor (c++ only)
enumToStringProcs*: Table[ItemId, LazySym]
emittedTypeInfo*: Table[string, FileIndex]
@@ -90,6 +94,7 @@ type
importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies
suggestMode*: bool # whether we are in nimsuggest mode or not.
invalidTransitiveClosure: bool
interactive*: bool
inclToMod*: Table[FileIndex, FileIndex] # mapping of include file to the
# first module that included it
importStack*: seq[FileIndex] # The current import stack. Used for detecting recursive
@@ -99,12 +104,18 @@ type
cache*: IdentCache
vm*: RootRef # unfortunately the 'vm' state is shared project-wise, this will
# be clarified in later compiler implementations.
repl*: RootRef # REPL state is shared project-wise.
doStopCompile*: proc(): bool {.closure.}
usageSym*: PSym # for nimsuggest
owners*: seq[PSym]
suggestSymbols*: Table[FileIndex, seq[SymInfoPair]]
suggestErrors*: Table[FileIndex, seq[Suggest]]
methods*: seq[tuple[methods: seq[PSym], dispatcher: PSym]] # needs serialization!
bucketTable*: CountTable[ItemId]
objectTree*: Table[ItemId, seq[tuple[depth: int, value: PType]]]
methodsPerType*: Table[ItemId, seq[LazySym]]
dispatchers*: seq[LazySym]
systemModule*: PSym
sysTypes*: array[TTypeKind, PType]
compilerprocs*: TStrTable
@@ -129,8 +140,6 @@ type
idgen*: IdGenerator
operators*: Operators
cachedFiles*: StringTableRef
TPassContext* = object of RootObj # the pass's context
idgen*: IdGenerator
PPassContext* = ref TPassContext
@@ -145,13 +154,15 @@ type
isFrontend: bool]
proc resetForBackend*(g: ModuleGraph) =
initStrTable(g.compilerprocs)
g.compilerprocs = initStrTable()
g.typeInstCache.clear()
g.procInstCache.clear()
for a in mitems(g.attachedOps):
a.clear()
g.methodsPerType.clear()
g.methodsPerGenericType.clear()
g.enumToStringProcs.clear()
g.dispatchers.setLen(0)
g.methodsPerType.clear()
const
cb64 = [
@@ -199,8 +210,8 @@ template semtabAll*(g: ModuleGraph, m: PSym): TStrTable =
g.ifaces[m.position].interfHidden
proc initStrTables*(g: ModuleGraph, m: PSym) =
initStrTable(semtab(g, m))
initStrTable(semtabAll(g, m))
semtab(g, m) = initStrTable()
semtabAll(g, m) = initStrTable()
proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) =
strTableAdd(semtab(g, m), s)
@@ -209,10 +220,10 @@ proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) =
proc isCachedModule(g: ModuleGraph; module: int): bool {.inline.} =
result = module < g.packed.len and g.packed[module].status == loaded
proc isCachedModule(g: ModuleGraph; m: PSym): bool {.inline.} =
proc isCachedModule*(g: ModuleGraph; m: PSym): bool {.inline.} =
isCachedModule(g, m.position)
proc simulateCachedModule*(g: ModuleGraph; moduleSym: PSym; m: PackedModule) =
proc simulateCachedModule(g: ModuleGraph; moduleSym: PSym; m: PackedModule) =
when false:
echo "simulating ", moduleSym.name.s, " ", moduleSym.position
simulateLoadedModule(g.packed, g.config, g.cache, moduleSym, m)
@@ -322,6 +333,7 @@ iterator procInstCacheItems*(g: ModuleGraph; s: PSym): PInstantiation =
for t in mitems(x[]):
yield resolveInst(g, t)
proc getAttachedOp*(g: ModuleGraph; t: PType; op: TTypeAttachedOp): PSym =
## returns the requested attached operation for type `t`. Can return nil
## if no such operation exists.
@@ -345,6 +357,27 @@ proc completePartialOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttached
toPackedGeneratedProcDef(value, g.encoders[module], g.packed[module].fromDisk)
#storeAttachedProcDef(t, op, value, g.encoders[module], g.packed[module].fromDisk)
iterator getDispatchers*(g: ModuleGraph): PSym =
for i in g.dispatchers.mitems:
yield resolveSym(g, i)
proc addDispatchers*(g: ModuleGraph, value: PSym) =
# TODO: add it for packed modules
g.dispatchers.add LazySym(sym: value)
iterator resolveLazySymSeq(g: ModuleGraph, list: var seq[LazySym]): PSym =
for it in list.mitems:
yield resolveSym(g, it)
proc setMethodsPerType*(g: ModuleGraph; id: ItemId, methods: seq[LazySym]) =
# TODO: add it for packed modules
g.methodsPerType[id] = methods
iterator getMethodsPerType*(g: ModuleGraph; t: PType): PSym =
if g.methodsPerType.contains(t.itemId):
for it in mitems g.methodsPerType[t.itemId]:
yield resolveSym(g, it)
proc getToStringProc*(g: ModuleGraph; t: PType): PSym =
result = resolveSym(g, g.enumToStringProcs[t.itemId])
assert result != nil
@@ -353,12 +386,12 @@ proc setToStringProc*(g: ModuleGraph; t: PType; value: PSym) =
g.enumToStringProcs[t.itemId] = LazySym(sym: value)
iterator methodsForGeneric*(g: ModuleGraph; t: PType): (int, PSym) =
if g.methodsPerType.contains(t.itemId):
for it in mitems g.methodsPerType[t.itemId]:
if g.methodsPerGenericType.contains(t.itemId):
for it in mitems g.methodsPerGenericType[t.itemId]:
yield (it[0], resolveSym(g, it[1]))
proc addMethodToGeneric*(g: ModuleGraph; module: int; t: PType; col: int; m: PSym) =
g.methodsPerType.mgetOrPut(t.itemId, @[]).add (col, LazySym(sym: m))
g.methodsPerGenericType.mgetOrPut(t.itemId, @[]).add (col, LazySym(sym: m))
proc hasDisabledAsgn*(g: ModuleGraph; t: PType): bool =
let op = getAttachedOp(g, t, attachedAsgn)
@@ -371,10 +404,11 @@ proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) =
setAttachedOp(g, module, dest, k, op)
proc loadCompilerProc*(g: ModuleGraph; name: string): PSym =
result = nil
if g.config.symbolFiles == disabledSf: return nil
# slow, linear search, but the results are cached:
for module in 0..high(g.packed):
for module in 0..<len(g.packed):
#if isCachedModule(g, module):
let x = searchForCompilerproc(g.packed[module], name)
if x >= 0:
@@ -431,7 +465,7 @@ proc registerModule*(g: ModuleGraph; m: PSym) =
setLen(g.ifaces, m.position + 1)
if m.position >= g.packed.len:
setLen(g.packed, m.position + 1)
setLen(g.packed.pm, m.position + 1)
g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[],
uniqueName: rope(uniqueModuleName(g.config, FileIndex(m.position))))
@@ -461,7 +495,7 @@ proc initModuleGraphFields(result: ModuleGraph) =
# A module ID of -1 means that the symbol is not attached to a module at all,
# but to the module graph:
result.idgen = IdGenerator(module: -1'i32, symId: 0'i32, typeId: 0'i32)
initStrTable(result.packageSyms)
result.packageSyms = initStrTable()
result.deps = initIntSet()
result.importDeps = initTable[FileIndex, seq[FileIndex]]()
result.ifaces = @[]
@@ -471,9 +505,9 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.suggestSymbols = initTable[FileIndex, seq[SymInfoPair]]()
result.suggestErrors = initTable[FileIndex, seq[Suggest]]()
result.methods = @[]
initStrTable(result.compilerprocs)
initStrTable(result.exposed)
initStrTable(result.packageTypes)
result.compilerprocs = initStrTable()
result.exposed = initStrTable()
result.packageTypes = initStrTable()
result.emptyNode = newNode(nkEmpty)
result.cacheSeqs = initTable[string, PNode]()
result.cacheCounters = initTable[string, BiggestInt]()
@@ -482,7 +516,6 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.symBodyHashes = initTable[int, SigHash]()
result.operators = initOperators(result)
result.emittedTypeInfo = initTable[string, FileIndex]()
result.cachedFiles = newStringTable()
proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
result = ModuleGraph()
@@ -491,7 +524,7 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
initModuleGraphFields(result)
proc resetAllModules*(g: ModuleGraph) =
initStrTable(g.packageSyms)
g.packageSyms = initStrTable()
g.deps = initIntSet()
g.ifaces = @[]
g.importStack = @[]
@@ -499,11 +532,12 @@ proc resetAllModules*(g: ModuleGraph) =
g.usageSym = nil
g.owners = @[]
g.methods = @[]
initStrTable(g.compilerprocs)
initStrTable(g.exposed)
g.compilerprocs = initStrTable()
g.exposed = initStrTable()
initModuleGraphFields(g)
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
result = nil
if fileIdx.int32 >= 0:
if isCachedModule(g, fileIdx.int32):
result = g.packed[fileIdx.int32].module
@@ -583,6 +617,7 @@ proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
if m != nil:
g.suggestSymbols.del(fileIdx)
g.suggestErrors.del(fileIdx)
g.resetForBackend
incl m.flags, sfDirty
proc unmarkAllDirty*(g: ModuleGraph) =
@@ -609,6 +644,7 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
proc needsCompilation*(g: ModuleGraph): bool =
# every module that *depends* on this file is also dirty:
result = false
for i in 0i32..<g.ifaces.len.int32:
let m = g.ifaces[i].module
if m != nil:
@@ -616,6 +652,7 @@ proc needsCompilation*(g: ModuleGraph): bool =
return true
proc needsCompilation*(g: ModuleGraph, fileIdx: FileIndex): bool =
result = false
let module = g.getModule(fileIdx)
if module != nil and g.isDirty(module):
return true
@@ -637,6 +674,8 @@ proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex;
## Returns 'nil' if the module needs to be recompiled.
if g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}:
result = moduleFromRodFile(g.packed, g.config, g.cache, fileIdx, cachedModules)
else:
result = nil
proc configComplete*(g: ModuleGraph) =
rememberStartupConfig(g.startupPackedConfig, g.config)

View File

@@ -7,9 +7,11 @@
# distribution, for details about the copyright.
#
import ast, renderer, strutils, msgs, options, idents, os, lineinfos,
import ast, renderer, msgs, options, idents, lineinfos,
pathutils
import std/[strutils, os]
proc getModuleName*(conf: ConfigRef; n: PNode): string =
# This returns a short relative module name without the nim extension
# e.g. like "system", "importer" or "somepath/module"
@@ -36,14 +38,11 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
localError(n.info, "only '/' supported with $package notation")
result = ""
else:
if n0.kind == nkIdent and n0.ident.s[0] == '/':
let modname = getModuleName(conf, n[2])
# hacky way to implement 'x / y /../ z':
result = getModuleName(conf, n1)
result.add renderTree(n0, {renderNoComments}).replace(" ")
result.add modname
else:
result = ""
let modname = getModuleName(conf, n[2])
# hacky way to implement 'x / y /../ z':
result = getModuleName(conf, n1)
result.add renderTree(n0, {renderNoComments}).replace(" ")
result.add modname
of nkPrefix:
when false:
if n[0].kind == nkIdent and n[0].ident.s == "$":

View File

@@ -14,9 +14,6 @@ import
idents, lexer, syntaxes, modulegraphs,
lineinfos, pathutils
import ../dist/checksums/src/checksums/sha1
import std/strtabs
proc resetSystemArtifacts*(g: ModuleGraph) =
magicsys.resetSysTypes(g)
@@ -45,8 +42,6 @@ proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
graph.addDep(s, fileIdx)
graph.addIncludeDep(s.position.FileIndex, fileIdx)
let path = toFullPath(graph.config, fileIdx)
graph.cachedFiles[path] = $secureHashFile(path)
proc wantMainModule*(conf: ConfigRef) =
if conf.projectFull.isEmpty:

View File

@@ -60,6 +60,22 @@ proc makeCString*(s: string): Rope =
toCChar(s[i], result)
result.add('\"')
proc makeCCharArray*(s: string): Rope =
result = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
result.add("{")
for i in 0..<s.len:
# line wrapping of string litterals in cgen'd code was a bad idea, e.g. causes: bug #16265
# It also makes reading c sources or grepping harder, for zero benefit.
# const MaxLineLength = 64
# if (i + 1) mod MaxLineLength == 0:
# res.add("\"\L\"")
if i != 0:
result.add ", "
result.add '\''
toCChar(s[i], result)
result.add '\''
result.add('}')
proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo =
result.fullPath = fullPath
#shallow(result.fullPath)
@@ -294,9 +310,11 @@ proc toColumn*(info: TLineInfo): int {.inline.} =
result = info.col
proc toFileLineCol(info: InstantiationInfo): string {.inline.} =
result = ""
result.toLocation(info.filename, info.line, info.column + ColOffset)
proc toFileLineCol*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
result = ""
result.toLocation(toMsgFilename(conf, info), info.line.int, info.col.int + ColOffset)
proc `$`*(conf: ConfigRef; info: TLineInfo): string = toFileLineCol(conf, info)
@@ -408,7 +426,7 @@ proc getMessageStr(msg: TMsgKind, arg: string): string = msgKindToString(msg) %
type TErrorHandling* = enum doNothing, doAbort, doRaise
proc log*(s: string) =
var f: File
var f: File = default(File)
if open(f, getHomeDir() / "nimsuggest.log", fmAppend):
f.writeLine(s)
close(f)
@@ -429,8 +447,7 @@ To create a stacktrace, rerun compilation with './koch temp $1 <file>', see $2 f
proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string, ignoreMsg: bool) =
if msg in fatalMsgs:
if conf.cmd == cmdIdeTools: log(s)
if conf.cmd != cmdIdeTools or msg != errFatal:
quit(conf, msg)
quit(conf, msg)
if msg >= errMin and msg <= errMax or
(msg in warnMin..hintMax and msg in conf.warningAsErrors and not ignoreMsg):
inc(conf.errorCounter)
@@ -438,11 +455,7 @@ proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string,
if conf.errorCounter >= conf.errorMax:
# only really quit when we're not in the new 'nim check --def' mode:
if conf.ideCmd == ideNone:
when defined(nimsuggest):
#we need to inform the user that something went wrong when initializing NimSuggest
raiseRecoverableError(s)
else:
quit(conf, msg)
quit(conf, msg)
elif eh == doAbort and conf.cmd != cmdIdeTools:
quit(conf, msg)
elif eh == doRaise:
@@ -507,6 +520,8 @@ proc getSurroundingSrc(conf: ConfigRef; info: TLineInfo): string =
result = "\n" & indent & $sourceLine(conf, info)
if info.col >= 0:
result.add "\n" & indent & spaces(info.col) & '^'
else:
result = ""
proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string =
let title = case msg
@@ -726,6 +741,8 @@ proc genSuccessX*(conf: ConfigRef) =
elif conf.outFile.isEmpty and conf.cmd notin {cmdJsonscript} + cmdDocLike + cmdBackends:
# for some cmd we expect a valid absOutFile
output = "unknownOutput"
elif optStdout in conf.globalOptions:
output = "stdout"
else:
output = $conf.absOutFile
if conf.filenameOption != foAbs: output = output.AbsoluteFile.extractFilename

View File

@@ -7,8 +7,8 @@
# distribution, for details about the copyright.
#
import ast, renderer, intsets, tables, msgs, options, lineinfos, strformat, idents, treetab, hashes
import sequtils, strutils, sets
import ast, renderer, msgs, options, lineinfos, idents, treetab
import std/[intsets, tables, sequtils, strutils, sets, strformat, hashes]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -309,6 +309,7 @@ proc symbol(n: PNode): Symbol =
# echo "symbol ", n, " ", n.kind, " ", result.int
func `$`(map: NilMap): string =
result = ""
var now = map
var stack: seq[NilMap] = @[]
while not now.isNil:
@@ -416,7 +417,7 @@ proc moveOut(ctx: NilCheckerContext, map: NilMap, target: PNode) =
if targetSetIndex != noSetIndex:
var targetSet = map.sets[targetSetIndex]
if targetSet.len > 1:
var other: ExprIndex
var other: ExprIndex = default(ExprIndex)
for element in targetSet:
if element.ExprIndex != targetIndex:
@@ -561,7 +562,7 @@ proc derefWarning(n, ctx, map; kind: Nilability) =
if n.info in ctx.warningLocations:
return
ctx.warningLocations.incl(n.info)
var a: seq[History]
var a: seq[History] = @[]
if n.kind == nkSym:
a = history(map, ctx.index(n))
var res = ""
@@ -765,7 +766,7 @@ proc checkIf(n, ctx, map): Check =
# the state of the conditions: negating conditions before the current one
var layerHistory = newNilMap(mapIf)
# the state after branch effects
var afterLayer: NilMap
var afterLayer: NilMap = nil
# the result nilability for expressions
var nilability = Safe
@@ -862,9 +863,10 @@ proc checkInfix(n, ctx, map): Check =
## a or b : map is an union of a and b's
## a == b : use checkCondition
## else: no change, just check args
result = default(Check)
if n[0].kind == nkSym:
var mapL: NilMap
var mapR: NilMap
var mapL: NilMap = nil
var mapR: NilMap = nil
if n[0].sym.magic notin {mAnd, mEqRef}:
mapL = checkCondition(n[1], ctx, map, false, false)
mapR = checkCondition(n[2], ctx, map, false, false)
@@ -916,7 +918,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
newSymNode(op, r.info),
l,
r)
result.typ = newType(tyBool, nextTypeId ctx.idgen, nil)
result.typ = newType(tyBool, ctx.idgen, nil)
proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
var cache = newIdentCache()
@@ -926,7 +928,7 @@ proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
result = nkPrefix.newTree(
newSymNode(op, node.info),
node)
result.typ = newType(tyBool, nextTypeId ctx.idgen, nil)
result.typ = newType(tyBool, ctx.idgen, nil)
proc infixEq(ctx: NilCheckerContext, l: PNode, r: PNode): PNode =
infix(ctx, l, r, mEqRef)
@@ -947,7 +949,7 @@ proc checkCase(n, ctx, map): Check =
let base = n[0]
result.map = map.copyMap()
result.nilability = Safe
var a: PNode
var a: PNode = nil
for child in n:
case child.kind:
of nkOfBranch:
@@ -1222,7 +1224,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check =
# TODO deeper nested elements?
# A(field: B()) #
# field: Safe ->
var elements: seq[(PNode, Nilability)]
var elements: seq[(PNode, Nilability)] = @[]
for i, child in n:
result = check(child, ctx, result.map)
if i > 0:
@@ -1333,7 +1335,7 @@ proc preVisit(ctx: NilCheckerContext, s: PSym, body: PNode, conf: ConfigRef) =
ctx.symbolIndices = {resultId: resultExprIndex}.toTable()
var cache = newIdentCache()
ctx.expressions = SeqOfDistinct[ExprIndex, PNode](@[newIdentNode(cache.getIdent("result"), s.ast.info)])
var emptySet: IntSet # set[ExprIndex]
var emptySet: IntSet = initIntSet() # set[ExprIndex]
ctx.dependants = SeqOfDistinct[ExprIndex, IntSet](@[emptySet])
for i, arg in s.typ.n.sons:
if i > 0:

View File

@@ -9,6 +9,7 @@ define:nimPreviewSlimSystem
define:nimPreviewCstringConversion
define:nimPreviewProcConversion
define:nimPreviewRangeDefault
define:nimPreviewNonVarDestructor
threads:off
#import:"$projectpath/testability"
@@ -41,5 +42,22 @@ define:useStdoutAsStdmsg
@end
@if nimHasWarnBareExcept:
warning[BareExcept]:on
warningAserror[BareExcept]:on
@end
@if nimUseStrictDefs:
experimental:strictDefs
warningAsError[Uninit]:on
warningAsError[ProveInit]:on
@end
@if nimHasWarnStdPrefix:
warning[StdPrefix]:on
warningAsError[StdPrefix]:on
@end
@if nimHasVtables:
experimental:vtables
@end

View File

@@ -28,7 +28,7 @@ import
commands, options, msgs, extccomp, main, idents, lineinfos, cmdlinehelper,
pathutils, modulegraphs
from browsers import openDefaultBrowser
from std/browsers import openDefaultBrowser
from nodejs import findNodeJs
when hasTinyCBackend:
@@ -91,6 +91,9 @@ proc getNimRunExe(conf: ConfigRef): string =
if conf.isDefined("mingw"):
if conf.isDefined("i386"): result = "wine"
elif conf.isDefined("amd64"): result = "wine64"
else: result = ""
else:
result = ""
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
let self = NimProg(
@@ -113,7 +116,8 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
conf.backend = backendC
if conf.selectedGC == gcUnselected:
if conf.backend in {backendC, backendCpp, backendObjc}:
if conf.backend in {backendC, backendCpp, backendObjc, backendNir} or
(conf.cmd == cmdInteractive and isDefined(conf, "nir")):
initOrcDefines(conf)
mainCommand(graph)
@@ -137,7 +141,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
# tasyncjs_fail` would fail, refs https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode
if cmdPrefix.len == 0: cmdPrefix = findNodeJs().quoteShell
cmdPrefix.add " --unhandled-rejections=strict"
else: doAssert false, $conf.backend
else: raiseAssert $conf.backend
if cmdPrefix.len > 0: cmdPrefix.add " "
# without the `cmdPrefix.len > 0` check, on windows you'd get a cryptic:
# `The parameter is incorrect`

View File

@@ -9,8 +9,9 @@
## Implements some helper procs for Nimble (Nim's package manager) support.
import parseutils, strutils, os, options, msgs, sequtils, lineinfos, pathutils,
tables
import options, msgs, lineinfos, pathutils
import std/[parseutils, strutils, os, tables, sequtils]
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
@@ -37,11 +38,16 @@ proc isSpecial(ver: Version): bool =
proc isValidVersion(v: string): bool =
if v.len > 0:
if v[0] in {'#'} + Digits: return true
if v[0] in {'#'} + Digits:
result = true
else:
result = false
else:
result = false
proc `<`*(ver: Version, ver2: Version): bool =
## This is synced from Nimble's version module.
result = false
# Handling for special versions such as "#head" or "#branch".
if ver.isSpecial or ver2.isSpecial:
if ver2.isSpecial and ($ver2).normalize == "#head":
@@ -145,7 +151,7 @@ proc addNimblePath(conf: ConfigRef; p: string, info: TLineInfo) =
conf.lazyPaths.insert(AbsoluteDir path, 0)
proc addPathRec(conf: ConfigRef; dir: string, info: TLineInfo) =
var packages: PackageInfo
var packages: PackageInfo = initTable[string, tuple[version, checksum: string]]()
var pos = dir.len-1
if dir[pos] in {DirSep, AltSep}: inc(pos)
for k,p in os.walkDir(dir):

View File

@@ -10,8 +10,10 @@
# This module handles the reading of the config file.
import
llstream, commands, os, strutils, msgs, lexer, ast,
options, idents, wordrecg, strtabs, lineinfos, pathutils, scriptconfig
llstream, commands, msgs, lexer, ast,
options, idents, wordrecg, lineinfos, pathutils, scriptconfig
import std/[os, strutils, strtabs]
when defined(nimPreviewSlimSystem):
import std/syncio
@@ -162,7 +164,7 @@ proc checkSymbol(L: Lexer, tok: Token) =
lexMessage(L, errGenerated, "expected identifier, but got: " & $tok)
proc parseAssignment(L: var Lexer, tok: var Token;
config: ConfigRef; condStack: var seq[bool]) =
config: ConfigRef; filename: AbsoluteFile; condStack: var seq[bool]) =
if tok.ident != nil:
if tok.ident.s == "-" or tok.ident.s == "--":
confTok(L, tok, config, condStack) # skip unnecessary prefix
@@ -205,6 +207,7 @@ proc parseAssignment(L: var Lexer, tok: var Token;
checkSymbol(L, tok)
val.add($tok)
confTok(L, tok, config, condStack)
config.currentConfigDir = parentDir(filename.string)
if percent:
processSwitch(s, strtabs.`%`(val, config.configVars,
{useEnvironment, useEmpty}), passPP, info, config)
@@ -214,20 +217,21 @@ proc parseAssignment(L: var Lexer, tok: var Token;
proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
config: ConfigRef): bool =
var
L: Lexer
L: Lexer = default(Lexer)
tok: Token
stream: PLLStream
stream = llStreamOpen(filename, fmRead)
if stream != nil:
initToken(tok)
openLexer(L, filename, stream, cache, config)
tok.tokType = tkEof # to avoid a pointless warning
var condStack: seq[bool] = @[]
confTok(L, tok, config, condStack) # read in the first token
while tok.tokType != tkEof: parseAssignment(L, tok, config, condStack)
while tok.tokType != tkEof: parseAssignment(L, tok, config, filename, condStack)
if condStack.len > 0: lexMessage(L, errGenerated, "expected @end")
closeLexer(L)
return true
else:
result = false
proc getUserConfigPath*(filename: RelativeFile): AbsoluteFile =
result = getConfigDir().AbsoluteDir / RelativeDir"nim" / filename
@@ -250,7 +254,7 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen:
template runNimScriptIfExists(path: AbsoluteFile, isMain = false) =
let p = path # eval once
var s: PLLStream
var s: PLLStream = nil
if isMain and optWasNimscript in conf.globalOptions:
if conf.projectIsStdin: s = stdin.llStreamOpen
elif conf.projectIsCmd: s = llStreamOpen(conf.cmdInput)

View File

@@ -12,8 +12,9 @@
# handling that exists! Only at line endings checks are necessary
# if the buffer needs refilling.
import
llstream, strutils
import llstream
import std/strutils
when defined(nimPreviewSlimSystem):
import std/assertions

View File

@@ -17,7 +17,7 @@ interpolation variables:
Unstable API
]##
import os, strutils
import std/[os, strutils]
when defined(nimPreviewSlimSystem):
import std/assertions

View File

@@ -62,7 +62,9 @@ proc someInSet*(s: PNode, a, b: PNode): bool =
result = false
proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet =
var first, j: Int128
result = @[]
var first: Int128 = Zero
var j: Int128 = Zero
first = firstOrd(conf, s.typ[0])
bitSetInit(result, int(getSize(conf, s.typ)))
for i in 0..<s.len:

2645
compiler/nir/ast2ir.nim Normal file

File diff suppressed because it is too large Load Diff

983
compiler/nir/cir.nim Normal file
View File

@@ -0,0 +1,983 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# We produce C code as a list of tokens.
import std / [assertions, syncio, tables, intsets, formatfloat]
from std / strutils import toOctal
import .. / ic / [bitabs, rodfiles]
import nirtypes, nirinsts, nirfiles
import ../../dist/checksums/src/checksums/md5
type
Token = LitId # indexing into the tokens BiTable[string]
PredefinedToken = enum
IgnoreMe = "<unused>"
EmptyToken = ""
CurlyLe = "{"
CurlyRi = "}"
ParLe = "("
ParRi = ")"
BracketLe = "["
BracketRi = "]"
NewLine = "\n"
Semicolon = ";"
Comma = ", "
Space = " "
Colon = ": "
Dot = "."
Arrow = "->"
Star = "*"
Amp = "&"
AsgnOpr = " = "
ScopeOpr = "::"
ConstKeyword = "const "
StaticKeyword = "static "
ExternKeyword = "extern "
WhileKeyword = "while "
IfKeyword = "if ("
ElseKeyword = "else "
SwitchKeyword = "switch "
CaseKeyword = "case "
DefaultKeyword = "default:"
BreakKeyword = "break"
NullPtr = "nullptr"
IfNot = "if (!("
ReturnKeyword = "return "
TypedefStruct = "typedef struct "
TypedefUnion = "typedef union "
IncludeKeyword = "#include "
proc fillTokenTable(tab: var BiTable[string]) =
for e in EmptyToken..high(PredefinedToken):
let id = tab.getOrIncl $e
assert id == LitId(e), $(id, " ", ord(e))
type
GeneratedCode* = object
m: NirModule
includes: seq[LitId]
includedHeaders: IntSet
data: seq[LitId]
protos: seq[LitId]
code: seq[LitId]
init: seq[LitId]
tokens: BiTable[string]
emittedStrings: IntSet
needsPrefix: IntSet
generatedTypes: IntSet
mangledModules: Table[LitId, LitId]
proc initGeneratedCode*(m: sink NirModule): GeneratedCode =
result = GeneratedCode(m: m, code: @[], tokens: initBiTable[string]())
fillTokenTable(result.tokens)
proc add*(g: var GeneratedCode; t: PredefinedToken) {.inline.} =
g.code.add Token(t)
proc add*(g: var GeneratedCode; s: string) {.inline.} =
g.code.add g.tokens.getOrIncl(s)
proc mangleModuleName(c: var GeneratedCode; key: LitId): LitId =
result = c.mangledModules.getOrDefault(key, LitId(0))
if result == LitId(0):
let u {.cursor.} = c.m.lit.strings[key]
var last = u.len - len(".nim") - 1
var start = last
while start >= 0 and u[start] != '/': dec start
var sum = getMD5(u)
sum.setLen(8)
let dest = u.substr(start+1, last) & sum
result = c.tokens.getOrIncl(dest)
c.mangledModules[key] = result
type
CppFile = object
f: File
proc write(f: var CppFile; s: string) = write(f.f, s)
proc write(f: var CppFile; c: char) = write(f.f, c)
proc writeTokenSeq(f: var CppFile; s: seq[Token]; c: GeneratedCode) =
var indent = 0
for i in 0..<s.len:
let x = s[i]
case x
of Token(CurlyLe):
inc indent
write f, c.tokens[x]
write f, "\n"
for i in 1..indent*2: write f, ' '
of Token(CurlyRi):
dec indent
write f, c.tokens[x]
if i+1 < s.len and s[i+1] == Token(CurlyRi):
discard
else:
write f, "\n"
for i in 1..indent*2: write f, ' '
of Token(Semicolon):
write f, c.tokens[x]
if i+1 < s.len and s[i+1] == Token(CurlyRi):
discard "no newline before }"
else:
write f, "\n"
for i in 1..indent*2: write f, ' '
of Token(NewLine):
write f, c.tokens[x]
for i in 1..indent*2: write f, ' '
else:
write f, c.tokens[x]
# Type graph
type
TypeList = object
processed: IntSet
s: seq[(TypeId, PredefinedToken)]
proc add(dest: var TypeList; elem: TypeId; decl: PredefinedToken) =
if not containsOrIncl(dest.processed, int(elem)):
dest.s.add (elem, decl)
type
TypeOrder = object
forwardedDecls, ordered: TypeList
typeImpls: Table[string, TypeId]
lookedAt: IntSet
proc traverseObject(types: TypeGraph; lit: Literals; c: var TypeOrder; t: TypeId)
proc recordDependency(types: TypeGraph; lit: Literals; c: var TypeOrder; parent, child: TypeId) =
var ch = child
var viaPointer = false
while true:
case types[ch].kind
of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy:
viaPointer = true
ch = elementType(types, ch)
of LastArrayTy:
ch = elementType(types, ch)
else:
break
case types[ch].kind
of ObjectTy, UnionTy:
let decl = if types[ch].kind == ObjectTy: TypedefStruct else: TypedefUnion
let obj = c.typeImpls.getOrDefault(lit.strings[types[ch].litId])
if viaPointer:
c.forwardedDecls.add obj, decl
else:
if not containsOrIncl(c.lookedAt, obj.int):
traverseObject(types, lit, c, obj)
c.ordered.add obj, decl
of ArrayTy:
if viaPointer:
c.forwardedDecls.add ch, TypedefStruct
else:
if not containsOrIncl(c.lookedAt, ch.int):
traverseObject(types, lit, c, ch)
c.ordered.add ch, TypedefStruct
else:
discard "uninteresting type as we only focus on the required struct declarations"
proc traverseObject(types: TypeGraph; lit: Literals; c: var TypeOrder; t: TypeId) =
for x in sons(types, t):
case types[x].kind
of FieldDecl:
recordDependency types, lit, c, t, x.firstSon
of ObjectTy:
# inheritance
recordDependency types, lit, c, t, x
else: discard
proc traverseTypes(types: TypeGraph; lit: Literals; c: var TypeOrder) =
for t in allTypes(types):
if types[t].kind in {ObjectDecl, UnionDecl}:
assert types[t.firstSon].kind == NameVal
c.typeImpls[lit.strings[types[t.firstSon].litId]] = t
for t in allTypesIncludingInner(types):
case types[t].kind
of ObjectDecl, UnionDecl:
traverseObject types, lit, c, t
let decl = if types[t].kind == ObjectDecl: TypedefStruct else: TypedefUnion
c.ordered.add t, decl
of ArrayTy:
traverseObject types, lit, c, t
c.ordered.add t, TypedefStruct
else: discard
when false:
template emitType(s: string) = c.types.add c.tokens.getOrIncl(s)
template emitType(t: Token) = c.types.add t
template emitType(t: PredefinedToken) = c.types.add Token(t)
proc genType(g: var GeneratedCode; types: TypeGraph; lit: Literals; t: TypeId; name = "") =
template maybeAddName =
if name != "":
g.add Space
g.add name
template atom(s: string) =
g.add s
maybeAddName()
case types[t].kind
of VoidTy: atom "void"
of IntTy: atom "NI" & $types[t].integralBits
of UIntTy: atom "NU" & $types[t].integralBits
of FloatTy: atom "NF" & $types[t].integralBits
of BoolTy: atom "NB" & $types[t].integralBits
of CharTy: atom "NC" & $types[t].integralBits
of ObjectTy, UnionTy, NameVal, AnnotationVal:
atom lit.strings[types[t].litId]
of VarargsTy:
g.add "..."
of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy:
genType g, types, lit, elementType(types, t)
g.add Star
maybeAddName()
of ArrayTy:
genType g, types, lit, arrayName(types, t)
maybeAddName()
of LastArrayTy:
genType g, types, lit, elementType(types, t)
maybeAddName()
g.add BracketLe
g.add BracketRi
of ProcTy:
let (retType, callConv) = returnType(types, t)
genType g, types, lit, retType
g.add Space
g.add ParLe
genType g, types, lit, callConv
g.add Star # "(*fn)"
maybeAddName()
g.add ParRi
g.add ParLe
var i = 0
for ch in params(types, t):
if i > 0: g.add Comma
genType g, types, lit, ch
inc i
g.add ParRi
of ObjectDecl, UnionDecl:
atom lit.strings[types[t.firstSon].litId]
of IntVal, SizeVal, AlignVal, OffsetVal, FieldDecl:
#raiseAssert "did not expect: " & $types[t].kind
g.add "BUG "
atom $types[t].kind
proc generateTypes(g: var GeneratedCode; types: TypeGraph; lit: Literals; c: TypeOrder) =
for (t, declKeyword) in c.forwardedDecls.s:
let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon
let s {.cursor.} = lit.strings[types[name].litId]
g.add declKeyword
g.add s
g.add Space
g.add s
g.add Semicolon
for (t, declKeyword) in c.ordered.s:
let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon
let litId = types[name].litId
if not g.generatedTypes.containsOrIncl(litId.int):
let s {.cursor.} = lit.strings[litId]
g.add declKeyword
g.add CurlyLe
if types[t].kind == ArrayTy:
genType g, types, lit, elementType(types, t), "a"
g.add BracketLe
g.add $arrayLen(types, t)
g.add BracketRi
g.add Semicolon
else:
var i = 0
for x in sons(types, t):
case types[x].kind
of FieldDecl:
genType g, types, lit, x.firstSon, "F" & $i
g.add Semicolon
inc i
of ObjectTy:
genType g, types, lit, x, "P"
g.add Semicolon
else: discard
g.add CurlyRi
g.add s
g.add Semicolon
# Procs
proc toCChar*(c: char; result: var string) {.inline.} =
case c
of '\0'..'\x1F', '\x7F'..'\xFF':
result.add '\\'
result.add toOctal(c)
of '\'', '\"', '\\', '?':
result.add '\\'
result.add c
else:
result.add c
proc makeCString(s: string): string =
result = newStringOfCap(s.len + 10)
result.add('"')
for c in s: toCChar(c, result)
result.add('"')
template emitData(s: string) = c.data.add c.tokens.getOrIncl(s)
template emitData(t: Token) = c.data.add t
template emitData(t: PredefinedToken) = c.data.add Token(t)
proc genStrLit(c: var GeneratedCode; lit: Literals; litId: LitId): Token =
result = Token(c.tokens.getOrIncl "QStr" & $litId)
if not containsOrIncl(c.emittedStrings, int(litId)):
let s {.cursor.} = lit.strings[litId]
emitData "static const struct "
emitData CurlyLe
emitData "NI cap"
emitData Semicolon
emitData "NC8 data"
emitData BracketLe
emitData $s.len
emitData "+1"
emitData BracketRi
emitData Semicolon
emitData CurlyRi
emitData result
emitData AsgnOpr
emitData CurlyLe
emitData $s.len
emitData " | NIM_STRLIT_FLAG"
emitData Comma
emitData makeCString(s)
emitData CurlyRi
emitData Semicolon
proc genIntLit(c: var GeneratedCode; lit: Literals; litId: LitId) =
let i = lit.numbers[litId]
if i > low(int32) and i <= high(int32):
c.add $i
elif i == low(int32):
# Nim has the same bug for the same reasons :-)
c.add "(-2147483647 -1)"
elif i > low(int64):
c.add "IL64("
c.add $i
c.add ")"
else:
c.add "(IL64(-9223372036854775807) - IL64(1))"
proc gen(c: var GeneratedCode; t: Tree; n: NodePos)
proc genDisplayName(c: var GeneratedCode; symId: SymId) =
let displayName = c.m.symnames[symId]
if displayName != LitId(0):
c.add "/*"
c.add c.m.lit.strings[displayName]
c.add "*/"
proc genSymDef(c: var GeneratedCode; t: Tree; n: NodePos) =
if t[n].kind == SymDef:
let symId = t[n].symId
c.needsPrefix.incl symId.int
genDisplayName c, symId
gen c, t, n
proc genGlobal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) =
c.add annotation
let m: string
if t[name].kind == SymDef:
let symId = t[name].symId
m = c.tokens[mangleModuleName(c, c.m.namespace)] & "__" & $symId
genDisplayName c, symId
else:
assert t[name].kind == ModuleSymUse
let (x, y) = sons2(t, name)
m = c.tokens[mangleModuleName(c, t[x].litId)] & "__" & $t[y].immediateVal
genType c, c.m.types, c.m.lit, t[typ].typeId, m
proc genLocal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) =
assert t[name].kind == SymDef
c.add annotation
let symId = t[name].symId
genType c, c.m.types, c.m.lit, t[typ].typeId, "q" & $symId
genDisplayName c, symId
proc genProcDecl(c: var GeneratedCode; t: Tree; n: NodePos; isExtern: bool) =
let signatureBegin = c.code.len
let name = n.firstSon
var prc = n.firstSon
next t, prc
while true:
case t[prc].kind
of PragmaPair:
let (x, y) = sons2(t, prc)
let key = cast[PragmaKey](t[x].rawOperand)
case key
of HeaderImport:
let lit = t[y].litId
let headerAsStr {.cursor.} = c.m.lit.strings[lit]
let header = c.tokens.getOrIncl(headerAsStr)
# headerAsStr can be empty, this has the semantics of the `nodecl` pragma:
if headerAsStr.len > 0 and not c.includedHeaders.containsOrIncl(int header):
if headerAsStr[0] == '#':
discard "skip the #include"
else:
c.includes.add Token(IncludeKeyword)
c.includes.add header
c.includes.add Token NewLine
# do not generate code for importc'ed procs:
return
of DllImport:
let lit = t[y].litId
raiseAssert "cannot eval: " & c.m.lit.strings[lit]
else: discard
of PragmaId: discard
else: break
next t, prc
var resultDeclPos = NodePos(-1)
if t[prc].kind == SummonResult:
resultDeclPos = prc
gen c, t, prc.firstSon
next t, prc
else:
c.add "void"
c.add Space
genSymDef c, t, name
c.add ParLe
var params = 0
while t[prc].kind == SummonParam:
if params > 0: c.add Comma
let (typ, sym) = sons2(t, prc)
genLocal c, t, sym, typ, ""
next t, prc
inc params
if params == 0:
c.add "void"
c.add ParRi
for i in signatureBegin ..< c.code.len:
c.protos.add c.code[i]
c.protos.add Token Semicolon
if isExtern:
c.code.setLen signatureBegin
else:
c.add CurlyLe
if resultDeclPos.int >= 0:
gen c, t, resultDeclPos
for ch in sonsRest(t, n, prc):
gen c, t, ch
c.add CurlyRi
template triop(opr) =
let (typ, a, b) = sons3(t, n)
c.add ParLe
c.add ParLe
gen c, t, typ
c.add ParRi
gen c, t, a
c.add opr
gen c, t, b
c.add ParRi
template cmpop(opr) =
let (_, a, b) = sons3(t, n)
c.add ParLe
gen c, t, a
c.add opr
gen c, t, b
c.add ParRi
template binaryop(opr) =
let (typ, a) = sons2(t, n)
c.add ParLe
c.add ParLe
gen c, t, typ
c.add ParRi
c.add opr
gen c, t, a
c.add ParRi
template checkedBinaryop(opr) =
let (typ, labIdx, a, b) = sons4(t, n)
let bits = integralBits(c.m.types[t[typ].typeId])
let lab = t[labIdx].label
c.add (opr & $bits)
c.add ParLe
c.gen t, a
c.add Comma
c.gen t, b
c.add Comma
c.add "L" & $lab.int
c.add ParRi
proc genNumberConv(c: var GeneratedCode; t: Tree; n: NodePos) =
let (typ, arg) = sons2(t, n)
if t[arg].kind == IntVal:
let litId = t[arg].litId
c.add ParLe
c.add ParLe
gen c, t, typ
c.add ParRi
case c.m.types[t[typ].typeId].kind
of UIntTy:
let x = cast[uint64](c.m.lit.numbers[litId])
c.add $x
of FloatTy:
let x = cast[float64](c.m.lit.numbers[litId])
c.add $x
else:
gen c, t, arg
c.add ParRi
else:
binaryop ""
template moveToDataSection(body: untyped) =
let oldLen = c.code.len
body
for i in oldLen ..< c.code.len:
c.data.add c.code[i]
setLen c.code, oldLen
proc gen(c: var GeneratedCode; t: Tree; n: NodePos) =
case t[n].kind
of Nop:
discard "nothing to emit"
of ImmediateVal:
c.add $t[n].immediateVal
of IntVal:
genIntLit c, c.m.lit, t[n].litId
of StrVal:
c.code.add genStrLit(c, c.m.lit, t[n].litId)
of Typed:
genType c, c.m.types, c.m.lit, t[n].typeId
of SymDef, SymUse:
let s = t[n].symId
if c.needsPrefix.contains(s.int):
c.code.add mangleModuleName(c, c.m.namespace)
c.add "__"
c.add $s
else:
# XXX Use proper names here
c.add "q"
c.add $s
of ModuleSymUse:
let (x, y) = sons2(t, n)
let u = mangleModuleName(c, t[x].litId)
let s = t[y].immediateVal
c.code.add u
c.add "__"
c.add $s
of NilVal:
c.add NullPtr
of LoopLabel:
c.add WhileKeyword
c.add ParLe
c.add "1"
c.add ParRi
c.add CurlyLe
of GotoLoop:
c.add CurlyRi
of Label:
let lab = t[n].label
c.add "L"
c.add $lab.int
c.add Colon
c.add Semicolon
of Goto:
let lab = t[n].label
c.add "goto L"
c.add $lab.int
c.add Semicolon
of CheckedGoto:
discard "XXX todo"
of ArrayConstr:
c.add CurlyLe
c.add ".a = "
c.add CurlyLe
var i = 0
for ch in sonsFrom1(t, n):
if i > 0: c.add Comma
c.gen t, ch
inc i
c.add CurlyRi
c.add CurlyRi
of ObjConstr:
c.add CurlyLe
var i = 0
for ch in sonsFrom1(t, n):
if i mod 2 == 0:
if i > 0: c.add Comma
c.add ".F" & $t[ch].immediateVal
c.add AsgnOpr
else:
c.gen t, ch
inc i
c.add CurlyRi
of Ret:
c.add ReturnKeyword
c.gen t, n.firstSon
c.add Semicolon
of Select:
c.add SwitchKeyword
c.add ParLe
let (_, selector) = sons2(t, n)
c.gen t, selector
c.add ParRi
c.add CurlyLe
for ch in sonsFromN(t, n, 2):
c.gen t, ch
c.add CurlyRi
of SelectPair:
let (le, ri) = sons2(t, n)
c.gen t, le
c.gen t, ri
of SelectList:
for ch in sons(t, n):
c.gen t, ch
of SelectValue:
c.add CaseKeyword
c.gen t, n.firstSon
c.add Colon
of SelectRange:
let (le, ri) = sons2(t, n)
c.add CaseKeyword
c.gen t, le
c.add " ... "
c.gen t, ri
c.add Colon
of ForeignDecl:
c.data.add LitId(ExternKeyword)
c.gen t, n.firstSon
of SummonGlobal:
moveToDataSection:
let (typ, sym) = sons2(t, n)
c.genGlobal t, sym, typ, ""
c.add Semicolon
of SummonThreadLocal:
moveToDataSection:
let (typ, sym) = sons2(t, n)
c.genGlobal t, sym, typ, "__thread "
c.add Semicolon
of SummonConst:
moveToDataSection:
let (typ, sym, val) = sons3(t, n)
c.genGlobal t, sym, typ, "const "
c.add AsgnOpr
c.gen t, val
c.add Semicolon
of Summon, SummonResult:
let (typ, sym) = sons2(t, n)
c.genLocal t, sym, typ, ""
c.add Semicolon
of SummonParam:
raiseAssert "SummonParam should have been handled in genProc"
of Kill:
discard "we don't care about Kill instructions"
of AddrOf:
let (_, arg) = sons2(t, n)
c.add "&"
gen c, t, arg
of DerefArrayAt:
let (_, a, i) = sons3(t, n)
gen c, t, a
c.add BracketLe
gen c, t, i
c.add BracketRi
of ArrayAt:
let (_, a, i) = sons3(t, n)
gen c, t, a
c.add Dot
c.add "a"
c.add BracketLe
gen c, t, i
c.add BracketRi
of FieldAt:
let (_, a, b) = sons3(t, n)
gen c, t, a
let field = t[b].immediateVal
c.add Dot
c.add "F" & $field
of DerefFieldAt:
let (_, a, b) = sons3(t, n)
gen c, t, a
let field = t[b].immediateVal
c.add Arrow
c.add "F" & $field
of Load:
let (_, arg) = sons2(t, n)
c.add ParLe
c.add "*"
gen c, t, arg
c.add ParRi
of Store:
raiseAssert "Assumption was that Store is unused!"
of Asgn:
let (_, dest, src) = sons3(t, n)
gen c, t, dest
c.add AsgnOpr
gen c, t, src
c.add Semicolon
of CheckedRange:
c.add "nimCheckRange"
c.add ParLe
let (_, gotoInstr, x, a, b) = sons5(t, n)
gen c, t, x
c.add Comma
gen c, t, a
c.add Comma
gen c, t, b
c.add Comma
c.add "L" & $t[gotoInstr].label.int
c.add ParRi
of CheckedIndex:
c.add "nimCheckIndex"
c.add ParLe
let (gotoInstr, x, a) = sons3(t, n)
gen c, t, x
c.add Comma
gen c, t, a
c.add Comma
c.add "L" & $t[gotoInstr].label.int
c.add ParRi
of Call, IndirectCall:
let (typ, fn) = sons2(t, n)
gen c, t, fn
c.add ParLe
var i = 0
for ch in sonsFromN(t, n, 2):
if i > 0: c.add Comma
gen c, t, ch
inc i
c.add ParRi
if c.m.types[t[typ].typeId].kind == VoidTy:
c.add Semicolon
of CheckedCall, CheckedIndirectCall:
let (typ, gotoInstr, fn) = sons3(t, n)
gen c, t, fn
c.add ParLe
var i = 0
for ch in sonsFromN(t, n, 3):
if i > 0: c.add Comma
gen c, t, ch
inc i
c.add ParRi
if c.m.types[t[typ].typeId].kind == VoidTy:
c.add Semicolon
of CheckedAdd: checkedBinaryop "nimAddInt"
of CheckedSub: checkedBinaryop "nimSubInt"
of CheckedMul: checkedBinaryop "nimMulInt"
of CheckedDiv: checkedBinaryop "nimDivInt"
of CheckedMod: checkedBinaryop "nimModInt"
of Add: triop " + "
of Sub: triop " - "
of Mul: triop " * "
of Div: triop " / "
of Mod: triop " % "
of BitShl: triop " << "
of BitShr: triop " >> "
of BitAnd: triop " & "
of BitOr: triop " | "
of BitXor: triop " ^ "
of BitNot: binaryop " ~ "
of BoolNot: binaryop " !"
of Eq: cmpop " == "
of Le: cmpop " <= "
of Lt: cmpop " < "
of Cast: binaryop ""
of NumberConv: genNumberConv c, t, n
of CheckedObjConv: binaryop ""
of ObjConv: binaryop ""
of Emit: raiseAssert "cannot interpret: Emit"
of ProcDecl: genProcDecl c, t, n, false
of ForeignProcDecl: genProcDecl c, t, n, true
of PragmaPair, PragmaId, TestOf, Yld, SetExc, TestExc:
c.add "cannot interpret: " & $t[n].kind
const
Prelude = """
/* GENERATED CODE. DO NOT EDIT. */
#ifdef __cplusplus
#define NB8 bool
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901)
// see #13798: to avoid conflicts for code emitting `#include <stdbool.h>`
#define NB8 _Bool
#else
typedef unsigned char NB8; // best effort
#endif
typedef unsigned char NC8;
typedef float NF32;
typedef double NF64;
#if defined(__BORLANDC__) || defined(_MSC_VER)
typedef signed char NI8;
typedef signed short int NI16;
typedef signed int NI32;
typedef __int64 NI64;
/* XXX: Float128? */
typedef unsigned char NU8;
typedef unsigned short int NU16;
typedef unsigned int NU32;
typedef unsigned __int64 NU64;
#elif defined(HAVE_STDINT_H)
#ifndef USE_NIM_NAMESPACE
# include <stdint.h>
#endif
typedef int8_t NI8;
typedef int16_t NI16;
typedef int32_t NI32;
typedef int64_t NI64;
typedef uint8_t NU8;
typedef uint16_t NU16;
typedef uint32_t NU32;
typedef uint64_t NU64;
#elif defined(HAVE_CSTDINT)
#ifndef USE_NIM_NAMESPACE
# include <cstdint>
#endif
typedef std::int8_t NI8;
typedef std::int16_t NI16;
typedef std::int32_t NI32;
typedef std::int64_t NI64;
typedef std::uint8_t NU8;
typedef std::uint16_t NU16;
typedef std::uint32_t NU32;
typedef std::uint64_t NU64;
#else
/* Unknown compiler/version, do our best */
#ifdef __INT8_TYPE__
typedef __INT8_TYPE__ NI8;
#else
typedef signed char NI8;
#endif
#ifdef __INT16_TYPE__
typedef __INT16_TYPE__ NI16;
#else
typedef signed short int NI16;
#endif
#ifdef __INT32_TYPE__
typedef __INT32_TYPE__ NI32;
#else
typedef signed int NI32;
#endif
#ifdef __INT64_TYPE__
typedef __INT64_TYPE__ NI64;
#else
typedef long long int NI64;
#endif
/* XXX: Float128? */
#ifdef __UINT8_TYPE__
typedef __UINT8_TYPE__ NU8;
#else
typedef unsigned char NU8;
#endif
#ifdef __UINT16_TYPE__
typedef __UINT16_TYPE__ NU16;
#else
typedef unsigned short int NU16;
#endif
#ifdef __UINT32_TYPE__
typedef __UINT32_TYPE__ NU32;
#else
typedef unsigned int NU32;
#endif
#ifdef __UINT64_TYPE__
typedef __UINT64_TYPE__ NU64;
#else
typedef unsigned long long int NU64;
#endif
#endif
#ifdef NIM_INTBITS
# if NIM_INTBITS == 64
typedef NI64 NI;
typedef NU64 NU;
# elif NIM_INTBITS == 32
typedef NI32 NI;
typedef NU32 NU;
# elif NIM_INTBITS == 16
typedef NI16 NI;
typedef NU16 NU;
# elif NIM_INTBITS == 8
typedef NI8 NI;
typedef NU8 NU;
# else
# error "invalid bit width for int"
# endif
#endif
#define NIM_STRLIT_FLAG ((NU)(1) << ((NIM_INTBITS) - 2)) /* This has to be the same as system.strlitFlag! */
#define nimAddInt64(a, b, L) ({long long int res; if(__builtin_saddll_overflow(a, b, &res)) goto L; res})
#define nimSubInt64(a, b, L) ({long long int res; if(__builtin_ssubll_overflow(a, b, &res)) goto L; res})
#define nimMulInt64(a, b, L) ({long long int res; if(__builtin_smulll_overflow(a, b, &res)) goto L; res})
#define nimAddInt32(a, b, L) ({long int res; if(__builtin_sadd_overflow(a, b, &res)) goto L; res})
#define nimSubInt32(a, b, L) ({long int res; if(__builtin_ssub_overflow(a, b, &res)) goto L; res})
#define nimMulInt32(a, b, L) ({long int res; if(__builtin_smul_overflow(a, b, &res)) goto L; res})
#define nimCheckRange(x, a, b, L) ({if (x < a || x > b) goto L; x})
#define nimCheckIndex(x, a, L) ({if (x >= a) goto L; x})
"""
proc traverseCode(c: var GeneratedCode) =
const AllowedInToplevelC = {SummonConst, SummonGlobal, SummonThreadLocal,
ProcDecl, ForeignDecl, ForeignProcDecl}
var i = NodePos(0)
while i.int < c.m.code.len:
let oldLen = c.code.len
let moveToInitSection = c.m.code[NodePos(i)].kind notin AllowedInToplevelC
gen c, c.m.code, NodePos(i)
next c.m.code, i
if moveToInitSection:
for i in oldLen ..< c.code.len:
c.init.add c.code[i]
setLen c.code, oldLen
proc generateCode*(inp, outp: string) =
var c = initGeneratedCode(load(inp))
var co = TypeOrder()
traverseTypes(c.m.types, c.m.lit, co)
generateTypes(c, c.m.types, c.m.lit, co)
let typeDecls = move c.code
traverseCode c
var f = CppFile(f: open(outp, fmWrite))
f.write "#define NIM_INTBITS " & $c.m.intbits & "\n"
f.write Prelude
writeTokenSeq f, c.includes, c
writeTokenSeq f, typeDecls, c
writeTokenSeq f, c.data, c
writeTokenSeq f, c.protos, c
writeTokenSeq f, c.code, c
if c.init.len > 0:
f.write "void __attribute__((constructor)) init(void) {"
writeTokenSeq f, c.init, c
f.write "}\n\n"
f.f.close

105
compiler/nir/nir.nim Normal file
View File

@@ -0,0 +1,105 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nim Intermediate Representation, designed to capture all of Nim's semantics without losing too much
## precious information. Can easily be translated into C. And to JavaScript, hopefully.
from std/os import addFileExt, `/`, createDir
import std / assertions
import ".." / [ast, modulegraphs, renderer, transf, options, msgs, lineinfos]
import nirtypes, nirinsts, ast2ir, nirlineinfos, nirfiles, nirvm
import ".." / ic / [rodfiles, bitabs]
type
PCtx* = ref object of TPassContext
m: ModuleCon
c: ProcCon
oldErrorCount: int
bytecode: Bytecode
proc newCtx*(module: PSym; g: ModuleGraph; idgen: IdGenerator): PCtx =
var lit = Literals()
var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit)
var m = initModuleCon(g, g.config, idgen, module, nirm)
m.noModularity = true
PCtx(m: m, c: initProcCon(m, nil, g.config), idgen: idgen, bytecode: initBytecode(nirm))
proc refresh*(c: PCtx; module: PSym; idgen: IdGenerator) =
#c.m = initModuleCon(c.m.graph, c.m.graph.config, idgen, module, c.m.nirm)
#c.m.noModularity = true
c.c = initProcCon(c.m, nil, c.m.graph.config)
c.idgen = idgen
proc setupGlobalCtx*(module: PSym; graph: ModuleGraph; idgen: IdGenerator) =
if graph.repl.isNil:
graph.repl = newCtx(module, graph, idgen)
#registerAdditionalOps(PCtx graph.repl)
else:
refresh(PCtx graph.repl, module, idgen)
proc setupNirReplGen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
setupGlobalCtx(module, graph, idgen)
result = PCtx graph.repl
proc evalStmt(c: PCtx; n: PNode) =
let n = transformExpr(c.m.graph, c.idgen, c.m.module, n)
let pc = genStmt(c.c, n)
#var res = ""
#toString c.m.nirm.code, NodePos(pc), c.m.nirm.lit.strings, c.m.nirm.lit.numbers, c.m.symnames, res
#res.add "\n--------------------------\n"
#toString res, c.m.types.g
if pc.int < c.m.nirm.code.len:
c.bytecode.interactive = c.m.graph.interactive
execCode c.bytecode, c.m.nirm.code, pc
#echo res
proc runCode*(c: PPassContext; n: PNode): PNode =
let c = PCtx(c)
# don't eval errornous code:
if c.oldErrorCount == c.m.graph.config.errorCounter:
evalStmt(c, n)
result = newNodeI(nkEmpty, n.info)
else:
result = n
c.oldErrorCount = c.m.graph.config.errorCounter
type
NirPassContext* = ref object of TPassContext
m: ModuleCon
c: ProcCon
proc openNirBackend*(g: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
var lit = Literals()
var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit)
let m = initModuleCon(g, g.config, idgen, module, nirm)
NirPassContext(m: m, c: initProcCon(m, nil, g.config), idgen: idgen)
proc gen(c: NirPassContext; n: PNode) =
let n = transformExpr(c.m.graph, c.idgen, c.m.module, n)
let pc = genStmt(c.c, n)
proc nirBackend*(c: PPassContext; n: PNode): PNode =
gen(NirPassContext(c), n)
result = n
proc closeNirBackend*(c: PPassContext; finalNode: PNode) =
discard nirBackend(c, finalNode)
let c = NirPassContext(c)
let nimcache = getNimcacheDir(c.c.config).string
createDir nimcache
let outp = nimcache / c.m.module.name.s.addFileExt("nir")
#c.m.nirm.code = move c.c.code
try:
store c.m.nirm[], outp
echo "created: ", outp
except IOError:
rawMessage(c.c.config, errFatal, "serialization failed: " & outp)

52
compiler/nir/nirc.nim Normal file
View File

@@ -0,0 +1,52 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nir Compiler.
import ".." / ic / [bitabs, rodfiles]
import nirinsts, nirtypes, nirlineinfos, nirfiles, cir
proc view(filename: string) =
let m = load(filename)
var res = ""
allTreesToString m.code, m.lit.strings, m.lit.numbers, m.symnames, res
res.add "\n# TYPES\n"
nirtypes.toString res, m.types
echo res
import std / [syncio, parseopt]
proc writeHelp =
echo """Usage: nirc view|c <file.nir>"""
quit 0
proc main =
var inp = ""
var cmd = ""
for kind, key, val in getopt():
case kind
of cmdArgument:
if cmd.len == 0: cmd = key
elif inp.len == 0: inp = key
else: quit "Error: too many arguments"
of cmdLongOption, cmdShortOption:
case key
of "help", "h": writeHelp()
of "version", "v": stdout.write "1.0\n"
of cmdEnd: discard
if inp.len == 0:
quit "Error: no input file specified"
case cmd
of "", "view":
view inp
of "c":
let outp = inp & ".c"
cir.generateCode inp, outp
main()

83
compiler/nir/nirfiles.nim Normal file
View File

@@ -0,0 +1,83 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import ".." / ic / [bitabs, rodfiles]
import nirinsts, nirtypes, nirlineinfos
type
NirModule* = object
code*: Tree
man*: LineInfoManager
types*: TypeGraph
lit*: Literals
namespace*: LitId
intbits*: uint32
symnames*: SymNames
proc load*(filename: string): NirModule =
let lit = Literals()
result = NirModule(lit: lit, types: initTypeGraph(lit))
var r = rodfiles.open(filename)
try:
r.loadHeader(nirCookie)
r.loadSection stringsSection
r.load result.lit.strings
r.loadSection numbersSection
r.load result.lit.numbers
r.loadSection bodiesSection
r.load result.code
r.loadSection typesSection
r.load result.types
r.loadSection sideChannelSection
r.load result.man
r.loadSection namespaceSection
r.loadPrim result.namespace
r.loadPrim result.intbits
r.loadSection symnamesSection
r.load result.symnames
finally:
r.close()
proc store*(m: NirModule; outp: string) =
var r = rodfiles.create(outp)
try:
r.storeHeader(nirCookie)
r.storeSection stringsSection
r.store m.lit.strings
r.storeSection numbersSection
r.store m.lit.numbers
r.storeSection bodiesSection
r.store m.code
r.storeSection typesSection
r.store m.types
r.storeSection sideChannelSection
r.store m.man
r.storeSection namespaceSection
r.storePrim m.namespace
r.storePrim m.intbits
r.storeSection symnamesSection
r.store m.symnames
finally:
r.close()
if r.err != ok:
raise newException(IOError, "could store into: " & outp)

582
compiler/nir/nirinsts.nim Normal file
View File

@@ -0,0 +1,582 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## NIR instructions. Somewhat inspired by LLVM's instructions.
import std / [assertions, hashes]
import .. / ic / [bitabs, rodfiles]
import nirlineinfos, nirtypes
const
NirVersion = 1
nirCookie* = [byte(0), byte('N'), byte('I'), byte('R'),
byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(NirVersion)]
type
SymId* = distinct int
proc `$`*(s: SymId): string {.borrow.}
proc hash*(s: SymId): Hash {.borrow.}
proc `==`*(a, b: SymId): bool {.borrow.}
type
Opcode* = enum
Nop,
ImmediateVal,
IntVal,
StrVal,
SymDef,
SymUse,
Typed, # with type ID
PragmaId, # with Pragma ID, possible values: see PragmaKey enum
NilVal,
Label,
Goto,
CheckedGoto,
LoopLabel,
GotoLoop, # last atom
ModuleSymUse, # `"module".x`
ArrayConstr,
ObjConstr,
Ret,
Yld,
Select,
SelectPair, # ((values...), Label)
SelectList, # (values...)
SelectValue, # (value)
SelectRange, # (valueA..valueB)
ForeignDecl, # Can wrap SummonGlobal, SummonThreadLocal, SummonConst
SummonGlobal,
SummonThreadLocal,
Summon, # x = Summon Typed <Type ID>; x begins to live
SummonResult,
SummonParam,
SummonConst,
Kill, # `Kill x`: scope end for `x`
AddrOf,
ArrayAt, # a[i]
DerefArrayAt, # a[i] where `a` is a PtrArray; `a[][i]`
FieldAt, # obj.field
DerefFieldAt, # obj[].field
Load, # a[]
Store, # a[] = b
Asgn, # a = b
SetExc,
TestExc,
CheckedRange,
CheckedIndex,
Call,
IndirectCall,
CheckedCall, # call that can raise
CheckedIndirectCall, # call that can raise
CheckedAdd, # with overflow checking etc.
CheckedSub,
CheckedMul,
CheckedDiv,
CheckedMod,
Add,
Sub,
Mul,
Div,
Mod,
BitShl,
BitShr,
BitAnd,
BitOr,
BitXor,
BitNot,
BoolNot,
Eq,
Le,
Lt,
Cast,
NumberConv,
CheckedObjConv,
ObjConv,
TestOf,
Emit,
ProcDecl,
ForeignProcDecl,
PragmaPair
type
PragmaKey* = enum
FastCall, StdCall, CDeclCall, SafeCall, SysCall, InlineCall, NoinlineCall, ThisCall, NoCall,
CoreName,
ExternName,
HeaderImport,
DllImport,
DllExport,
ObjExport
const
LastAtomicValue = GotoLoop
OpcodeBits = 8'u32
OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32
ValueProducingAtoms = {ImmediateVal, IntVal, StrVal, SymUse, NilVal}
ValueProducing* = {
ImmediateVal,
IntVal,
StrVal,
SymUse,
NilVal,
ModuleSymUse,
ArrayConstr,
ObjConstr,
CheckedAdd,
CheckedSub,
CheckedMul,
CheckedDiv,
CheckedMod,
Add,
Sub,
Mul,
Div,
Mod,
BitShl,
BitShr,
BitAnd,
BitOr,
BitXor,
BitNot,
BoolNot,
Eq,
Le,
Lt,
Cast,
NumberConv,
CheckedObjConv,
ObjConv,
AddrOf,
Load,
ArrayAt,
DerefArrayAt,
FieldAt,
DerefFieldAt,
TestOf
}
type
Instr* = object # 8 bytes
x: uint32
info*: PackedLineInfo
template kind*(n: Instr): Opcode = Opcode(n.x and OpcodeMask)
template operand(n: Instr): uint32 = (n.x shr OpcodeBits)
template rawOperand*(n: Instr): uint32 = (n.x shr OpcodeBits)
template toX(k: Opcode; operand: uint32): uint32 =
uint32(k) or (operand shl OpcodeBits)
template toX(k: Opcode; operand: LitId): uint32 =
uint32(k) or (operand.uint32 shl OpcodeBits)
type
Tree* = object
nodes: seq[Instr]
Values* = object
numbers: BiTable[int64]
strings: BiTable[string]
type
PatchPos* = distinct int
NodePos* = distinct int
const
InvalidPatchPos* = PatchPos(-1)
proc isValid(p: PatchPos): bool {.inline.} = p.int != -1
proc prepare*(tree: var Tree; info: PackedLineInfo; kind: Opcode): PatchPos =
result = PatchPos tree.nodes.len
tree.nodes.add Instr(x: toX(kind, 1'u32), info: info)
proc isAtom(tree: Tree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
proc isAtom(tree: Tree; pos: NodePos): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
proc patch*(tree: var Tree; pos: PatchPos) =
let pos = pos.int
let k = tree.nodes[pos].kind
assert k > LastAtomicValue
let distance = int32(tree.nodes.len - pos)
assert distance > 0
tree.nodes[pos].x = toX(k, cast[uint32](distance))
template build*(tree: var Tree; info: PackedLineInfo; kind: Opcode; body: untyped) =
let pos = prepare(tree, info, kind)
body
patch(tree, pos)
template buildTyped*(tree: var Tree; info: PackedLineInfo; kind: Opcode; typ: TypeId; body: untyped) =
let pos = prepare(tree, info, kind)
tree.addTyped info, typ
body
patch(tree, pos)
proc len*(tree: Tree): int {.inline.} = tree.nodes.len
template rawSpan(n: Instr): int = int(operand(n))
proc nextChild(tree: Tree; pos: var int) {.inline.} =
if tree.nodes[pos].kind > LastAtomicValue:
assert tree.nodes[pos].operand > 0'u32
inc pos, tree.nodes[pos].rawSpan
else:
inc pos
proc next*(tree: Tree; pos: var NodePos) {.inline.} = nextChild tree, int(pos)
template firstSon*(n: NodePos): NodePos = NodePos(n.int+1)
template skipTyped*(n: NodePos): NodePos = NodePos(n.int+2)
iterator sons*(tree: Tree; n: NodePos): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last:
yield NodePos pos
nextChild tree, pos
iterator sonsFrom1*(tree: Tree; n: NodePos): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
nextChild tree, pos
while pos < last:
yield NodePos pos
nextChild tree, pos
iterator sonsFromN*(tree: Tree; n: NodePos; toSkip = 2): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
for i in 1..toSkip:
nextChild tree, pos
while pos < last:
yield NodePos pos
nextChild tree, pos
template `[]`*(t: Tree; n: NodePos): Instr = t.nodes[n.int]
iterator sonsRest*(tree: Tree; parent, n: NodePos): NodePos =
var pos = n.int
assert tree[parent].kind > LastAtomicValue
let last = parent.int + tree[parent].rawSpan
while pos < last:
yield NodePos pos
nextChild tree, pos
proc span(tree: Tree; pos: int): int {.inline.} =
if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
proc copyTree*(dest: var Tree; src: Tree) =
let pos = 0
let L = span(src, pos)
let d = dest.nodes.len
dest.nodes.setLen(d + L)
assert L > 0
for i in 0..<L:
dest.nodes[d+i] = src.nodes[pos+i]
proc sons2*(tree: Tree; n: NodePos): (NodePos, NodePos) {.inline.} =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
result = (NodePos a, NodePos b)
proc sons3*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos) {.inline.} =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
let c = b + span(tree, b)
result = (NodePos a, NodePos b, NodePos c)
proc sons4*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos, NodePos) {.inline.} =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
let c = b + span(tree, b)
let d = c + span(tree, c)
result = (NodePos a, NodePos b, NodePos c, NodePos d)
proc sons5*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos, NodePos, NodePos) {.inline.} =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
let c = b + span(tree, b)
let d = c + span(tree, c)
let e = d + span(tree, d)
result = (NodePos a, NodePos b, NodePos c, NodePos d, NodePos e)
proc typeId*(ins: Instr): TypeId {.inline.} =
assert ins.kind == Typed
result = TypeId(ins.operand)
proc symId*(ins: Instr): SymId {.inline.} =
assert ins.kind in {SymUse, SymDef}
result = SymId(ins.operand)
proc immediateVal*(ins: Instr): int {.inline.} =
assert ins.kind == ImmediateVal
result = cast[int](ins.operand)
proc litId*(ins: Instr): LitId {.inline.} =
assert ins.kind in {StrVal, IntVal}
result = LitId(ins.operand)
type
LabelId* = distinct int
proc `==`*(a, b: LabelId): bool {.borrow.}
proc hash*(a: LabelId): Hash {.borrow.}
proc label*(ins: Instr): LabelId {.inline.} =
assert ins.kind in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto}
result = LabelId(ins.operand)
proc newLabel*(labelGen: var int): LabelId {.inline.} =
result = LabelId labelGen
inc labelGen
proc newLabels*(labelGen: var int; n: int): LabelId {.inline.} =
result = LabelId labelGen
inc labelGen, n
proc addNewLabel*(t: var Tree; labelGen: var int; info: PackedLineInfo; k: Opcode): LabelId =
assert k in {Label, LoopLabel}
result = LabelId labelGen
t.nodes.add Instr(x: toX(k, uint32(result)), info: info)
inc labelGen
proc gotoLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) =
assert k in {Goto, GotoLoop, CheckedGoto}
t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
proc addLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) {.inline.} =
assert k in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto}
t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
proc addSymUse*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} =
t.nodes.add Instr(x: toX(SymUse, uint32(s)), info: info)
proc addSymDef*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} =
t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info)
proc addNop*(t: var Tree; info: PackedLineInfo) {.inline.} =
t.nodes.add Instr(x: toX(Nop, 0'u32), info: info)
proc addTyped*(t: var Tree; info: PackedLineInfo; typ: TypeId) {.inline.} =
assert typ.int >= 0
t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
proc addSummon*(t: var Tree; info: PackedLineInfo; s: SymId; typ: TypeId; opc = Summon) {.inline.} =
assert typ.int >= 0
assert opc in {Summon, SummonConst, SummonGlobal, SummonThreadLocal, SummonParam, SummonResult}
let x = prepare(t, info, opc)
t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info)
patch t, x
proc addImmediateVal*(t: var Tree; info: PackedLineInfo; x: int) =
assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
t.nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
proc addPragmaId*(t: var Tree; info: PackedLineInfo; x: PragmaKey) =
t.nodes.add Instr(x: toX(PragmaId, uint32(x)), info: info)
proc addIntVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; typ: TypeId; x: int64) =
buildTyped t, info, NumberConv, typ:
t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(x))), info: info)
proc boolVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; b: bool) =
buildTyped t, info, NumberConv, Bool8Id:
t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(ord b))), info: info)
proc addStrVal*(t: var Tree; strings: var BiTable[string]; info: PackedLineInfo; s: string) =
t.nodes.add Instr(x: toX(StrVal, uint32(strings.getOrIncl(s))), info: info)
proc addStrLit*(t: var Tree; info: PackedLineInfo; s: LitId) =
t.nodes.add Instr(x: toX(StrVal, uint32(s)), info: info)
proc addNilVal*(t: var Tree; info: PackedLineInfo; typ: TypeId) =
buildTyped t, info, NumberConv, typ:
t.nodes.add Instr(x: toX(NilVal, uint32(0)), info: info)
proc store*(r: var RodFile; t: Tree) = storeSeq r, t.nodes
proc load*(r: var RodFile; t: var Tree) = loadSeq r, t.nodes
proc escapeToNimLit*(s: string; result: var string) =
result.add '"'
for c in items s:
if c < ' ' or int(c) >= 128:
result.add '\\'
result.addInt int(c)
elif c == '\\':
result.add r"\\"
elif c == '\n':
result.add r"\n"
elif c == '\r':
result.add r"\r"
elif c == '\t':
result.add r"\t"
else:
result.add c
result.add '"'
type
SymNames* = object
s: seq[LitId]
proc `[]=`*(t: var SymNames; key: SymId; val: LitId) =
let k = int(key)
if k >= t.s.len: t.s.setLen k+1
t.s[k] = val
proc `[]`*(t: SymNames; key: SymId): LitId =
let k = int(key)
if k < t.s.len: result = t.s[k]
else: result = LitId(0)
template localName(s: SymId): string =
let name = names[s]
if name != LitId(0):
strings[name]
else:
$s.int
proc store*(r: var RodFile; t: SymNames) = storeSeq(r, t.s)
proc load*(r: var RodFile; t: var SymNames) = loadSeq(r, t.s)
proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTable[int64];
names: SymNames;
r: var string; nesting = 0) =
if r.len > 0 and r[r.len-1] notin {' ', '\n', '(', '[', '{'}:
r.add ' '
case t[pos].kind
of Nop: r.add "Nop"
of ImmediateVal:
r.add $t[pos].operand
of IntVal:
r.add "IntVal "
r.add $integers[LitId t[pos].operand]
of StrVal:
escapeToNimLit(strings[LitId t[pos].operand], r)
of SymDef:
r.add "SymDef "
r.add localName(SymId t[pos].operand)
of SymUse:
r.add "SymUse "
r.add localName(SymId t[pos].operand)
of PragmaId:
r.add $cast[PragmaKey](t[pos].operand)
of Typed:
r.add "T<"
r.add $t[pos].operand
r.add ">"
of NilVal:
r.add "NilVal"
of Label:
# undo the nesting:
var spaces = r.len-1
while spaces >= 0 and r[spaces] == ' ': dec spaces
r.setLen spaces+1
r.add "\n L"
r.add $t[pos].operand
of Goto, CheckedGoto, LoopLabel, GotoLoop:
r.add $t[pos].kind
r.add " L"
r.add $t[pos].operand
else:
r.add $t[pos].kind
r.add "{\n"
for i in 0..<(nesting+1)*2: r.add ' '
for p in sons(t, pos):
toString t, p, strings, integers, names, r, nesting+1
r.add "\n"
for i in 0..<nesting*2: r.add ' '
r.add "}"
proc allTreesToString*(t: Tree; strings: BiTable[string]; integers: BiTable[int64];
names: SymNames;
r: var string) =
var i = 0
while i < t.len:
toString t, NodePos(i), strings, integers, names, r
nextChild t, i
type
Value* = distinct Tree
proc prepare*(dest: var Value; info: PackedLineInfo; k: Opcode): PatchPos {.inline.} =
assert k in ValueProducing - ValueProducingAtoms
result = prepare(Tree(dest), info, k)
proc patch*(dest: var Value; pos: PatchPos) {.inline.} =
patch(Tree(dest), pos)
proc localToValue*(info: PackedLineInfo; s: SymId): Value =
result = Value(Tree())
Tree(result).addSymUse info, s
proc hasValue*(v: Value): bool {.inline.} = Tree(v).len > 0
proc isEmpty*(v: Value): bool {.inline.} = Tree(v).len == 0
proc extractTemp*(v: Value): SymId =
if hasValue(v) and Tree(v)[NodePos 0].kind == SymUse:
result = SymId(Tree(v)[NodePos 0].operand)
else:
result = SymId(-1)
proc copyTree*(dest: var Tree; src: Value) = copyTree dest, Tree(src)
proc addImmediateVal*(t: var Value; info: PackedLineInfo; x: int) =
assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
Tree(t).nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
template build*(tree: var Value; info: PackedLineInfo; kind: Opcode; body: untyped) =
let pos = prepare(Tree(tree), info, kind)
body
patch(tree, pos)
proc addTyped*(t: var Value; info: PackedLineInfo; typ: TypeId) {.inline.} =
addTyped(Tree(t), info, typ)
template buildTyped*(tree: var Value; info: PackedLineInfo; kind: Opcode; typ: TypeId; body: untyped) =
let pos = prepare(tree, info, kind)
tree.addTyped info, typ
body
patch(tree, pos)
proc addStrVal*(t: var Value; strings: var BiTable[string]; info: PackedLineInfo; s: string) =
addStrVal(Tree(t), strings, info, s)
proc addNilVal*(t: var Value; info: PackedLineInfo; typ: TypeId) =
addNilVal Tree(t), info, typ
proc addIntVal*(t: var Value; integers: var BiTable[int64]; info: PackedLineInfo; typ: TypeId; x: int64) =
addIntVal Tree(t), integers, info, typ, x

View File

@@ -0,0 +1,84 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# For the line information we use 32 bits. They are used as follows:
# Bit 0 (AsideBit): If we have inline line information or not. If not, the
# remaining 31 bits are used as an index into a seq[(LitId, int, int)].
#
# We use 10 bits for the "file ID", this means a program can consist of as much
# as 1024 different files. (If it uses more files than that, the overflow bit
# would be set.)
# This means we have 21 bits left to encode the (line, col) pair. We use 7 bits for the column
# so 128 is the limit and 14 bits for the line number.
# The packed representation supports files with up to 16384 lines.
# Keep in mind that whenever any limit is reached the AsideBit is set and the real line
# information is kept in a side channel.
import std / assertions
const
AsideBit = 1
FileBits = 10
LineBits = 14
ColBits = 7
FileMax = (1 shl FileBits) - 1
LineMax = (1 shl LineBits) - 1
ColMax = (1 shl ColBits) - 1
static:
assert AsideBit + FileBits + LineBits + ColBits == 32
import .. / ic / [bitabs, rodfiles] # for LitId
type
PackedLineInfo* = distinct uint32
LineInfoManager* = object
aside: seq[(LitId, int32, int32)]
const
NoLineInfo* = PackedLineInfo(0'u32)
proc pack*(m: var LineInfoManager; file: LitId; line, col: int32): PackedLineInfo =
if file.uint32 <= FileMax.uint32 and line <= LineMax and col <= ColMax:
let col = if col < 0'i32: 0'u32 else: col.uint32
let line = if line < 0'i32: 0'u32 else: line.uint32
# use inline representation:
result = PackedLineInfo((file.uint32 shl 1'u32) or (line shl uint32(AsideBit + FileBits)) or
(col shl uint32(AsideBit + FileBits + LineBits)))
else:
result = PackedLineInfo((m.aside.len shl 1) or AsideBit)
m.aside.add (file, line, col)
proc unpack*(m: LineInfoManager; i: PackedLineInfo): (LitId, int32, int32) =
let i = i.uint32
if (i and 1'u32) == 0'u32:
# inline representation:
result = (LitId((i shr 1'u32) and FileMax.uint32),
int32((i shr uint32(AsideBit + FileBits)) and LineMax.uint32),
int32((i shr uint32(AsideBit + FileBits + LineBits)) and ColMax.uint32))
else:
result = m.aside[int(i shr 1'u32)]
proc getFileId*(m: LineInfoManager; i: PackedLineInfo): LitId =
result = unpack(m, i)[0]
proc store*(r: var RodFile; m: LineInfoManager) = storeSeq(r, m.aside)
proc load*(r: var RodFile; m: var LineInfoManager) = loadSeq(r, m.aside)
when isMainModule:
var m = LineInfoManager(aside: @[])
for i in 0'i32..<16388'i32:
for col in 0'i32..<100'i32:
let packed = pack(m, LitId(1023), i, col)
let u = unpack(m, packed)
assert u[0] == LitId(1023)
assert u[1] == i
assert u[2] == col
echo m.aside.len

104
compiler/nir/nirslots.nim Normal file
View File

@@ -0,0 +1,104 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Management of slots. Similar to "register allocation"
## in lower level languages.
import std / [assertions, tables]
import nirtypes, nirinsts
type
SlotManagerFlag* = enum
ReuseTemps,
ReuseVars
SlotKind* = enum
Temp, Perm
SlotManager* = object # "register allocator"
live: Table[SymId, (SlotKind, TypeId)]
dead: Table[TypeId, seq[SymId]]
flags: set[SlotManagerFlag]
inScope: seq[SymId]
proc initSlotManager*(flags: set[SlotManagerFlag]): SlotManager {.inline.} =
SlotManager(flags: flags)
proc allocRaw(m: var SlotManager; t: TypeId; f: SlotManagerFlag; k: SlotKind;
symIdgen: var int32): SymId {.inline.} =
if f in m.flags and m.dead.hasKey(t) and m.dead[t].len > 0:
result = m.dead[t].pop()
else:
inc symIdgen
result = SymId(symIdgen)
m.inScope.add result
m.live[result] = (k, t)
proc allocTemp*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} =
result = allocRaw(m, t, ReuseTemps, Temp, symIdgen)
proc allocVar*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} =
result = allocRaw(m, t, ReuseVars, Perm, symIdgen)
proc freeLoc*(m: var SlotManager; s: SymId) =
let t = m.live.getOrDefault(s)
assert t[1].int != 0
m.live.del s
m.dead.mgetOrPut(t[1], @[]).add s
proc freeTemp*(m: var SlotManager; s: SymId) =
let t = m.live.getOrDefault(s)
if t[1].int != 0 and t[0] == Temp:
m.live.del s
m.dead.mgetOrPut(t[1], @[]).add s
iterator stillAlive*(m: SlotManager): (SymId, TypeId) =
for k, v in pairs(m.live):
yield (k, v[1])
proc getType*(m: SlotManager; s: SymId): TypeId {.inline.} = m.live[s][1]
proc openScope*(m: var SlotManager) =
m.inScope.add SymId(-1) # add marker
proc closeScope*(m: var SlotManager) =
var i = m.inScope.len - 1
while i >= 0:
if m.inScope[i] == SymId(-1):
m.inScope.setLen i
break
dec i
when isMainModule:
var symIdgen: int32
var m = initSlotManager({ReuseTemps})
var g = initTypeGraph(Literals())
let a = g.openType ArrayTy
g.addBuiltinType Int8Id
g.addArrayLen 5
let finalArrayType = finishType(g, a)
let obj = g.openType ObjectDecl
g.addName "MyType"
g.addField "p", finalArrayType, 0
let objB = finishType(g, obj)
let x = m.allocTemp(objB, symIdgen)
assert x.int == 0
let y = m.allocTemp(objB, symIdgen)
assert y.int == 1
let z = m.allocTemp(Int8Id, symIdgen)
assert z.int == 2
m.freeLoc y
let y2 = m.allocTemp(objB, symIdgen)
assert y2.int == 1

475
compiler/nir/nirtypes.nim Normal file
View File

@@ -0,0 +1,475 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Type system for NIR. Close to C's type system but without its quirks.
import std / [assertions, hashes]
import .. / ic / [bitabs, rodfiles]
type
NirTypeKind* = enum
VoidTy, IntTy, UIntTy, FloatTy, BoolTy, CharTy, NameVal,
IntVal, SizeVal, AlignVal, OffsetVal,
AnnotationVal,
ObjectTy,
UnionTy,
VarargsTy, # the `...` in a C prototype; also the last "atom"
APtrTy, # pointer to aliasable memory
UPtrTy, # pointer to unique/unaliasable memory
AArrayPtrTy, # pointer to array of aliasable memory
UArrayPtrTy, # pointer to array of unique/unaliasable memory
ArrayTy,
LastArrayTy, # array of unspecified size as a last field inside an object
ProcTy,
ObjectDecl,
UnionDecl,
FieldDecl
const
TypeKindBits = 8'u32
TypeKindMask = (1'u32 shl TypeKindBits) - 1'u32
type
TypeNode* = object # 4 bytes
x: uint32
template kind*(n: TypeNode): NirTypeKind = NirTypeKind(n.x and TypeKindMask)
template operand(n: TypeNode): uint32 = (n.x shr TypeKindBits)
proc integralBits*(n: TypeNode): int {.inline.} =
# Number of bits in the IntTy, etc. Only valid for integral types.
assert n.kind in {IntTy, UIntTy, FloatTy, BoolTy, CharTy}
result = int(n.operand)
template toX(k: NirTypeKind; operand: uint32): uint32 =
uint32(k) or (operand shl TypeKindBits)
template toX(k: NirTypeKind; operand: LitId): uint32 =
uint32(k) or (operand.uint32 shl TypeKindBits)
type
TypeId* = distinct int
proc `==`*(a, b: TypeId): bool {.borrow.}
proc hash*(a: TypeId): Hash {.borrow.}
type
Literals* = ref object
strings*: BiTable[string]
numbers*: BiTable[int64]
TypeGraph* = object
nodes: seq[TypeNode]
lit: Literals
const
VoidId* = TypeId 0
Bool8Id* = TypeId 1
Char8Id* = TypeId 2
Int8Id* = TypeId 3
Int16Id* = TypeId 4
Int32Id* = TypeId 5
Int64Id* = TypeId 6
UInt8Id* = TypeId 7
UInt16Id* = TypeId 8
UInt32Id* = TypeId 9
UInt64Id* = TypeId 10
Float32Id* = TypeId 11
Float64Id* = TypeId 12
VoidPtrId* = TypeId 13
LastBuiltinId* = 13
proc initTypeGraph*(lit: Literals): TypeGraph =
result = TypeGraph(nodes: @[
TypeNode(x: toX(VoidTy, 0'u32)),
TypeNode(x: toX(BoolTy, 8'u32)),
TypeNode(x: toX(CharTy, 8'u32)),
TypeNode(x: toX(IntTy, 8'u32)),
TypeNode(x: toX(IntTy, 16'u32)),
TypeNode(x: toX(IntTy, 32'u32)),
TypeNode(x: toX(IntTy, 64'u32)),
TypeNode(x: toX(UIntTy, 8'u32)),
TypeNode(x: toX(UIntTy, 16'u32)),
TypeNode(x: toX(UIntTy, 32'u32)),
TypeNode(x: toX(UIntTy, 64'u32)),
TypeNode(x: toX(FloatTy, 32'u32)),
TypeNode(x: toX(FloatTy, 64'u32)),
TypeNode(x: toX(APtrTy, 2'u32)),
TypeNode(x: toX(VoidTy, 0'u32))
], lit: lit)
assert result.nodes.len == LastBuiltinId+2
type
TypePatchPos* = distinct int
const
InvalidTypePatchPos* = TypePatchPos(-1)
LastAtomicValue = VarargsTy
proc isValid(p: TypePatchPos): bool {.inline.} = p.int != -1
proc prepare(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
result = TypePatchPos tree.nodes.len
tree.nodes.add TypeNode(x: toX(kind, 1'u32))
proc isAtom(tree: TypeGraph; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
proc isAtom(tree: TypeGraph; pos: TypeId): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
proc patch(tree: var TypeGraph; pos: TypePatchPos) =
let pos = pos.int
let k = tree.nodes[pos].kind
assert k > LastAtomicValue
let distance = int32(tree.nodes.len - pos)
assert distance > 0
tree.nodes[pos].x = toX(k, cast[uint32](distance))
proc len*(tree: TypeGraph): int {.inline.} = tree.nodes.len
template rawSpan(n: TypeNode): int = int(operand(n))
proc nextChild(tree: TypeGraph; pos: var int) {.inline.} =
if tree.nodes[pos].kind > LastAtomicValue:
assert tree.nodes[pos].operand > 0'u32
inc pos, tree.nodes[pos].rawSpan
else:
inc pos
iterator sons*(tree: TypeGraph; n: TypeId): TypeId =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last:
yield TypeId pos
nextChild tree, pos
template `[]`*(t: TypeGraph; n: TypeId): TypeNode = t.nodes[n.int]
proc elementType*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
assert tree[n].kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ArrayTy, LastArrayTy}
result = TypeId(n.int+1)
proc litId*(n: TypeNode): LitId {.inline.} =
assert n.kind in {NameVal, IntVal, SizeVal, AlignVal, OffsetVal, AnnotationVal, ObjectTy, UnionTy}
result = LitId(n.operand)
proc kind*(tree: TypeGraph; n: TypeId): NirTypeKind {.inline.} = tree[n].kind
proc span(tree: TypeGraph; pos: int): int {.inline.} =
if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
proc sons2(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
result = (TypeId a, TypeId b)
proc sons3(tree: TypeGraph; n: TypeId): (TypeId, TypeId, TypeId) =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
let c = b + span(tree, b)
result = (TypeId a, TypeId b, TypeId c)
proc arrayName*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
assert tree[n].kind == ArrayTy
let (_, _, c) = sons3(tree, n)
result = c
proc arrayLen*(tree: TypeGraph; n: TypeId): BiggestInt =
assert tree[n].kind == ArrayTy
let (_, b) = sons2(tree, n)
result = tree.lit.numbers[LitId tree[b].operand]
proc returnType*(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
# Returns the positions of the return type + calling convention.
var pos = n.int
assert tree.nodes[pos].kind == ProcTy
let a = n.int+1
let b = a + span(tree, a)
result = (TypeId b, TypeId a) # not a typo, order is reversed
iterator params*(tree: TypeGraph; n: TypeId): TypeId =
var pos = n.int
assert tree.nodes[pos].kind == ProcTy
let last = pos + tree.nodes[pos].rawSpan
inc pos
nextChild tree, pos
nextChild tree, pos
while pos < last:
yield TypeId pos
nextChild tree, pos
proc openType*(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
assert kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy,
ArrayTy, LastArrayTy, ProcTy, ObjectDecl, UnionDecl,
FieldDecl}
result = prepare(tree, kind)
template typeInvariant(p: TypePatchPos) =
when false:
if tree[TypeId(p)].kind == FieldDecl:
var k = 0
for ch in sons(tree, TypeId(p)):
inc k
assert k > 2, "damn! " & $k
proc sealType*(tree: var TypeGraph; p: TypePatchPos) =
patch tree, p
typeInvariant(p)
proc finishType*(tree: var TypeGraph; p: TypePatchPos): TypeId =
# Search for an existing instance of this type in
# order to reduce memory consumption:
patch tree, p
typeInvariant(p)
let s = span(tree, p.int)
var i = 0
while i < p.int:
if tree.nodes[i].x == tree.nodes[p.int].x:
var isMatch = true
for j in 1..<s:
if tree.nodes[j+i].x == tree.nodes[j+p.int].x:
discard "still a match"
else:
isMatch = false
break
if isMatch:
if p.int+s == tree.len:
setLen tree.nodes, p.int
return TypeId(i)
nextChild tree, i
result = TypeId(p)
proc nominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string): TypeId =
assert kind in {ObjectTy, UnionTy}
let content = TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name)))
for i in 0..<tree.len:
if tree.nodes[i].x == content.x:
return TypeId(i)
result = TypeId tree.nodes.len
tree.nodes.add content
proc addNominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string) =
assert kind in {ObjectTy, UnionTy}
tree.nodes.add TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name)))
proc getTypeTag*(tree: TypeGraph; t: TypeId): string =
assert tree[t].kind in {ObjectTy, UnionTy}
result = tree.lit.strings[LitId tree[t].operand]
proc addVarargs*(tree: var TypeGraph) =
tree.nodes.add TypeNode(x: toX(VarargsTy, 0'u32))
proc getFloat128Type*(tree: var TypeGraph): TypeId =
result = TypeId tree.nodes.len
tree.nodes.add TypeNode(x: toX(FloatTy, 128'u32))
proc addBuiltinType*(g: var TypeGraph; id: TypeId) =
g.nodes.add g[id]
template firstSon*(n: TypeId): TypeId = TypeId(n.int+1)
proc addType*(g: var TypeGraph; t: TypeId) =
# We cannot simply copy `*Decl` nodes. We have to introduce `*Ty` nodes instead:
if g[t].kind in {ObjectDecl, UnionDecl}:
assert g[t.firstSon].kind == NameVal
let name = LitId g[t.firstSon].operand
if g[t].kind == ObjectDecl:
g.nodes.add TypeNode(x: toX(ObjectTy, name))
else:
g.nodes.add TypeNode(x: toX(UnionTy, name))
else:
let pos = t.int
let L = span(g, pos)
let d = g.nodes.len
g.nodes.setLen(d + L)
assert L > 0
for i in 0..<L:
g.nodes[d+i] = g.nodes[pos+i]
proc addArrayLen*(g: var TypeGraph; len: int64) =
g.nodes.add TypeNode(x: toX(IntVal, g.lit.numbers.getOrIncl(len)))
proc addSize*(g: var TypeGraph; s: int64) =
g.nodes.add TypeNode(x: toX(SizeVal, g.lit.numbers.getOrIncl(s)))
proc addOffset*(g: var TypeGraph; offset: int64) =
g.nodes.add TypeNode(x: toX(OffsetVal, g.lit.numbers.getOrIncl(offset)))
proc addAlign*(g: var TypeGraph; a: int64) =
g.nodes.add TypeNode(x: toX(AlignVal, g.lit.numbers.getOrIncl(a)))
proc addName*(g: var TypeGraph; name: string) =
g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name)))
proc addAnnotation*(g: var TypeGraph; name: string) =
g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name)))
proc addField*(g: var TypeGraph; name: string; typ: TypeId; offset: int64) =
let f = g.openType FieldDecl
g.addType typ
g.addOffset offset
g.addName name
sealType(g, f)
proc ptrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
let f = g.openType APtrTy
g.addType t
result = finishType(g, f)
proc arrayPtrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
let f = g.openType AArrayPtrTy
g.addType t
result = finishType(g, f)
proc store*(r: var RodFile; g: TypeGraph) =
storeSeq r, g.nodes
proc load*(r: var RodFile; g: var TypeGraph) =
loadSeq r, g.nodes
proc toString*(dest: var string; g: TypeGraph; i: TypeId) =
case g[i].kind
of VoidTy: dest.add "void"
of IntTy:
dest.add "i"
dest.addInt g[i].operand
of UIntTy:
dest.add "u"
dest.addInt g[i].operand
of FloatTy:
dest.add "f"
dest.addInt g[i].operand
of BoolTy:
dest.add "b"
dest.addInt g[i].operand
of CharTy:
dest.add "c"
dest.addInt g[i].operand
of NameVal, AnnotationVal:
dest.add g.lit.strings[LitId g[i].operand]
of IntVal, SizeVal, AlignVal, OffsetVal:
dest.add $g[i].kind
dest.add ' '
dest.add $g.lit.numbers[LitId g[i].operand]
of VarargsTy:
dest.add "..."
of APtrTy:
dest.add "aptr["
toString(dest, g, g.elementType(i))
dest.add "]"
of UPtrTy:
dest.add "uptr["
toString(dest, g, g.elementType(i))
dest.add "]"
of AArrayPtrTy:
dest.add "aArrayPtr["
toString(dest, g, g.elementType(i))
dest.add "]"
of UArrayPtrTy:
dest.add "uArrayPtr["
toString(dest, g, g.elementType(i))
dest.add "]"
of ArrayTy:
dest.add "Array["
let (elems, len, name) = g.sons3(i)
toString(dest, g, elems)
dest.add ", "
toString(dest, g, len)
dest.add ", "
toString(dest, g, name)
dest.add "]"
of LastArrayTy:
# array of unspecified size as a last field inside an object
dest.add "LastArrayTy["
toString(dest, g, g.elementType(i))
dest.add "]"
of ObjectTy:
dest.add "object "
dest.add g.lit.strings[LitId g[i].operand]
of UnionTy:
dest.add "union "
dest.add g.lit.strings[LitId g[i].operand]
of ProcTy:
dest.add "proc["
for t in sons(g, i):
dest.add ' '
toString(dest, g, t)
dest.add "]"
of ObjectDecl:
dest.add "object["
for t in sons(g, i):
toString(dest, g, t)
dest.add '\n'
dest.add "]"
of UnionDecl:
dest.add "union["
for t in sons(g, i):
toString(dest, g, t)
dest.add '\n'
dest.add "]"
of FieldDecl:
dest.add "field["
for t in sons(g, i):
toString(dest, g, t)
dest.add ' '
dest.add "]"
when false:
let (typ, offset, name) = g.sons3(i)
toString(dest, g, typ)
dest.add ' '
toString(dest, g, offset)
dest.add ' '
toString(dest, g, name)
proc toString*(dest: var string; g: TypeGraph) =
var i = 0
while i < g.len:
dest.add "T<"
dest.addInt i
dest.add "> "
toString(dest, g, TypeId i)
dest.add '\n'
nextChild g, i
iterator allTypes*(g: TypeGraph; start = 0): TypeId =
var i = start
while i < g.len:
yield TypeId i
nextChild g, i
iterator allTypesIncludingInner*(g: TypeGraph; start = 0): TypeId =
var i = start
while i < g.len:
yield TypeId i
inc i
proc `$`(g: TypeGraph): string =
result = ""
toString(result, g)
when isMainModule:
var g = initTypeGraph(Literals())
let a = g.openType ArrayTy
g.addBuiltinType Int8Id
g.addArrayLen 5
g.addName "SomeArray"
let finalArrayType = finishType(g, a)
let obj = g.openType ObjectDecl
g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl("MyType")))
g.addField "p", finalArrayType, 0
sealType(g, obj)
echo g

1175
compiler/nir/nirvm.nim Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,200 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## included from ast2ir.nim
#[
case s
of "abc", "abbd":
echo 1
of "hah":
echo 2
of "gah":
echo 3
# we produce code like this:
if s[0] <= 'a':
if s == "abc: goto L1
elif s == "abbd": goto L1
else:
if s[2] <= 'h':
if s == "hah": goto L2
elif s == "gah": goto L3
goto afterCase
L1:
echo 1
goto afterCase
L2:
echo 2
goto afterCase
L3:
echo 3
goto afterCase
afterCase: ...
]#
# We split the set of strings into 2 sets of roughly the same size.
# The condition used for splitting is a (position, char) tuple.
# Every string of length > position for which s[position] <= char is in one
# set else it is in the other set.
from std/sequtils import addUnique
type
Key = (LitId, LabelId)
proc splitValue(strings: BiTable[string]; a: openArray[Key]; position: int): (char, float) =
var cand: seq[char] = @[]
for t in items a:
let s = strings[t[0]]
if s.len > position: cand.addUnique s[position]
result = ('\0', -1.0)
for disc in items cand:
var hits = 0
for t in items a:
let s = strings[t[0]]
if s.len > position and s[position] <= disc:
inc hits
# the split is the better, the more `hits` is close to `a.len / 2`:
let grade = 100000.0 - abs(hits.float - a.len.float / 2.0)
if grade > result[1]:
result = (disc, grade)
proc tryAllPositions(strings: BiTable[string]; a: openArray[Key]): (char, int) =
var m = 0
for t in items a:
m = max(m, strings[t[0]].len)
result = ('\0', -1)
var best = -1.0
for i in 0 ..< m:
let current = splitValue(strings, a, i)
if current[1] > best:
best = current[1]
result = (current[0], i)
type
SearchKind = enum
LinearSearch, SplitSearch
SearchResult* = object
case kind: SearchKind
of LinearSearch:
a: seq[Key]
of SplitSearch:
span: int
best: (char, int)
proc emitLinearSearch(strings: BiTable[string]; a: openArray[Key]; dest: var seq[SearchResult]) =
var d = SearchResult(kind: LinearSearch, a: @[])
for x in a: d.a.add x
dest.add d
proc split(strings: BiTable[string]; a: openArray[Key]; dest: var seq[SearchResult]) =
if a.len <= 4:
emitLinearSearch strings, a, dest
else:
let best = tryAllPositions(strings, a)
var groupA: seq[Key] = @[]
var groupB: seq[Key] = @[]
for t in items a:
let s = strings[t[0]]
if s.len > best[1] and s[best[1]] <= best[0]:
groupA.add t
else:
groupB.add t
if groupA.len == 0 or groupB.len == 0:
emitLinearSearch strings, a, dest
else:
let toPatch = dest.len
dest.add SearchResult(kind: SplitSearch, span: 1, best: best)
split strings, groupA, dest
split strings, groupB, dest
let dist = dest.len - toPatch
assert dist > 0
dest[toPatch].span = dist
proc toProblemDescription(c: var ProcCon; n: PNode): (seq[Key], LabelId) =
result = (@[], newLabels(c.labelGen, n.len))
assert n.kind == nkCaseStmt
for i in 1..<n.len:
let it = n[i]
let thisBranch = LabelId(result[1].int + i - 1)
if it.kind == nkOfBranch:
for j in 0..<it.len-1:
assert it[j].kind in {nkStrLit..nkTripleStrLit}
result[0].add (c.lit.strings.getOrIncl(it[j].strVal), thisBranch)
proc decodeSolution(c: var ProcCon; dest: var Tree; s: seq[SearchResult]; i: int;
selector: Value; info: PackedLineInfo) =
case s[i].kind
of SplitSearch:
let thenA = i+1
let elseA = thenA + (if s[thenA].kind == LinearSearch: 1 else: s[thenA].span)
let best = s[i].best
let tmp = getTemp(c, Bool8Id, info)
buildTyped dest, info, Asgn, Bool8Id:
dest.copyTree tmp
buildTyped dest, info, Call, Bool8Id:
c.addUseCodegenProc dest, "nimStrAtLe", info
dest.copyTree selector
dest.addIntVal c.lit.numbers, info, c.m.nativeIntId, best[1]
dest.addIntVal c.lit.numbers, info, Char8Id, best[0].int
template then() =
c.decodeSolution dest, s, thenA, selector, info
template otherwise() =
c.decodeSolution dest, s, elseA, selector, info
buildIfThenElse tmp, then, otherwise
freeTemp c, tmp
of LinearSearch:
let tmp = getTemp(c, Bool8Id, info)
for x in s[i].a:
buildTyped dest, info, Asgn, Bool8Id:
dest.copyTree tmp
buildTyped dest, info, Call, Bool8Id:
c.addUseCodegenProc dest, "eqStrings", info
dest.copyTree selector
dest.addStrLit info, x[0]
buildIf tmp:
c.code.gotoLabel info, Goto, x[1]
freeTemp c, tmp
proc genStringCase(c: var ProcCon; n: PNode; d: var Value) =
let (problem, firstBranch) = toProblemDescription(c, n)
var solution: seq[SearchResult] = @[]
split c.lit.strings, problem, solution
# XXX Todo move complex case selector into a temporary.
let selector = c.genx(n[0])
let info = toLineInfo(c, n.info)
decodeSolution c, c.code, solution, 0, selector, info
let lend = newLabel(c.labelGen)
c.code.addLabel info, Goto, lend
for i in 1..<n.len:
let it = n[i]
let thisBranch = LabelId(firstBranch.int + i - 1)
c.code.addLabel info, Label, thisBranch
if it.kind == nkOfBranch:
gen(c, it.lastSon, d)
c.code.addLabel info, Goto, lend
else:
gen(c, it.lastSon, d)
c.code.addLabel info, Label, lend
freeTemp c, selector

525
compiler/nir/types2ir.nim Normal file
View File

@@ -0,0 +1,525 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import std / [assertions, tables, sets]
import ".." / [ast, types, options, sighashes, modulegraphs]
import nirtypes
type
TypesCon* = object
processed: Table[ItemId, TypeId]
processedByName: Table[string, TypeId]
recursionCheck: HashSet[ItemId]
conf: ConfigRef
stringType: TypeId
proc initTypesCon*(conf: ConfigRef): TypesCon =
TypesCon(conf: conf, stringType: TypeId(-1))
proc mangle(c: var TypesCon; t: PType): string =
result = $sighashes.hashType(t, c.conf)
template cached(c: var TypesCon; t: PType; body: untyped) =
result = c.processed.getOrDefault(t.itemId)
if result.int == 0:
body
c.processed[t.itemId] = result
template cachedByName(c: var TypesCon; t: PType; body: untyped) =
let key = mangle(c, t)
result = c.processedByName.getOrDefault(key)
if result.int == 0:
body
c.processedByName[key] = result
proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId
proc collectFieldTypes(c: var TypesCon; g: var TypeGraph; n: PNode; dest: var Table[ItemId, TypeId]) =
case n.kind
of nkRecList:
for i in 0..<n.len:
collectFieldTypes(c, g, n[i], dest)
of nkRecCase:
assert(n[0].kind == nkSym)
collectFieldTypes(c, g, n[0], dest)
for i in 1..<n.len:
case n[i].kind
of nkOfBranch, nkElse:
collectFieldTypes c, g, lastSon(n[i]), dest
else: discard
of nkSym:
dest[n.sym.itemId] = typeToIr(c, g, n.sym.typ)
else:
assert false, "unknown node kind: " & $n.kind
proc objectToIr(c: var TypesCon; g: var TypeGraph; n: PNode; fieldTypes: Table[ItemId, TypeId]; unionId: var int) =
case n.kind
of nkRecList:
for i in 0..<n.len:
objectToIr(c, g, n[i], fieldTypes, unionId)
of nkRecCase:
assert(n[0].kind == nkSym)
objectToIr(c, g, n[0], fieldTypes, unionId)
let u = openType(g, UnionDecl)
g.addName "u_" & $unionId
inc unionId
for i in 1..<n.len:
case n[i].kind
of nkOfBranch, nkElse:
let subObj = openType(g, ObjectDecl)
g.addName "uo_" & $unionId & "_" & $i
objectToIr c, g, lastSon(n[i]), fieldTypes, unionId
sealType(g, subObj)
else: discard
sealType(g, u)
of nkSym:
g.addField n.sym.name.s & "_" & $n.sym.position, fieldTypes[n.sym.itemId], n.sym.offset
else:
assert false, "unknown node kind: " & $n.kind
proc objectToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
if t[0] != nil:
# ensure we emitted the base type:
discard typeToIr(c, g, t[0])
var unionId = 0
var fieldTypes = initTable[ItemId, TypeId]()
collectFieldTypes c, g, t.n, fieldTypes
let obj = openType(g, ObjectDecl)
g.addName mangle(c, t)
g.addSize c.conf.getSize(t)
g.addAlign c.conf.getAlign(t)
if t[0] != nil:
g.addNominalType(ObjectTy, mangle(c, t[0]))
else:
g.addBuiltinType VoidId # object does not inherit
if not lacksMTypeField(t):
let f2 = g.openType FieldDecl
let voidPtr = openType(g, APtrTy)
g.addBuiltinType(VoidId)
sealType(g, voidPtr)
g.addOffset 0 # type field is always at offset 0
g.addName "m_type"
sealType(g, f2) # FieldDecl
objectToIr c, g, t.n, fieldTypes, unionId
result = finishType(g, obj)
proc objectHeaderToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
result = g.nominalType(ObjectTy, mangle(c, t))
proc tupleToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
var fieldTypes = newSeq[TypeId](t.len)
for i in 0..<t.len:
fieldTypes[i] = typeToIr(c, g, t[i])
let obj = openType(g, ObjectDecl)
g.addName mangle(c, t)
g.addSize c.conf.getSize(t)
g.addAlign c.conf.getAlign(t)
var accum = OffsetAccum(maxAlign: 1)
for i in 0..<t.len:
let child = t[i]
g.addField "f_" & $i, fieldTypes[i], accum.offset
computeSizeAlign(c.conf, child)
accum.align(child.align)
accum.inc(int32(child.size))
result = finishType(g, obj)
proc procToIr(c: var TypesCon; g: var TypeGraph; t: PType; addEnv = false): TypeId =
var fieldTypes = newSeq[TypeId](0)
for i in 0..<t.len:
if t[i] == nil or not isCompileTimeOnly(t[i]):
fieldTypes.add typeToIr(c, g, t[i])
let obj = openType(g, ProcTy)
case t.callConv
of ccNimCall, ccFastCall, ccClosure: g.addAnnotation "__fastcall"
of ccStdCall: g.addAnnotation "__stdcall"
of ccCDecl: g.addAnnotation "__cdecl"
of ccSafeCall: g.addAnnotation "__safecall"
of ccSysCall: g.addAnnotation "__syscall"
of ccInline: g.addAnnotation "__inline"
of ccNoInline: g.addAnnotation "__noinline"
of ccThisCall: g.addAnnotation "__thiscall"
of ccNoConvention: g.addAnnotation ""
for i in 0..<fieldTypes.len:
g.addType fieldTypes[i]
if addEnv:
let a = openType(g, APtrTy)
g.addBuiltinType(VoidId)
sealType(g, a)
if tfVarargs in t.flags:
g.addVarargs()
result = finishType(g, obj)
proc nativeInt(c: TypesCon): TypeId =
case c.conf.target.intSize
of 2: result = Int16Id
of 4: result = Int32Id
else: result = Int64Id
proc openArrayPayloadType*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
let e = lastSon(t)
let elementType = typeToIr(c, g, e)
let arr = g.openType AArrayPtrTy
g.addType elementType
result = finishType(g, arr) # LastArrayTy
proc openArrayToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
# object (a: ArrayPtr[T], len: int)
let e = lastSon(t)
let mangledBase = mangle(c, e)
let typeName = "NimOpenArray" & mangledBase
let elementType = typeToIr(c, g, e)
#assert elementType.int >= 0, typeToString(t)
let p = openType(g, ObjectDecl)
g.addName typeName
g.addSize c.conf.target.ptrSize*2
g.addAlign c.conf.target.ptrSize
let f = g.openType FieldDecl
let arr = g.openType AArrayPtrTy
g.addType elementType
sealType(g, arr) # LastArrayTy
g.addOffset 0
g.addName "data"
sealType(g, f) # FieldDecl
g.addField "len", c.nativeInt, c.conf.target.ptrSize
result = finishType(g, p) # ObjectDecl
proc strPayloadType(c: var TypesCon; g: var TypeGraph): (string, TypeId) =
result = ("NimStrPayload", TypeId(-1))
let p = openType(g, ObjectDecl)
g.addName result[0]
g.addSize c.conf.target.ptrSize*2
g.addAlign c.conf.target.ptrSize
g.addField "cap", c.nativeInt, 0
let f = g.openType FieldDecl
let arr = g.openType LastArrayTy
g.addBuiltinType Char8Id
result[1] = finishType(g, arr) # LastArrayTy
g.addOffset c.conf.target.ptrSize # comes after the len field
g.addName "data"
sealType(g, f) # FieldDecl
sealType(g, p)
proc strPayloadPtrType*(c: var TypesCon; g: var TypeGraph): (TypeId, TypeId) =
let (mangled, arrayType) = strPayloadType(c, g)
let ffp = g.openType APtrTy
g.addNominalType ObjectTy, mangled
result = (finishType(g, ffp), arrayType) # APtrTy
proc stringToIr(c: var TypesCon; g: var TypeGraph): TypeId =
#[
NimStrPayload = object
cap: int
data: UncheckedArray[char]
NimStringV2 = object
len: int
p: ptr NimStrPayload
]#
let payload = strPayloadType(c, g)
let str = openType(g, ObjectDecl)
g.addName "NimStringV2"
g.addSize c.conf.target.ptrSize*2
g.addAlign c.conf.target.ptrSize
g.addField "len", c.nativeInt, 0
let fp = g.openType FieldDecl
let ffp = g.openType APtrTy
g.addNominalType ObjectTy, "NimStrPayload"
sealType(g, ffp) # APtrTy
g.addOffset c.conf.target.ptrSize # comes after 'len' field
g.addName "p"
sealType(g, fp) # FieldDecl
result = finishType(g, str) # ObjectDecl
proc seqPayloadType(c: var TypesCon; g: var TypeGraph; t: PType): (string, TypeId) =
#[
NimSeqPayload[T] = object
cap: int
data: UncheckedArray[T]
]#
let e = lastSon(t)
result = (mangle(c, e), TypeId(-1))
let payloadName = "NimSeqPayload" & result[0]
let elementType = typeToIr(c, g, e)
let p = openType(g, ObjectDecl)
g.addName payloadName
g.addSize c.conf.target.intSize
g.addAlign c.conf.target.intSize
g.addField "cap", c.nativeInt, 0
let f = g.openType FieldDecl
let arr = g.openType LastArrayTy
g.addType elementType
# DO NOT USE `finishType` here as it is an inner type. This is subtle and we
# probably need an even better API here.
sealType(g, arr)
result[1] = TypeId(arr)
g.addOffset c.conf.target.ptrSize
g.addName "data"
sealType(g, f) # FieldDecl
sealType(g, p)
proc seqPayloadPtrType*(c: var TypesCon; g: var TypeGraph; t: PType): (TypeId, TypeId) =
let (mangledBase, arrayType) = seqPayloadType(c, g, t)
let ffp = g.openType APtrTy
g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase
result = (finishType(g, ffp), arrayType) # APtrTy
proc seqToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
#[
NimSeqV2*[T] = object
len: int
p: ptr NimSeqPayload[T]
]#
let (mangledBase, _) = seqPayloadType(c, g, t)
let sq = openType(g, ObjectDecl)
g.addName "NimSeqV2" & mangledBase
g.addSize c.conf.getSize(t)
g.addAlign c.conf.getAlign(t)
g.addField "len", c.nativeInt, 0
let fp = g.openType FieldDecl
let ffp = g.openType APtrTy
g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase
sealType(g, ffp) # APtrTy
g.addOffset c.conf.target.ptrSize
g.addName "p"
sealType(g, fp) # FieldDecl
result = finishType(g, sq) # ObjectDecl
proc closureToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
# struct {fn(args, void* env), env}
# typedef struct {$n" &
# "N_NIMCALL_PTR($2, ClP_0) $3;$n" &
# "void* ClE_0;$n} $1;$n"
let mangledBase = mangle(c, t)
let typeName = "NimClosure" & mangledBase
let procType = procToIr(c, g, t, addEnv=true)
let p = openType(g, ObjectDecl)
g.addName typeName
g.addSize c.conf.getSize(t)
g.addAlign c.conf.getAlign(t)
let f = g.openType FieldDecl
g.addType procType
g.addOffset 0
g.addName "ClP_0"
sealType(g, f) # FieldDecl
let f2 = g.openType FieldDecl
let voidPtr = openType(g, APtrTy)
g.addBuiltinType(VoidId)
sealType(g, voidPtr)
g.addOffset c.conf.target.ptrSize
g.addName "ClE_0"
sealType(g, f2) # FieldDecl
result = finishType(g, p) # ObjectDecl
proc bitsetBasetype*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
let s = int(getSize(c.conf, t))
case s
of 1: result = UInt8Id
of 2: result = UInt16Id
of 4: result = UInt32Id
of 8: result = UInt64Id
else: result = UInt8Id
proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
if t == nil: return VoidId
case t.kind
of tyInt:
case int(getSize(c.conf, t))
of 2: result = Int16Id
of 4: result = Int32Id
else: result = Int64Id
of tyInt8: result = Int8Id
of tyInt16: result = Int16Id
of tyInt32: result = Int32Id
of tyInt64: result = Int64Id
of tyFloat:
case int(getSize(c.conf, t))
of 4: result = Float32Id
else: result = Float64Id
of tyFloat32: result = Float32Id
of tyFloat64: result = Float64Id
of tyFloat128: result = getFloat128Type(g)
of tyUInt:
case int(getSize(c.conf, t))
of 2: result = UInt16Id
of 4: result = UInt32Id
else: result = UInt64Id
of tyUInt8: result = UInt8Id
of tyUInt16: result = UInt16Id
of tyUInt32: result = UInt32Id
of tyUInt64: result = UInt64Id
of tyBool: result = Bool8Id
of tyChar: result = Char8Id
of tyVoid: result = VoidId
of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned, tyRange:
result = typeToIr(c, g, t.lastSon)
of tyEnum:
if firstOrd(c.conf, t) < 0:
result = Int32Id
else:
case int(getSize(c.conf, t))
of 1: result = UInt8Id
of 2: result = UInt16Id
of 4: result = Int32Id
of 8: result = Int64Id
else: result = Int32Id
of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
if t.len > 0:
result = typeToIr(c, g, t.lastSon)
else:
result = TypeId(-1)
of tyFromExpr:
if t.n != nil and t.n.typ != nil:
result = typeToIr(c, g, t.n.typ)
else:
result = TypeId(-1)
of tyArray:
cached(c, t):
var n = toInt64(lengthOrd(c.conf, t))
if n <= 0: n = 1 # make an array of at least one element
let elemType = typeToIr(c, g, t[1])
let a = openType(g, ArrayTy)
g.addType(elemType)
g.addArrayLen n
g.addName mangle(c, t)
result = finishType(g, a)
of tyPtr, tyRef:
cached(c, t):
let e = t.lastSon
if e.kind == tyUncheckedArray:
let elemType = typeToIr(c, g, e.lastSon)
let a = openType(g, AArrayPtrTy)
g.addType(elemType)
result = finishType(g, a)
else:
let elemType = typeToIr(c, g, t.lastSon)
let a = openType(g, APtrTy)
g.addType(elemType)
result = finishType(g, a)
of tyVar, tyLent:
cached(c, t):
let e = t.lastSon
if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
# skip the modifier, `var openArray` is a (ptr, len) pair too:
result = typeToIr(c, g, e)
else:
let elemType = typeToIr(c, g, e)
let a = openType(g, APtrTy)
g.addType(elemType)
result = finishType(g, a)
of tySet:
let s = int(getSize(c.conf, t))
case s
of 1: result = UInt8Id
of 2: result = UInt16Id
of 4: result = UInt32Id
of 8: result = UInt64Id
else:
# array[U8, s]
cached(c, t):
let a = openType(g, ArrayTy)
g.addType(UInt8Id)
g.addArrayLen s
g.addName mangle(c, t)
result = finishType(g, a)
of tyPointer, tyNil:
# tyNil can happen for code like: `const CRAP = nil` which we have in posix.nim
let a = openType(g, APtrTy)
g.addBuiltinType(VoidId)
result = finishType(g, a)
of tyObject:
# Objects are special as they can be recursive in Nim. This is easily solvable.
# We check if we are already "processing" t. If so, we produce `ObjectTy`
# instead of `ObjectDecl`.
cached(c, t):
if not c.recursionCheck.containsOrIncl(t.itemId):
result = objectToIr(c, g, t)
else:
result = objectHeaderToIr(c, g, t)
of tyTuple:
cachedByName(c, t):
result = tupleToIr(c, g, t)
of tyProc:
cached(c, t):
if t.callConv == ccClosure:
result = closureToIr(c, g, t)
else:
result = procToIr(c, g, t)
of tyVarargs, tyOpenArray:
cached(c, t):
result = openArrayToIr(c, g, t)
of tyString:
if c.stringType.int < 0:
result = stringToIr(c, g)
c.stringType = result
else:
result = c.stringType
of tySequence:
cachedByName(c, t):
result = seqToIr(c, g, t)
of tyCstring:
cached(c, t):
let a = openType(g, AArrayPtrTy)
g.addBuiltinType Char8Id
result = finishType(g, a)
of tyUncheckedArray:
# We already handled the `ptr UncheckedArray` in a special way.
cached(c, t):
let elemType = typeToIr(c, g, t.lastSon)
let a = openType(g, LastArrayTy)
g.addType(elemType)
result = finishType(g, a)
of tyUntyped, tyTyped:
# this avoids a special case for system.echo which is not a generic but
# uses `varargs[typed]`:
result = VoidId
of tyNone, tyEmpty, tyTypeDesc,
tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
result = TypeId(-1)

View File

@@ -1,4 +1,4 @@
import os
import std/os
proc findNodeJs*(): string {.inline.} =
## Find NodeJS executable and return it as a string.

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