mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 10:53:40 +00:00
Compare commits
541 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f500679b1 | ||
|
|
93cb5889f4 | ||
|
|
2b075fc87d | ||
|
|
8f7fd28692 | ||
|
|
74b30de1c6 | ||
|
|
6947d96b5f | ||
|
|
689111936c | ||
|
|
34a594abec | ||
|
|
f10dda264c | ||
|
|
c5455c1515 | ||
|
|
334f2d6a87 | ||
|
|
29125f0bc7 | ||
|
|
becb06dd70 | ||
|
|
2ddeabceaf | ||
|
|
9fa69d222f | ||
|
|
d48fc130c1 | ||
|
|
c86e7a0ca9 | ||
|
|
8d553c5624 | ||
|
|
d9ed8f2717 | ||
|
|
35429f6252 | ||
|
|
7277d95b3c | ||
|
|
ba8ff51f2d | ||
|
|
a4982bd74d | ||
|
|
196f444699 | ||
|
|
67446d192d | ||
|
|
97c160271c | ||
|
|
c022120ebb | ||
|
|
e45bef46a1 | ||
|
|
a21a1c99cd | ||
|
|
f3f76cdc52 | ||
|
|
e6413f8fe4 | ||
|
|
fa6be0fb6a | ||
|
|
f04fe4e4a3 | ||
|
|
d1016a3bc9 | ||
|
|
0ae9f5e4df | ||
|
|
fda7c2e5bb | ||
|
|
237f50e0d9 | ||
|
|
34e61d5ae6 | ||
|
|
1dafcbd2a7 | ||
|
|
57e4b364d2 | ||
|
|
6d32ceaebb | ||
|
|
72e24284ef | ||
|
|
f4fd26d403 | ||
|
|
a4ec5d6be2 | ||
|
|
75f818f385 | ||
|
|
919d0d5ea8 | ||
|
|
34c9606b41 | ||
|
|
a69ab81fa9 | ||
|
|
90b7517656 | ||
|
|
244af30c58 | ||
|
|
795b5665dc | ||
|
|
c8556ef5df | ||
|
|
6c8ab9f898 | ||
|
|
547416b806 | ||
|
|
97c41c0f15 | ||
|
|
feaa364038 | ||
|
|
05c8e1d85d | ||
|
|
90efe870c8 | ||
|
|
860e827df6 | ||
|
|
834c35a137 | ||
|
|
75f01bd49f | ||
|
|
800384176e | ||
|
|
dc8f1ab52d | ||
|
|
ffaabdf21e | ||
|
|
431e01eaf2 | ||
|
|
a5e73ff408 | ||
|
|
37fd04a0eb | ||
|
|
dc1c3ed90e | ||
|
|
8d475993f8 | ||
|
|
8914baae78 | ||
|
|
fcf4f10c70 | ||
|
|
5394c6814b | ||
|
|
2ddda806a9 | ||
|
|
8775ef62fe | ||
|
|
63398611e7 | ||
|
|
a6988458c4 | ||
|
|
9346b138e1 | ||
|
|
c75c85cbf8 | ||
|
|
38384d040a | ||
|
|
605180fcfa | ||
|
|
be6e195585 | ||
|
|
873ab1f9ef | ||
|
|
4efece995e | ||
|
|
40e1a34831 | ||
|
|
bd9cbc91ba | ||
|
|
d7ae00349a | ||
|
|
61e98e9bf1 | ||
|
|
7f6c0afa59 | ||
|
|
6b89497b1e | ||
|
|
ab00c56904 | ||
|
|
6db962ebf5 | ||
|
|
05c76c7f1c | ||
|
|
365da2cb97 | ||
|
|
3bbba9e0ff | ||
|
|
4eaecfe59e | ||
|
|
f1373637e7 | ||
|
|
42f1c3944c | ||
|
|
1374741fae | ||
|
|
6cc267ab19 | ||
|
|
9af50a9c47 | ||
|
|
33f12c8493 | ||
|
|
60a204dfaa | ||
|
|
cf5b89f573 | ||
|
|
d01ea21451 | ||
|
|
d260855f35 | ||
|
|
8b8272d729 | ||
|
|
48d71e7ead | ||
|
|
0c2d7d9307 | ||
|
|
83b9c834e8 | ||
|
|
f66f9f261a | ||
|
|
47c41955bb | ||
|
|
9595e17ba5 | ||
|
|
2136f349f4 | ||
|
|
4ed76ff007 | ||
|
|
9628c7a4f8 | ||
|
|
cfe163795f | ||
|
|
8a5067912c | ||
|
|
3774f84e8c | ||
|
|
a2e2da2ab2 | ||
|
|
3d40226993 | ||
|
|
73d9194449 | ||
|
|
0a18975472 | ||
|
|
716642567c | ||
|
|
b28b321eba | ||
|
|
5724c685e9 | ||
|
|
5d3d8b52cd | ||
|
|
ee2b480da6 | ||
|
|
79e9634369 | ||
|
|
2c4b889d0a | ||
|
|
cf5099cdba | ||
|
|
8ea9c6454c | ||
|
|
2123969cc4 | ||
|
|
f0b22a7620 | ||
|
|
b5dd9735f4 | ||
|
|
2fc23370ec | ||
|
|
4c7ddcd79a | ||
|
|
377b6cc6bf | ||
|
|
569968a916 | ||
|
|
a6585c1df9 | ||
|
|
d84ca9c013 | ||
|
|
8ea5ba7000 | ||
|
|
bd22f6e9fd | ||
|
|
87cc6d0a91 | ||
|
|
031bbcdece | ||
|
|
2031f9e202 | ||
|
|
8f7b312f24 | ||
|
|
576c401816 | ||
|
|
1ab6879799 | ||
|
|
99b09e6609 | ||
|
|
516f5141ba | ||
|
|
fe12553cfb | ||
|
|
55806c8b36 | ||
|
|
4cbdebcd50 | ||
|
|
fef0b5a351 | ||
|
|
1735e585f2 | ||
|
|
c339651ae1 | ||
|
|
e7f03b0604 | ||
|
|
a88b3afa64 | ||
|
|
ac3a98be9e | ||
|
|
03dd55747c | ||
|
|
ca74debfbf | ||
|
|
23b7372aa0 | ||
|
|
d3f2715130 | ||
|
|
cbd883e501 | ||
|
|
8616161cc4 | ||
|
|
4472740440 | ||
|
|
80b80f64f0 | ||
|
|
e9c5b4f494 | ||
|
|
27feeea129 | ||
|
|
f4f13fbcfc | ||
|
|
1a4a1ab747 | ||
|
|
ce69b31309 | ||
|
|
911a651984 | ||
|
|
8f49466c85 | ||
|
|
f783924fd8 | ||
|
|
95d25a9d7f | ||
|
|
137fb97fb5 | ||
|
|
02f73120ae | ||
|
|
597670b1d4 | ||
|
|
88f1d4f154 | ||
|
|
6d5ddcde49 | ||
|
|
4974d9dad0 | ||
|
|
1a2ee566e3 | ||
|
|
a5ade112cb | ||
|
|
5e17c88416 | ||
|
|
f003664a14 | ||
|
|
3d634911b8 | ||
|
|
1f205a0f10 | ||
|
|
62df0b7586 | ||
|
|
d65a0a3144 | ||
|
|
58d4945c1c | ||
|
|
1c89ae6684 | ||
|
|
7fdbdb2f20 | ||
|
|
11fc6962ae | ||
|
|
1b49765122 | ||
|
|
c55ee7a191 | ||
|
|
0022ddb271 | ||
|
|
7d6695b51f | ||
|
|
f209041be0 | ||
|
|
25a13ad0e5 | ||
|
|
975ca268f0 | ||
|
|
3fd9c986f6 | ||
|
|
17e0dae12f | ||
|
|
8120d329ee | ||
|
|
832eb7e2eb | ||
|
|
13752aba99 | ||
|
|
9cfc3399bc | ||
|
|
b10ebc8d17 | ||
|
|
706d1264af | ||
|
|
6c94f456c7 | ||
|
|
cebaa87a16 | ||
|
|
ee916f051b | ||
|
|
d89fd45b9e | ||
|
|
11fd7c045e | ||
|
|
ea51ca8d25 | ||
|
|
c385fcb6be | ||
|
|
39757d421e | ||
|
|
a35b5fb813 | ||
|
|
96a02f1982 | ||
|
|
c1fbde1e5a | ||
|
|
c5030c8bc6 | ||
|
|
d5e8e5d985 | ||
|
|
0bdc4434e0 | ||
|
|
b67f7fab64 | ||
|
|
d9be82d381 | ||
|
|
f81b83df79 | ||
|
|
939682eba0 | ||
|
|
19f620c934 | ||
|
|
5d20ae6098 | ||
|
|
13a0e1a004 | ||
|
|
f7145dd26e | ||
|
|
1db543e8b2 | ||
|
|
238a4db3d9 | ||
|
|
a19d06e1f7 | ||
|
|
beb54a5a75 | ||
|
|
cfe89097e7 | ||
|
|
b5ee86b43f | ||
|
|
1227799b84 | ||
|
|
545058a4ea | ||
|
|
403b24faeb | ||
|
|
aa8715afde | ||
|
|
397eb361e9 | ||
|
|
ea4df85f34 | ||
|
|
e3a2af00ea | ||
|
|
349ee54838 | ||
|
|
a8d87c041c | ||
|
|
e7244c0d28 | ||
|
|
0c8cefcbef | ||
|
|
94497c790b | ||
|
|
74f4042f89 | ||
|
|
ec1d68fc64 | ||
|
|
20ff258a08 | ||
|
|
c7dc4ae86d | ||
|
|
2d872329ae | ||
|
|
96f5b693ba | ||
|
|
3c8be5b63f | ||
|
|
380697d3ff | ||
|
|
0cd5307633 | ||
|
|
ee44fe197b | ||
|
|
72190536cb | ||
|
|
7842428261 | ||
|
|
0dd198278e | ||
|
|
c452d706ae | ||
|
|
741411e0dc | ||
|
|
706011a21c | ||
|
|
018e63b46c | ||
|
|
093f5a1de5 | ||
|
|
975e8576ec | ||
|
|
2de409cd0c | ||
|
|
23ca21a9c4 | ||
|
|
31effe8c75 | ||
|
|
a2a6565e23 | ||
|
|
01389b5eb9 | ||
|
|
210f747596 | ||
|
|
65a0ec3964 | ||
|
|
1d0e1679a8 | ||
|
|
2c7577745b | ||
|
|
6864337dc2 | ||
|
|
ce67056f80 | ||
|
|
3a8b7d987b | ||
|
|
f8ab76ba61 | ||
|
|
5c9aea9c69 | ||
|
|
3a9920d8fd | ||
|
|
81eabe3b9e | ||
|
|
e68a91c8df | ||
|
|
346b989b5d | ||
|
|
8dcb6ddc89 | ||
|
|
20362cc0d2 | ||
|
|
e799d2fca0 | ||
|
|
4d41384f09 | ||
|
|
6032a14f26 | ||
|
|
bfd25121f9 | ||
|
|
faa4042e26 | ||
|
|
2aa2ac354f | ||
|
|
9c64374599 | ||
|
|
44c1b2a6df | ||
|
|
903ce6db28 | ||
|
|
56bde37add | ||
|
|
9f4fe7fd7a | ||
|
|
ee1ecbd51e | ||
|
|
05beb32d07 | ||
|
|
6af8b33485 | ||
|
|
8f563f2cc9 | ||
|
|
ae8ae8fa95 | ||
|
|
1d8fed5f6b | ||
|
|
ed57499427 | ||
|
|
1c7ffece0a | ||
|
|
cd9c47140e | ||
|
|
6651c40ba0 | ||
|
|
9cf0d07b9e | ||
|
|
82974d91ce | ||
|
|
937801e3aa | ||
|
|
58f1e22db3 | ||
|
|
6bc07c7e3f | ||
|
|
b9d3348dab | ||
|
|
66e2352bf9 | ||
|
|
f20e6ef901 | ||
|
|
dac77cc97e | ||
|
|
4143bb32f7 | ||
|
|
34de654aa7 | ||
|
|
8038ad4e58 | ||
|
|
3a9c88239b | ||
|
|
fc587256c3 | ||
|
|
7f902217a1 | ||
|
|
881d1dfdb6 | ||
|
|
d3780bb7bd | ||
|
|
51edd9bd60 | ||
|
|
c8a030a902 | ||
|
|
1380084f57 | ||
|
|
5584885226 | ||
|
|
26d3b4c3ab | ||
|
|
130e7182c4 | ||
|
|
f5026570c2 | ||
|
|
bcecce885f | ||
|
|
b740e8cca8 | ||
|
|
1bae14aa25 | ||
|
|
ce8d3e02f5 | ||
|
|
a5e595d8ad | ||
|
|
6c34f62785 | ||
|
|
46e1322d29 | ||
|
|
27b54fdc76 | ||
|
|
d594e70d57 | ||
|
|
6bf9265d24 | ||
|
|
a627c9ba9c | ||
|
|
7cec03eb1b | ||
|
|
123a7ff29f | ||
|
|
c0d50ddc26 | ||
|
|
2193c3fb70 | ||
|
|
c2b825713c | ||
|
|
ae011eaeea | ||
|
|
8fe518ed47 | ||
|
|
64927c6ae7 | ||
|
|
21c0564573 | ||
|
|
12347eae74 | ||
|
|
52cadfc3d7 | ||
|
|
528e2b2271 | ||
|
|
0c0df28619 | ||
|
|
a2a1c2b7f1 | ||
|
|
41c4ed8dca | ||
|
|
f6167cb0c8 | ||
|
|
72ce16990b | ||
|
|
ea3a4203fa | ||
|
|
24b24c17b1 | ||
|
|
e80884665d | ||
|
|
f4009f0957 | ||
|
|
728a99d5cd | ||
|
|
019a3180f8 | ||
|
|
fb13e3608b | ||
|
|
f5804a36b9 | ||
|
|
a83c535ed4 | ||
|
|
3c71429eca | ||
|
|
9e1b199e78 | ||
|
|
b2f2b34fe5 | ||
|
|
7be1bb572e | ||
|
|
40476fa24f | ||
|
|
3054cbe422 | ||
|
|
b31aed01f1 | ||
|
|
9c7f04dacb | ||
|
|
c5ee216c42 | ||
|
|
ede6540c55 | ||
|
|
0c14372a8c | ||
|
|
6deb3a90ae | ||
|
|
e0e1061562 | ||
|
|
d96c5b2396 | ||
|
|
09835a1d9e | ||
|
|
0823b9d177 | ||
|
|
b5068f427a | ||
|
|
1cee3c7f18 | ||
|
|
844ba2168b | ||
|
|
d5437b7a4a | ||
|
|
faa9ae08b0 | ||
|
|
7b596b4e1f | ||
|
|
cd06f0769f | ||
|
|
0cce145dac | ||
|
|
43f7e160ba | ||
|
|
5a71c36d25 | ||
|
|
1299dd4651 | ||
|
|
51a0f3de6e | ||
|
|
e2b6021630 | ||
|
|
428b64251f | ||
|
|
5b0b90fb49 | ||
|
|
2f5481ce88 | ||
|
|
9aeb5c254c | ||
|
|
4e1bc4216a | ||
|
|
316141162b | ||
|
|
8d8a90e079 | ||
|
|
105e134c3f | ||
|
|
85c8b5b304 | ||
|
|
2d470c9afd | ||
|
|
94a6b85538 | ||
|
|
90c5dfc32c | ||
|
|
a7b671dad5 | ||
|
|
fb11c4404e | ||
|
|
1adcab885b | ||
|
|
5ddbf2372e | ||
|
|
8f668c2373 | ||
|
|
3daf7dd2ac | ||
|
|
4b4b97018b | ||
|
|
aa5fc4af58 | ||
|
|
062e77bce0 | ||
|
|
d04f9c426e | ||
|
|
52809cd3dd | ||
|
|
05a8b65eea | ||
|
|
b1a555dd52 | ||
|
|
f5453e453e | ||
|
|
7d425e712e | ||
|
|
e6f5e49184 | ||
|
|
cd370e4725 | ||
|
|
42184227aa | ||
|
|
14ce1a91ce | ||
|
|
ff7b83f266 | ||
|
|
522b184d5a | ||
|
|
d339c58628 | ||
|
|
01b6c5d0d1 | ||
|
|
1bc501f8ce | ||
|
|
aa8d62f89c | ||
|
|
60a8eaaaa5 | ||
|
|
f3da96d880 | ||
|
|
87c306061b | ||
|
|
2b1885a0fa | ||
|
|
9c87f2cb4b | ||
|
|
03b6999499 | ||
|
|
2690ab01c0 | ||
|
|
c79fb859f1 | ||
|
|
2d658e8de5 | ||
|
|
0036bb976b | ||
|
|
b0f3d1e874 | ||
|
|
9f03b98de5 | ||
|
|
0b7e22635e | ||
|
|
3642f4d375 | ||
|
|
f292393816 | ||
|
|
6ec663f7bc | ||
|
|
6d02ac1ba0 | ||
|
|
ce1fa86095 | ||
|
|
4900550e9c | ||
|
|
9fe2356e74 | ||
|
|
37ab27bd99 | ||
|
|
5e22d8bc3c | ||
|
|
6b102d5c13 | ||
|
|
51f8649e36 | ||
|
|
df27b427af | ||
|
|
e57f755b78 | ||
|
|
d78c7aa697 | ||
|
|
435a152c66 | ||
|
|
6c2de9b294 | ||
|
|
babc7d8c16 | ||
|
|
022bd12e82 | ||
|
|
3c528c987c | ||
|
|
52d94c1c86 | ||
|
|
87de7f9193 | ||
|
|
520b16b81e | ||
|
|
98403a06e7 | ||
|
|
4bdeddcac5 | ||
|
|
9be3559ed2 | ||
|
|
f2a9765014 | ||
|
|
ac8c44e08d | ||
|
|
850132d37c | ||
|
|
a1ee2ee566 | ||
|
|
9306b5e917 | ||
|
|
67a636bec8 | ||
|
|
9a6230ee5a | ||
|
|
7e840e0164 | ||
|
|
cd760b00c2 | ||
|
|
0cce80071b | ||
|
|
5aeabdac8f | ||
|
|
2d678fa45c | ||
|
|
ee1c4de48a | ||
|
|
b3e02ef0c3 | ||
|
|
893c638485 | ||
|
|
9f51b52f5f | ||
|
|
bcfb30a8be | ||
|
|
7948e2f2c2 | ||
|
|
6b31400ade | ||
|
|
a713aee682 | ||
|
|
aa7e7f5f63 | ||
|
|
8d7b3baf9f | ||
|
|
274cdba334 | ||
|
|
a04dada93d | ||
|
|
4d170ac586 | ||
|
|
e3a8d98626 | ||
|
|
41145210a8 | ||
|
|
3c2b32aebe | ||
|
|
613f1e94ae | ||
|
|
660a9cecf0 | ||
|
|
bffd2e0330 | ||
|
|
d357a2e9a5 | ||
|
|
fca3504105 | ||
|
|
bf45efb1ea | ||
|
|
517a2fc275 | ||
|
|
4c56f9d675 | ||
|
|
de93f82d6e | ||
|
|
fa1819eb2d | ||
|
|
0fde5a0cc2 | ||
|
|
090139eb6f | ||
|
|
ee4bf757ea | ||
|
|
b0b4b498c8 | ||
|
|
d102571d78 | ||
|
|
1f418de2cc | ||
|
|
21bdc8ff0f | ||
|
|
9f7b664836 | ||
|
|
b24f58183d | ||
|
|
b8efee444c | ||
|
|
336549c49d | ||
|
|
2d4e1f981e | ||
|
|
13110fc5d3 | ||
|
|
700ca2eb60 | ||
|
|
5945ad41a1 | ||
|
|
7f113dc875 | ||
|
|
e13f86a596 | ||
|
|
6c96892d5e | ||
|
|
dd0cc389bb | ||
|
|
75e50f804a | ||
|
|
599f1ad6b3 | ||
|
|
d991600a00 | ||
|
|
b873eaedf5 | ||
|
|
39a6106e8b | ||
|
|
e262d9506d | ||
|
|
ddc7f35e05 | ||
|
|
f70a17f885 | ||
|
|
7a79f465fa | ||
|
|
b6450a98ea |
20
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
20
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -10,16 +10,6 @@ body:
|
||||
Please provide a minimal code example that reproduces the bug if possible.
|
||||
Reports with a reproducible example or detailed information will likely receive fixes faster.
|
||||
|
||||
- type: textarea
|
||||
id: nim-version
|
||||
attributes:
|
||||
label: Nim Version
|
||||
description: |
|
||||
Can be obtained from `nim -v` on the command line along with the OS/architecture.
|
||||
For development versions, including the commit hash may help.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
@@ -29,6 +19,16 @@ body:
|
||||
placeholder: Bug reports with reproducible code or detailed information will be fixed faster.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: nim-version
|
||||
attributes:
|
||||
label: Nim Version
|
||||
description: |
|
||||
Can be obtained from `nim -v` on the command line along with the OS/architecture.
|
||||
For development versions, make sure to include the commit hash.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: current-logs
|
||||
|
||||
11
.github/dependabot.yml
vendored
11
.github/dependabot.yml
vendored
@@ -1,11 +0,0 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
2
.github/workflows/bisects.yml
vendored
2
.github/workflows/bisects.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
name: ${{ matrix.platform }}-bisects
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Install OpenSSL (Windows)
|
||||
if: |
|
||||
|
||||
4
.github/workflows/ci_docs.yml
vendored
4
.github/workflows/ci_docs.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
if: |
|
||||
github.event_name == 'push' && github.ref == 'refs/heads/devel' &&
|
||||
matrix.target == 'linux'
|
||||
uses: crazy-max/ghaction-github-pages@v5
|
||||
uses: crazy-max/ghaction-github-pages@v4
|
||||
with:
|
||||
build_dir: doc/html
|
||||
env:
|
||||
|
||||
8
.github/workflows/ci_packages.yml
vendored
8
.github/workflows/ci_packages.yml
vendored
@@ -33,14 +33,14 @@ jobs:
|
||||
NIM_TESTAMENT_BATCH: ${{ matrix.batch }}
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js'
|
||||
uses: actions/setup-node@v6
|
||||
- name: 'Install node.js 20.x'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
|
||||
8
.github/workflows/ci_publish.yml
vendored
8
.github/workflows/ci_publish.yml
vendored
@@ -17,14 +17,14 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js'
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: ''
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
run: nim c -r -d:release ci/action.nim
|
||||
|
||||
- name: 'Comment'
|
||||
uses: actions/github-script@v9
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
|
||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v10
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
days-before-pr-stale: 365
|
||||
days-before-pr-close: 30
|
||||
|
||||
17
changelog.md
17
changelog.md
@@ -27,17 +27,13 @@ errors.
|
||||
|
||||
- With `-d:nimPreviewDuplicateModuleError`, importing two modules that share the same name becomes a compile-time error. This includes importing the same module more than once. Use `import foo as foo1` (or other aliases) to avoid collisions.
|
||||
|
||||
- Adds the switch `--mangle:nim|cpp`, which selects `nim` or `cpp` style name mangling when used with `debuginfo` on, defaults to `cpp`.
|
||||
- Adds the switch `--mangle:nim|cpp`, which selects `nim` or `cpp` style name mangling when used with `debuginfo` on, defaults to `nim`. The default is changed from `cpp` to `nim`.
|
||||
|
||||
- The second parameter of `succ`, `pred`, `inc`, and `dec` in `system` now accepts `SomeInteger` (previously `Ordinal`).
|
||||
|
||||
- Bitshift operators (`shl`, `shr`, `ashr`) now apply bitmasking to the right operand in the C/C++/VM/JS backends.
|
||||
|
||||
- Adds a new warning `--warning:ImplicitRangeConversion` that detects downsizing implicit conversions to range types (e.g., `int -> range[0..255]` or `range[1..256] -> range[0..255]`) that could cause runtime panics. Safe conversions like `range[0..255] -> range[0..65535]` and explicit casts do not trigger warnings. `int` to `Natural` and `Positive` conversions do not trigger warnings, which can be enabled with `--warning:systemRangeConversion`.
|
||||
|
||||
- Procedure compatibility also checks the backend representation of the
|
||||
parameter and result types, not just their source-level shape. Use
|
||||
`--legacy:procParamTypeBackendAliases` to restore the older behavior.
|
||||
- Adds a new warning enabled by `--warning:ImplicitRangeConversion` that detects downsizing implicit conversions to range types (e.g., `int -> range[0..255]` or `range[1..256] -> range[0..255]`) that could cause runtime panics. Safe conversions like `range[0..255] -> range[0..65535]` and explicit casts are not warned on.
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
@@ -64,26 +60,17 @@ parameter and result types, not just their source-level shape. Use
|
||||
- `copyDirWithPermissions` to recursively preserve attributes
|
||||
|
||||
- `system.setLenUninit` now supports refc, JS and VM backends.
|
||||
- `system.setLenUninit` for the `string` type. Allows setting length without initializing new memory on growth.
|
||||
|
||||
- `std/parseopt` now supports multiple parser modes via a `CliMode` enum.
|
||||
Modes include `Nim` (default, fully compatible) and two new experimental modes:
|
||||
`Lax` and `Gnu` for different option parsing behaviors.
|
||||
|
||||
- `std/nre2` is added to replace deprecated NRE.
|
||||
|
||||
[//]: # "Changes:"
|
||||
|
||||
- `std/math` The `^` symbol now supports floating-point as exponent in addition to the Natural type.
|
||||
- `min`, `max`, and `sequtils`' `minIndex`, `maxIndex` and `minmax` for `openArray`s now accept a comparison function.
|
||||
- `system.substr` implementation now uses `copymem` (wrapped C `memcpy`) for copying data, if available at compilation.
|
||||
- `system.newStringUninit` is now considered free of side-effects allowing it to be used with `--experimental:strictFuncs`.
|
||||
- `std/re` and `std/nre` are deprecated as PCRE library is obsolete.
|
||||
Use https://github.com/nitely/nim-regex or `std/nre2`.
|
||||
See: https://github.com/nim-lang/Nim/issues/23668.
|
||||
- `std/pegs` now correctly lexes UTF-8 bytes inside bare identifier-style
|
||||
terminals, so case-insensitive matching of non-ASCII terms (e.g. ``\i café``)
|
||||
works without single-quoting.
|
||||
|
||||
## Language changes
|
||||
|
||||
|
||||
1776
compiler/ast.nim
1776
compiler/ast.nim
File diff suppressed because it is too large
Load Diff
1664
compiler/ast2nif.nim
1664
compiler/ast2nif.nim
File diff suppressed because it is too large
Load Diff
@@ -68,6 +68,8 @@ template mdbg*: bool {.deprecated.} =
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
proc lookupInRecord*(n: PNode, field: PIdent): PSym
|
||||
proc mustRehash*(length, counter: int): bool
|
||||
proc nextTry*(h, maxHash: Hash): Hash {.inline.}
|
||||
|
||||
# ------------- table[int, int] ---------------------------------------------
|
||||
const
|
||||
@@ -214,6 +216,10 @@ proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym =
|
||||
proc hashNode(p: RootRef): Hash =
|
||||
result = hash(cast[pointer](p))
|
||||
|
||||
proc mustRehash(length, counter: int): bool =
|
||||
assert(length > counter)
|
||||
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||
|
||||
import std/tables
|
||||
|
||||
const backrefStyle = "\e[90m"
|
||||
@@ -478,6 +484,12 @@ proc debug(n: PNode; conf: ConfigRef) =
|
||||
this.value(n)
|
||||
echo($this.res)
|
||||
|
||||
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
|
||||
result = ((5 * h) + 1) and maxHash
|
||||
# For any initial h in range(maxHash), repeating that maxHash times
|
||||
# generates each int in range(maxHash) exactly once (see any text on
|
||||
# random-number generation for proof).
|
||||
|
||||
proc objectSetContains*(t: TObjectSet, obj: RootRef): bool =
|
||||
# returns true whether n is in t
|
||||
var h: Hash = hashNode(obj) and high(t.data) # start with real hash value
|
||||
@@ -525,6 +537,95 @@ proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool =
|
||||
inc(t.counter)
|
||||
result = false
|
||||
|
||||
proc strTableContains*(t: TStrTable, n: PSym): bool =
|
||||
var h: Hash = n.name.h and high(t.data) # start with real hash value
|
||||
while t.data[h] != nil:
|
||||
if (t.data[h] == n):
|
||||
return true
|
||||
h = nextTry(h, high(t.data))
|
||||
result = false
|
||||
|
||||
proc strTableRawInsert(data: var seq[PSym], n: PSym) =
|
||||
var h: Hash = n.name.h and high(data)
|
||||
while data[h] != nil:
|
||||
if data[h] == n:
|
||||
# allowed for 'export' feature:
|
||||
#InternalError(n.info, "StrTableRawInsert: " & n.name.s)
|
||||
return
|
||||
h = nextTry(h, high(data))
|
||||
assert(data[h] == nil)
|
||||
data[h] = n
|
||||
|
||||
proc symTabReplaceRaw(data: var seq[PSym], prevSym: PSym, newSym: PSym) =
|
||||
assert prevSym.name.h == newSym.name.h
|
||||
var h: Hash = prevSym.name.h and high(data)
|
||||
while data[h] != nil:
|
||||
if data[h] == prevSym:
|
||||
data[h] = newSym
|
||||
return
|
||||
h = nextTry(h, high(data))
|
||||
assert false
|
||||
|
||||
proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
|
||||
symTabReplaceRaw(t.data, prevSym, newSym)
|
||||
|
||||
proc strTableEnlarge(t: var TStrTable) =
|
||||
var n: seq[PSym]
|
||||
newSeq(n, t.data.len * GrowthFactor)
|
||||
for i in 0..high(t.data):
|
||||
if t.data[i] != nil: strTableRawInsert(n, t.data[i])
|
||||
swap(t.data, n)
|
||||
|
||||
proc strTableAdd*(t: var TStrTable, n: PSym) =
|
||||
if mustRehash(t.data.len, t.counter): strTableEnlarge(t)
|
||||
strTableRawInsert(t.data, n)
|
||||
inc(t.counter)
|
||||
|
||||
proc strTableInclReportConflict*(t: var TStrTable, n: PSym;
|
||||
onConflictKeepOld = false): PSym =
|
||||
# if `t` has a conflicting symbol (same identifier as `n`), return it
|
||||
# otherwise return `nil`. Incl `n` to `t` unless `onConflictKeepOld = true`
|
||||
# and a conflict was found.
|
||||
assert n.name != nil
|
||||
var h: Hash = n.name.h and high(t.data)
|
||||
var replaceSlot = -1
|
||||
while true:
|
||||
var it = t.data[h]
|
||||
if it == nil: break
|
||||
# Semantic checking can happen multiple times thanks to templates
|
||||
# and overloading: (var x=@[]; x).mapIt(it).
|
||||
# So it is possible the very same sym is added multiple
|
||||
# times to the symbol table which we allow here with the 'it == n' check.
|
||||
if it.name.id == n.name.id:
|
||||
if it == n: return nil
|
||||
replaceSlot = h
|
||||
h = nextTry(h, high(t.data))
|
||||
if replaceSlot >= 0:
|
||||
result = t.data[replaceSlot] # found it
|
||||
if not onConflictKeepOld:
|
||||
t.data[replaceSlot] = n # overwrite it with newer definition!
|
||||
return result # but return the old one
|
||||
elif mustRehash(t.data.len, t.counter):
|
||||
strTableEnlarge(t)
|
||||
strTableRawInsert(t.data, n)
|
||||
else:
|
||||
assert(t.data[h] == nil)
|
||||
t.data[h] = n
|
||||
inc(t.counter)
|
||||
result = nil
|
||||
|
||||
proc strTableIncl*(t: var TStrTable, n: PSym;
|
||||
onConflictKeepOld = false): bool {.discardable.} =
|
||||
result = strTableInclReportConflict(t, n, onConflictKeepOld) != nil
|
||||
|
||||
proc strTableGet*(t: TStrTable, name: PIdent): PSym =
|
||||
var h: Hash = name.h and high(t.data)
|
||||
while true:
|
||||
result = t.data[h]
|
||||
if result == nil: break
|
||||
if result.name.id == name.id: break
|
||||
h = nextTry(h, high(t.data))
|
||||
|
||||
|
||||
type
|
||||
TIdentIter* = object # iterator over all syms with same identifier
|
||||
|
||||
@@ -202,11 +202,7 @@ type
|
||||
tySequence,
|
||||
tyProc,
|
||||
tyPointer, tyOpenArray,
|
||||
tyString, tyCstring,
|
||||
tyForward,
|
||||
# a type not yet semchecked
|
||||
# When semcheck a type section, all types defined in it are initialized to tyForward
|
||||
|
||||
tyString, tyCstring, tyForward,
|
||||
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
|
||||
tyFloat, tyFloat32, tyFloat64, tyFloat128,
|
||||
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
|
||||
@@ -701,7 +697,6 @@ type
|
||||
|
||||
PLib* = ref TLib
|
||||
TSym* {.acyclic.} = object # Keep in sync with ast2nif.nim
|
||||
# Check `transitionSymKindCommon` in ast.nim when add a new field.
|
||||
itemId*: ItemId
|
||||
# proc and type instantiations are cached in the generic symbol
|
||||
state*: ItemState
|
||||
|
||||
@@ -69,7 +69,7 @@ proc copyHalf[Key, Val](h, result: Node[Key, Val]) =
|
||||
result.links[j] = h.links[Mhalf + j]
|
||||
else:
|
||||
for j in 0..<Mhalf:
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc) or defined(gcYrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
result.vals[j] = move h.vals[Mhalf + j]
|
||||
else:
|
||||
shallowCopy(result.vals[j], h.vals[Mhalf + j])
|
||||
@@ -92,7 +92,7 @@ proc insert[Key, Val](h: Node[Key, Val], key: Key, val: Val): Node[Key, Val] =
|
||||
if less(key, h.keys[j]): break
|
||||
inc j
|
||||
for i in countdown(h.entries, j+1):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc) or defined(gcYrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
h.vals[i] = move h.vals[i-1]
|
||||
else:
|
||||
shallowCopy(h.vals[i], h.vals[i-1])
|
||||
|
||||
121
compiler/cbuilder.nim
Normal file
121
compiler/cbuilder.nim
Normal file
@@ -0,0 +1,121 @@
|
||||
type
|
||||
Snippet = string
|
||||
Builder = string
|
||||
|
||||
template newBuilder(s: string): Builder =
|
||||
s
|
||||
|
||||
proc addField(obj: var Builder; name, typ: Snippet) =
|
||||
obj.add('\t')
|
||||
obj.add(typ)
|
||||
obj.add(" ")
|
||||
obj.add(name)
|
||||
obj.add(";\n")
|
||||
|
||||
proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool; initializer: Snippet) =
|
||||
obj.add('\t')
|
||||
if field.alignment > 0:
|
||||
obj.add("NIM_ALIGN(")
|
||||
obj.addInt(field.alignment)
|
||||
obj.add(") ")
|
||||
obj.add(typ)
|
||||
if sfNoalias in field.flags:
|
||||
obj.add(" NIM_NOALIAS")
|
||||
obj.add(" ")
|
||||
obj.add(name)
|
||||
if isFlexArray:
|
||||
obj.add("[SEQ_DECL_SIZE]")
|
||||
if field.bitsize != 0:
|
||||
obj.add(":")
|
||||
obj.addInt(field.bitsize)
|
||||
if initializer.len != 0:
|
||||
obj.add(initializer)
|
||||
obj.add(";\n")
|
||||
|
||||
proc structOrUnion(t: PType): Snippet =
|
||||
let t = t.skipTypes({tyAlias, tySink})
|
||||
if tfUnion in t.flags: "union"
|
||||
else: "struct"
|
||||
|
||||
proc ptrType(t: Snippet): Snippet =
|
||||
t & "*"
|
||||
|
||||
template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: string; body: typed) =
|
||||
if tfPacked in typ.flags:
|
||||
if hasAttribute in CC[m.config.cCompiler].props:
|
||||
obj.add(structOrUnion(typ))
|
||||
obj.add(" __attribute__((__packed__))")
|
||||
else:
|
||||
obj.add("#pragma pack(push, 1)\n")
|
||||
obj.add(structOrUnion(typ))
|
||||
else:
|
||||
obj.add(structOrUnion(typ))
|
||||
obj.add(" ")
|
||||
obj.add(name)
|
||||
type BaseClassKind = enum
|
||||
bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti
|
||||
var baseKind = bcNone
|
||||
if typ.kind == tyObject:
|
||||
if typ.baseClass == nil:
|
||||
if lacksMTypeField(typ):
|
||||
baseKind = bcNone
|
||||
elif optTinyRtti in m.config.globalOptions:
|
||||
baseKind = bcNoneTinyRtti
|
||||
else:
|
||||
baseKind = bcNoneRtti
|
||||
elif m.compileToCpp:
|
||||
baseKind = bcCppInherit
|
||||
else:
|
||||
baseKind = bcSupField
|
||||
if baseKind == bcCppInherit:
|
||||
obj.add(" : public ")
|
||||
obj.add(baseType)
|
||||
obj.add(" ")
|
||||
obj.add("{\n")
|
||||
let currLen = obj.len
|
||||
case baseKind
|
||||
of bcNone:
|
||||
# rest of the options add a field or don't need it due to inheritance,
|
||||
# we need to add the dummy field for uncheckedarray ahead of time
|
||||
# so that it remains trailing
|
||||
if typ.itemId notin m.g.graph.memberProcsPerType and
|
||||
typ.n != nil and typ.n.len == 1 and typ.n[0].kind == nkSym and
|
||||
typ.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray:
|
||||
# only consists of flexible array field, add *initial* dummy field
|
||||
obj.addField(name = "dummy", typ = "char")
|
||||
of bcCppInherit: discard
|
||||
of bcNoneRtti:
|
||||
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimType")))
|
||||
of bcNoneTinyRtti:
|
||||
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimTypeV2")))
|
||||
of bcSupField:
|
||||
obj.addField(name = "Sup", typ = baseType)
|
||||
body
|
||||
if baseKind == bcNone and currLen == obj.len and typ.itemId notin m.g.graph.memberProcsPerType:
|
||||
# no fields were added, add dummy field
|
||||
obj.addField(name = "dummy", typ = "char")
|
||||
obj.add("};\n")
|
||||
if tfPacked in typ.flags and hasAttribute notin CC[m.config.cCompiler].props:
|
||||
result.add("#pragma pack(pop)\n")
|
||||
|
||||
template addFieldWithStructType(obj: var Builder; m: BModule; parentTyp: PType; fieldName: string, body: typed) =
|
||||
## adds a field with a `struct { ... }` type, building it according to `body`
|
||||
obj.add('\t')
|
||||
if tfPacked in parentTyp.flags:
|
||||
if hasAttribute in CC[m.config.cCompiler].props:
|
||||
obj.add("struct __attribute__((__packed__)) {\n")
|
||||
else:
|
||||
obj.add("#pragma pack(push, 1)\nstruct {")
|
||||
else:
|
||||
obj.add("struct {\n")
|
||||
body
|
||||
obj.add("} ")
|
||||
obj.add(fieldName)
|
||||
obj.add(";\n")
|
||||
if tfPacked in parentTyp.flags and hasAttribute notin CC[m.config.cCompiler].props:
|
||||
result.add("#pragma pack(pop)\n")
|
||||
|
||||
template addAnonUnion(obj: var Builder; body: typed) =
|
||||
obj.add "union{\n"
|
||||
body
|
||||
obj.add("};\n")
|
||||
@@ -1,164 +0,0 @@
|
||||
import ropes, int128
|
||||
|
||||
type
|
||||
Snippet* = string
|
||||
Builder* = object
|
||||
buf*: string
|
||||
indents*: int
|
||||
|
||||
template newBuilder*(s: string): Builder =
|
||||
Builder(buf: s)
|
||||
|
||||
proc extract*(builder: Builder): Snippet =
|
||||
builder.buf
|
||||
|
||||
proc add*(builder: var Builder, s: string) =
|
||||
builder.buf.add(s)
|
||||
|
||||
proc add*(builder: var Builder, s: char) =
|
||||
builder.buf.add(s)
|
||||
|
||||
proc addNewline*(builder: var Builder) =
|
||||
builder.add('\n')
|
||||
for i in 0 ..< builder.indents:
|
||||
builder.add('\t')
|
||||
|
||||
proc addLineEnd*(builder: var Builder, s: string) =
|
||||
builder.add(s)
|
||||
builder.addNewline()
|
||||
|
||||
proc addLineEndIndent*(builder: var Builder, s: string) =
|
||||
inc builder.indents
|
||||
builder.add(s)
|
||||
builder.addNewline()
|
||||
|
||||
proc addDedent*(builder: var Builder, s: string) =
|
||||
if builder.buf.len > 0 and builder.buf[^1] == '\t':
|
||||
builder.buf.setLen(builder.buf.len - 1)
|
||||
builder.add(s)
|
||||
dec builder.indents
|
||||
|
||||
proc addLineEndDedent*(builder: var Builder, s: string) =
|
||||
builder.addDedent(s)
|
||||
builder.addNewline()
|
||||
|
||||
proc addLineComment*(builder: var Builder, comment: string) =
|
||||
# probably no-op on nifc
|
||||
builder.add("// ")
|
||||
builder.add(comment)
|
||||
builder.addNewline()
|
||||
|
||||
proc addIntValue*(builder: var Builder, val: int) =
|
||||
builder.buf.addInt(val)
|
||||
|
||||
proc addIntValue*(builder: var Builder, val: int64) =
|
||||
builder.buf.addInt(val)
|
||||
|
||||
proc addIntValue*(builder: var Builder, val: uint64) =
|
||||
builder.buf.addInt(val)
|
||||
|
||||
proc addIntValue*(builder: var Builder, val: Int128) =
|
||||
builder.buf.addInt128(val)
|
||||
|
||||
template cIntValue*(val: int): Snippet = $val
|
||||
template cIntValue*(val: int64): Snippet = $val
|
||||
template cIntValue*(val: uint64): Snippet = $val
|
||||
template cIntValue*(val: Int128): Snippet = $val
|
||||
|
||||
template cUintValue*(val: uint): Snippet = $val & "U"
|
||||
|
||||
import std/formatfloat
|
||||
|
||||
proc addFloatValue*(builder: var Builder, val: float) =
|
||||
builder.buf.addFloat(val)
|
||||
|
||||
template cFloatValue*(val: float): Snippet = $val
|
||||
|
||||
proc addInt64Literal*(result: var Builder; i: BiggestInt) =
|
||||
if i > low(int64):
|
||||
result.add "IL64($1)" % [rope(i)]
|
||||
else:
|
||||
result.add "(IL64(-9223372036854775807) - IL64(1))"
|
||||
|
||||
proc addUint64Literal*(result: var Builder; i: uint64) =
|
||||
result.add rope($i & "ULL")
|
||||
|
||||
proc addIntLiteral*(result: var Builder; i: BiggestInt) =
|
||||
if i > low(int32) and i <= high(int32):
|
||||
result.addIntValue(i)
|
||||
elif i == low(int32):
|
||||
# Nim has the same bug for the same reasons :-)
|
||||
result.add "(-2147483647 -1)"
|
||||
elif i > low(int64):
|
||||
result.add "IL64($1)" % [rope(i)]
|
||||
else:
|
||||
result.add "(IL64(-9223372036854775807) - IL64(1))"
|
||||
|
||||
proc addIntLiteral*(result: var Builder; i: Int128) =
|
||||
addIntLiteral(result, toInt64(i))
|
||||
|
||||
proc cInt64Literal*(i: BiggestInt): Snippet =
|
||||
if i > low(int64):
|
||||
result = "IL64($1)" % [rope(i)]
|
||||
else:
|
||||
result = "(IL64(-9223372036854775807) - IL64(1))"
|
||||
|
||||
proc cUint64Literal*(i: uint64): Snippet =
|
||||
result = $i & "ULL"
|
||||
|
||||
proc cIntLiteral*(i: BiggestInt): Snippet =
|
||||
if i > low(int32) and i <= high(int32):
|
||||
result = rope(i)
|
||||
elif i == low(int32):
|
||||
# Nim has the same bug for the same reasons :-)
|
||||
result = "(-2147483647 -1)"
|
||||
elif i > low(int64):
|
||||
result = "IL64($1)" % [rope(i)]
|
||||
else:
|
||||
result = "(IL64(-9223372036854775807) - IL64(1))"
|
||||
|
||||
proc cIntLiteral*(i: Int128): Snippet =
|
||||
result = cIntLiteral(toInt64(i))
|
||||
|
||||
const
|
||||
NimInt* = "NI"
|
||||
NimInt8* = "NI8"
|
||||
NimInt16* = "NI16"
|
||||
NimInt32* = "NI32"
|
||||
NimInt64* = "NI64"
|
||||
CInt* = "int"
|
||||
NimUint* = "NU"
|
||||
NimUint8* = "NU8"
|
||||
NimUint16* = "NU16"
|
||||
NimUint32* = "NU32"
|
||||
NimUint64* = "NU64"
|
||||
NimFloat* = "NF"
|
||||
NimFloat32* = "NF32"
|
||||
NimFloat64* = "NF64"
|
||||
NimFloat128* = "NF128" # not actually defined
|
||||
NimNan* = "NAN"
|
||||
NimInf* = "INF"
|
||||
NimBool* = "NIM_BOOL"
|
||||
NimTrue* = "NIM_TRUE"
|
||||
NimFalse* = "NIM_FALSE"
|
||||
NimChar* = "NIM_CHAR"
|
||||
CChar* = "char"
|
||||
NimCstring* = "NCSTRING"
|
||||
NimNil* = "NIM_NIL"
|
||||
CNil* = "NULL"
|
||||
NimStrlitFlag* = "NIM_STRLIT_FLAG"
|
||||
CVoid* = "void"
|
||||
CPointer* = "void*"
|
||||
CConstPointer* = "NIM_CONST void*"
|
||||
|
||||
proc cIntType*(bits: BiggestInt): Snippet =
|
||||
"NI" & $bits
|
||||
|
||||
proc cUintType*(bits: BiggestInt): Snippet =
|
||||
"NU" & $bits
|
||||
|
||||
type
|
||||
IfBuilderState* = enum
|
||||
WaitingIf, WaitingElseIf, InBlock
|
||||
IfBuilder* = object
|
||||
state*: IfBuilderState
|
||||
@@ -1,668 +0,0 @@
|
||||
type VarKind = enum
|
||||
Local
|
||||
Global
|
||||
Threadvar
|
||||
Const
|
||||
AlwaysConst ## const even on C++
|
||||
|
||||
proc addVarHeader(builder: var Builder, kind: VarKind) =
|
||||
## adds modifiers for given var kind:
|
||||
## Local has no modifier
|
||||
## Global has `static` modifier
|
||||
## Const has `static NIM_CONST` modifier
|
||||
## AlwaysConst has `static const` modifier (NIM_CONST is no-op on C++)
|
||||
## Threadvar is unimplemented
|
||||
case kind
|
||||
of Local: discard
|
||||
of Global:
|
||||
builder.add("static ")
|
||||
of Const:
|
||||
builder.add("static NIM_CONST ")
|
||||
of AlwaysConst:
|
||||
builder.add("static const ")
|
||||
of Threadvar:
|
||||
doAssert false, "unimplemented"
|
||||
|
||||
proc addVar(builder: var Builder, kind: VarKind = Local, name: string, typ: Snippet, initializer: Snippet = "") =
|
||||
## adds a variable declaration to the builder
|
||||
builder.addVarHeader(kind)
|
||||
builder.add(typ)
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
if initializer.len != 0:
|
||||
builder.add(" = ")
|
||||
builder.add(initializer)
|
||||
builder.addLineEnd(";")
|
||||
|
||||
template addVarWithType(builder: var Builder, kind: VarKind = Local, name: string, body: typed) =
|
||||
## adds a variable declaration to the builder, with the `body` building the type
|
||||
builder.addVarHeader(kind)
|
||||
body
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
builder.addLineEnd(";")
|
||||
|
||||
template addVarWithInitializer(builder: var Builder, kind: VarKind = Local, name: string,
|
||||
typ: Snippet, initializerBody: typed) =
|
||||
## adds a variable declaration to the builder, with
|
||||
## `initializerBody` building the initializer. initializer must be provided
|
||||
builder.addVarHeader(kind)
|
||||
builder.add(typ)
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
builder.add(" = ")
|
||||
initializerBody
|
||||
builder.addLineEnd(";")
|
||||
|
||||
template addVarWithTypeAndInitializer(builder: var Builder, kind: VarKind = Local, name: string,
|
||||
typeBody, initializerBody: typed) =
|
||||
## adds a variable declaration to the builder, with `typeBody` building the type, and
|
||||
## `initializerBody` building the initializer. initializer must be provided
|
||||
builder.addVarHeader(kind)
|
||||
typeBody
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
builder.add(" = ")
|
||||
initializerBody
|
||||
builder.addLineEnd(";")
|
||||
|
||||
proc addArrayVar(builder: var Builder, kind: VarKind = Local, name: string, elementType: Snippet, len: int, initializer: Snippet = "") =
|
||||
## adds an array variable declaration to the builder
|
||||
builder.addVarHeader(kind)
|
||||
builder.add(elementType)
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
builder.add("[")
|
||||
builder.addIntValue(len)
|
||||
builder.add("]")
|
||||
if initializer.len != 0:
|
||||
builder.add(" = ")
|
||||
builder.add(initializer)
|
||||
builder.addLineEnd(";")
|
||||
|
||||
template addArrayVarWithInitializer(builder: var Builder, kind: VarKind = Local, name: string, elementType: Snippet, len: int, body: typed) =
|
||||
## adds an array variable declaration to the builder with the initializer built according to `body`
|
||||
builder.addVarHeader(kind)
|
||||
builder.add(elementType)
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
builder.add("[")
|
||||
builder.addIntValue(len)
|
||||
builder.add("] = ")
|
||||
body
|
||||
builder.addLineEnd(";")
|
||||
|
||||
template addTypedef(builder: var Builder, name: string, typeBody: typed) =
|
||||
## adds a typedef declaration to the builder with name `name` and type as
|
||||
## built in `typeBody`
|
||||
builder.add("typedef ")
|
||||
typeBody
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
builder.addLineEnd(";")
|
||||
|
||||
proc addProcTypedef(builder: var Builder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
|
||||
builder.add("typedef ")
|
||||
builder.add(CallingConvToStr[callConv])
|
||||
builder.add("_PTR(")
|
||||
builder.add(rettype)
|
||||
builder.add(", ")
|
||||
builder.add(name)
|
||||
builder.add(")")
|
||||
builder.add(params)
|
||||
builder.addLineEnd(";")
|
||||
|
||||
template addArrayTypedef(builder: var Builder, name: string, len: BiggestInt, typeBody: typed) =
|
||||
## adds an array typedef declaration to the builder with name `name`,
|
||||
## length `len`, and element type as built in `typeBody`
|
||||
builder.add("typedef ")
|
||||
typeBody
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
builder.add("[")
|
||||
builder.addIntValue(len)
|
||||
builder.addLineEnd("];")
|
||||
|
||||
type
|
||||
StructInitializerKind = enum
|
||||
siOrderedStruct ## struct constructor, but without named fields on C
|
||||
siNamedStruct ## struct constructor, with named fields i.e. C99 designated initializer
|
||||
siArray ## array constructor
|
||||
siWrapper ## wrapper for a single field, generates it verbatim
|
||||
|
||||
StructInitializer = object
|
||||
## context for building struct initializers, i.e. `{ field1, field2 }`
|
||||
kind: StructInitializerKind
|
||||
## if true, fields will not be named, instead values are placed in order
|
||||
needsComma: bool
|
||||
|
||||
proc initStructInitializer(builder: var Builder, kind: StructInitializerKind): StructInitializer =
|
||||
## starts building a struct initializer, i.e. braced initializer list
|
||||
result = StructInitializer(kind: kind, needsComma: false)
|
||||
if kind != siWrapper:
|
||||
builder.add("{")
|
||||
|
||||
template addField(builder: var Builder, constr: var StructInitializer, name: string, valueBody: typed) =
|
||||
## adds a field to a struct initializer, with the value built in `valueBody`
|
||||
if constr.needsComma:
|
||||
assert constr.kind != siWrapper, "wrapper constructor cannot have multiple fields"
|
||||
builder.add(", ")
|
||||
else:
|
||||
constr.needsComma = true
|
||||
case constr.kind
|
||||
of siArray, siWrapper:
|
||||
# no name, can just add value
|
||||
valueBody
|
||||
of siOrderedStruct:
|
||||
# positional init - name not used in output (empty allowed for anonymous unions)
|
||||
valueBody
|
||||
of siNamedStruct:
|
||||
# designated init - empty name for anonymous unions (skips .name = prefix)
|
||||
if name.len != 0:
|
||||
builder.add(".")
|
||||
builder.add(name)
|
||||
builder.add(" = ")
|
||||
valueBody
|
||||
|
||||
proc finishStructInitializer(builder: var Builder, constr: StructInitializer) =
|
||||
## finishes building a struct initializer
|
||||
if constr.kind != siWrapper:
|
||||
builder.add("}")
|
||||
|
||||
template addStructInitializer(builder: var Builder, constr: out StructInitializer, kind: StructInitializerKind, body: typed) =
|
||||
## builds a struct initializer, i.e. `{ field1, field2 }`
|
||||
## a `var StructInitializer` must be declared and passed as a parameter so
|
||||
## that it can be used with `addField`
|
||||
constr = builder.initStructInitializer(kind)
|
||||
body
|
||||
builder.finishStructInitializer(constr)
|
||||
|
||||
proc addField(obj: var Builder; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
|
||||
## adds a field inside a struct/union type
|
||||
obj.add('\t')
|
||||
obj.add(typ)
|
||||
obj.add(" ")
|
||||
obj.add(name)
|
||||
if isFlexArray:
|
||||
obj.add("[SEQ_DECL_SIZE]")
|
||||
if initializer.len != 0:
|
||||
obj.add(initializer)
|
||||
obj.add(";\n")
|
||||
|
||||
proc addArrayField(obj: var Builder; name, elementType: Snippet; len: int; initializer: Snippet = "") =
|
||||
## adds an array field inside a struct/union type
|
||||
obj.add('\t')
|
||||
obj.add(elementType)
|
||||
obj.add(" ")
|
||||
obj.add(name)
|
||||
obj.add("[")
|
||||
obj.addIntValue(len)
|
||||
obj.add("]")
|
||||
if initializer.len != 0:
|
||||
obj.add(initializer)
|
||||
obj.add(";\n")
|
||||
|
||||
proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
|
||||
## adds an field inside a struct/union type, based on an `skField` symbol
|
||||
obj.add('\t')
|
||||
if field.alignment > 0:
|
||||
obj.add("NIM_ALIGN(")
|
||||
obj.addIntValue(field.alignment)
|
||||
obj.add(") ")
|
||||
obj.add(typ)
|
||||
if sfNoalias in field.flags:
|
||||
obj.add(" NIM_NOALIAS")
|
||||
obj.add(" ")
|
||||
obj.add(name)
|
||||
if isFlexArray:
|
||||
obj.add("[SEQ_DECL_SIZE]")
|
||||
if field.bitsize != 0:
|
||||
obj.add(":")
|
||||
obj.addIntValue(field.bitsize)
|
||||
if initializer.len != 0:
|
||||
obj.add(initializer)
|
||||
obj.add(";\n")
|
||||
|
||||
proc addProcField(obj: var Builder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
|
||||
obj.add(CallingConvToStr[callConv])
|
||||
obj.add("_PTR(")
|
||||
obj.add(rettype)
|
||||
obj.add(", ")
|
||||
obj.add(name)
|
||||
obj.add(")")
|
||||
obj.add(params)
|
||||
obj.add(";\n")
|
||||
|
||||
type
|
||||
BaseClassKind = enum
|
||||
## denotes how and whether or not the base class/RTTI should be stored
|
||||
bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti
|
||||
StructBuilderInfo = object
|
||||
## context for building `struct` types
|
||||
baseKind: BaseClassKind
|
||||
named: bool
|
||||
preFieldsLen: int
|
||||
|
||||
proc structOrUnion(t: PType): Snippet =
|
||||
let t = t.skipTypes({tyAlias, tySink})
|
||||
if tfUnion in t.flags: "union"
|
||||
else: "struct"
|
||||
|
||||
proc startSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet): StructBuilderInfo =
|
||||
result = StructBuilderInfo(baseKind: bcNone, named: name.len != 0)
|
||||
obj.add("struct")
|
||||
if result.named:
|
||||
obj.add(" ")
|
||||
obj.add(name)
|
||||
if baseType.len != 0:
|
||||
if m.compileToCpp:
|
||||
result.baseKind = bcCppInherit
|
||||
else:
|
||||
result.baseKind = bcSupField
|
||||
if result.baseKind == bcCppInherit:
|
||||
obj.add(" : public ")
|
||||
obj.add(baseType)
|
||||
obj.add(" ")
|
||||
obj.add("{\n")
|
||||
result.preFieldsLen = obj.buf.len
|
||||
if result.baseKind == bcSupField:
|
||||
obj.addField(name = "Sup", typ = baseType)
|
||||
|
||||
proc finishSimpleStruct(obj: var Builder; m: BModule; info: StructBuilderInfo) =
|
||||
if info.baseKind == bcNone and info.preFieldsLen == obj.buf.len:
|
||||
# no fields were added, add dummy field
|
||||
obj.addField(name = "dummy", typ = CChar)
|
||||
if info.named:
|
||||
obj.add("};\n")
|
||||
else:
|
||||
obj.add("}")
|
||||
|
||||
template addSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet; body: typed) =
|
||||
## builds a struct type not based on a Nim type with fields according to `body`,
|
||||
## `name` can be empty to build as a type expression and not a statement
|
||||
let info = startSimpleStruct(obj, m, name, baseType)
|
||||
body
|
||||
finishSimpleStruct(obj, m, info)
|
||||
|
||||
proc startStruct(obj: var Builder; m: BModule; t: PType; name: string; baseType: Snippet): StructBuilderInfo =
|
||||
result = StructBuilderInfo(baseKind: bcNone, named: name.len != 0)
|
||||
if tfPacked in t.flags:
|
||||
if hasAttribute in CC[m.config.cCompiler].props:
|
||||
obj.add(structOrUnion(t))
|
||||
obj.add(" __attribute__((__packed__))")
|
||||
else:
|
||||
obj.add("#pragma pack(push, 1)\n")
|
||||
obj.add(structOrUnion(t))
|
||||
else:
|
||||
obj.add(structOrUnion(t))
|
||||
if result.named:
|
||||
obj.add(" ")
|
||||
obj.add(name)
|
||||
if t.kind == tyObject:
|
||||
if t.baseClass == nil:
|
||||
if lacksMTypeField(t):
|
||||
result.baseKind = bcNone
|
||||
elif optTinyRtti in m.config.globalOptions:
|
||||
result.baseKind = bcNoneTinyRtti
|
||||
else:
|
||||
result.baseKind = bcNoneRtti
|
||||
elif m.compileToCpp:
|
||||
result.baseKind = bcCppInherit
|
||||
else:
|
||||
result.baseKind = bcSupField
|
||||
elif baseType.len != 0:
|
||||
if m.compileToCpp:
|
||||
result.baseKind = bcCppInherit
|
||||
else:
|
||||
result.baseKind = bcSupField
|
||||
if result.baseKind == bcCppInherit:
|
||||
obj.add(" : public ")
|
||||
obj.add(baseType)
|
||||
obj.add(" ")
|
||||
obj.add("{\n")
|
||||
result.preFieldsLen = obj.buf.len
|
||||
case result.baseKind
|
||||
of bcNone:
|
||||
# rest of the options add a field or don't need it due to inheritance,
|
||||
# we need to add the dummy field for uncheckedarray ahead of time
|
||||
# so that it remains trailing
|
||||
if t.itemId notin m.g.graph.memberProcsPerType and
|
||||
t.n != nil and t.n.len == 1 and t.n[0].kind == nkSym and
|
||||
t.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray:
|
||||
# only consists of flexible array field, add *initial* dummy field
|
||||
obj.addField(name = "dummy", typ = CChar)
|
||||
of bcCppInherit: discard
|
||||
of bcNoneRtti:
|
||||
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimType")))
|
||||
of bcNoneTinyRtti:
|
||||
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimTypeV2")))
|
||||
of bcSupField:
|
||||
obj.addField(name = "Sup", typ = baseType)
|
||||
|
||||
proc finishStruct(obj: var Builder; m: BModule; t: PType; info: StructBuilderInfo) =
|
||||
if info.baseKind == bcNone and info.preFieldsLen == obj.buf.len and
|
||||
t.itemId notin m.g.graph.memberProcsPerType:
|
||||
# no fields were added, add dummy field
|
||||
obj.addField(name = "dummy", typ = CChar)
|
||||
if info.named:
|
||||
obj.add("};\n")
|
||||
else:
|
||||
obj.add("}")
|
||||
if tfPacked in t.flags and hasAttribute notin CC[m.config.cCompiler].props:
|
||||
obj.add("#pragma pack(pop)\n")
|
||||
|
||||
template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: Snippet; body: typed) =
|
||||
## builds a struct type directly based on `typ` with fields according to `body`,
|
||||
## `name` can be empty to build as a type expression and not a statement
|
||||
let info = startStruct(obj, m, typ, name, baseType)
|
||||
body
|
||||
finishStruct(obj, m, typ, info)
|
||||
|
||||
template addFieldWithStructType(obj: var Builder; m: BModule; parentTyp: PType; fieldName: string, body: typed) =
|
||||
## adds a field with a `struct { ... }` type, building the fields according to `body`
|
||||
obj.add('\t')
|
||||
if tfPacked in parentTyp.flags:
|
||||
if hasAttribute in CC[m.config.cCompiler].props:
|
||||
obj.add("struct __attribute__((__packed__)) {\n")
|
||||
else:
|
||||
obj.add("#pragma pack(push, 1)\nstruct {")
|
||||
else:
|
||||
obj.add("struct {\n")
|
||||
body
|
||||
obj.add("} ")
|
||||
obj.add(fieldName)
|
||||
obj.add(";\n")
|
||||
if tfPacked in parentTyp.flags and hasAttribute notin CC[m.config.cCompiler].props:
|
||||
obj.add("#pragma pack(pop)\n")
|
||||
|
||||
template addAnonUnion(obj: var Builder; body: typed) =
|
||||
## adds an anonymous union i.e. `union { ... };` with fields according to `body`
|
||||
obj.add "union{\n"
|
||||
body
|
||||
obj.add("};\n")
|
||||
|
||||
template addUnionType(obj: var Builder; body: typed) =
|
||||
## adds a union type i.e. `union { ... }` with fields according to `body`
|
||||
obj.add "union{\n"
|
||||
body
|
||||
obj.add("}")
|
||||
|
||||
type DeclVisibility = enum
|
||||
None
|
||||
Extern
|
||||
ExternC
|
||||
ImportLib
|
||||
ExportLib
|
||||
ExportLibVar
|
||||
Private
|
||||
StaticProc
|
||||
|
||||
proc addVisibilityPrefix(builder: var Builder, visibility: DeclVisibility) =
|
||||
# internal proc
|
||||
case visibility
|
||||
of None: discard
|
||||
of Extern:
|
||||
builder.add("extern ")
|
||||
of ExternC:
|
||||
builder.add("NIM_EXTERNC ")
|
||||
of ImportLib:
|
||||
builder.add("N_LIB_IMPORT ")
|
||||
of ExportLib:
|
||||
builder.add("N_LIB_EXPORT ")
|
||||
of ExportLibVar:
|
||||
builder.add("N_LIB_EXPORT_VAR ")
|
||||
of Private:
|
||||
builder.add("N_LIB_PRIVATE ")
|
||||
of StaticProc:
|
||||
builder.add("static ")
|
||||
|
||||
template addDeclWithVisibility(builder: var Builder, visibility: DeclVisibility, declBody: typed) =
|
||||
## adds a declaration as in `declBody` with the given visibility
|
||||
builder.addVisibilityPrefix(visibility)
|
||||
declBody
|
||||
|
||||
type ProcParamBuilder = object
|
||||
needsComma: bool
|
||||
|
||||
proc initProcParamBuilder(builder: var Builder): ProcParamBuilder =
|
||||
result = ProcParamBuilder(needsComma: false)
|
||||
builder.add("(")
|
||||
|
||||
proc finishProcParamBuilder(builder: var Builder, params: ProcParamBuilder) =
|
||||
if params.needsComma:
|
||||
builder.add(")")
|
||||
else:
|
||||
builder.add("void)")
|
||||
|
||||
template cgDeclFrmt*(s: PSym): string =
|
||||
s.constraint.strVal
|
||||
|
||||
proc addParam(builder: var Builder, params: var ProcParamBuilder, name: string, typ: Snippet) =
|
||||
if params.needsComma:
|
||||
builder.add(", ")
|
||||
else:
|
||||
params.needsComma = true
|
||||
builder.add(typ)
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
|
||||
proc addParam(builder: var Builder, params: var ProcParamBuilder, param: PSym, typ: Snippet) =
|
||||
if params.needsComma:
|
||||
builder.add(", ")
|
||||
else:
|
||||
params.needsComma = true
|
||||
var modifiedTyp = typ
|
||||
if sfNoalias in param.flags:
|
||||
modifiedTyp.add(" NIM_NOALIAS")
|
||||
if sfCodegenDecl notin param.flags:
|
||||
builder.add(modifiedTyp)
|
||||
builder.add(" ")
|
||||
builder.add(param.loc.snippet)
|
||||
else:
|
||||
builder.add runtimeFormat(param.cgDeclFrmt, [modifiedTyp, param.loc.snippet])
|
||||
|
||||
proc addUnnamedParam(builder: var Builder, params: var ProcParamBuilder, typ: Snippet) =
|
||||
if params.needsComma:
|
||||
builder.add(", ")
|
||||
else:
|
||||
params.needsComma = true
|
||||
builder.add(typ)
|
||||
|
||||
proc addProcTypedParam(builder: var Builder, paramBuilder: var ProcParamBuilder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
|
||||
if paramBuilder.needsComma:
|
||||
builder.add(", ")
|
||||
else:
|
||||
paramBuilder.needsComma = true
|
||||
builder.add(CallingConvToStr[callConv])
|
||||
builder.add("_PTR(")
|
||||
builder.add(rettype)
|
||||
builder.add(", ")
|
||||
builder.add(name)
|
||||
builder.add(")")
|
||||
builder.add(params)
|
||||
|
||||
proc addVarargsParam(builder: var Builder, params: var ProcParamBuilder) =
|
||||
# does not exist in NIFC, needs to be proc pragma
|
||||
if params.needsComma:
|
||||
builder.add(", ")
|
||||
else:
|
||||
params.needsComma = true
|
||||
builder.add("...")
|
||||
|
||||
template addProcParams(builder: var Builder, params: out ProcParamBuilder, body: typed) =
|
||||
params = initProcParamBuilder(builder)
|
||||
body
|
||||
finishProcParamBuilder(builder, params)
|
||||
|
||||
type SimpleProcParam = tuple
|
||||
name, typ: string
|
||||
|
||||
proc cProcParams(params: varargs[SimpleProcParam]): Snippet =
|
||||
if params.len == 0: return "(void)"
|
||||
result = "("
|
||||
for i in 0 ..< params.len:
|
||||
if i != 0: result.add(", ")
|
||||
result.add(params[i].typ)
|
||||
if params[i].name.len != 0:
|
||||
result.add(" ")
|
||||
result.add(params[i].name)
|
||||
result.add(")")
|
||||
|
||||
template addProcHeaderWithParams(builder: var Builder, callConv: TCallingConvention,
|
||||
name: string, rettype: Snippet, paramBuilder: typed) =
|
||||
# on nifc should build something like (proc name params type pragmas
|
||||
# with no body given
|
||||
# or enforce this with secondary builder object
|
||||
builder.add(CallingConvToStr[callConv])
|
||||
builder.add("(")
|
||||
builder.add(rettype)
|
||||
builder.add(", ")
|
||||
builder.add(name)
|
||||
builder.add(")")
|
||||
paramBuilder
|
||||
|
||||
proc addProcHeader(builder: var Builder, callConv: TCallingConvention,
|
||||
name: string, rettype, params: Snippet) =
|
||||
# on nifc should build something like (proc name params type pragmas
|
||||
# with no body given
|
||||
# or enforce this with secondary builder object
|
||||
addProcHeaderWithParams(builder, callConv, name, rettype):
|
||||
builder.add(params)
|
||||
|
||||
proc addProcHeader(builder: var Builder, name: string, rettype, params: Snippet, isConstructor = false) =
|
||||
# no callconv
|
||||
builder.add(rettype)
|
||||
builder.add(" ")
|
||||
if isConstructor:
|
||||
builder.add("__attribute__((constructor)) ")
|
||||
builder.add(name)
|
||||
builder.add(params)
|
||||
|
||||
proc addProcHeader(builder: var Builder, m: BModule, prc: PSym, name: string, params, rettype: Snippet, addAttributes: bool) =
|
||||
# on nifc should build something like (proc name params type pragmas
|
||||
# with no body given
|
||||
# or enforce this with secondary builder object
|
||||
let noreturn = isNoReturn(m, prc)
|
||||
if sfPure in prc.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add("__declspec(naked) ")
|
||||
if noreturn and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add("__declspec(noreturn) ")
|
||||
builder.add(CallingConvToStr[prc.typ.callConv])
|
||||
builder.add("(")
|
||||
builder.add(rettype)
|
||||
builder.add(", ")
|
||||
builder.add(name)
|
||||
builder.add(")")
|
||||
builder.add(params)
|
||||
if addAttributes:
|
||||
if sfPure in prc.flags and hasAttribute in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add(" __attribute__((naked))")
|
||||
if noreturn and hasAttribute in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add(" __attribute__((noreturn))")
|
||||
|
||||
proc finishProcHeaderAsProto(builder: var Builder) =
|
||||
builder.addLineEnd(";")
|
||||
|
||||
template finishProcHeaderWithBody(builder: var Builder, body: typed) =
|
||||
builder.addLineEndIndent(" {")
|
||||
body
|
||||
builder.addLineEndDedent("}")
|
||||
builder.addNewline
|
||||
|
||||
proc addProcVar(builder: var Builder, m: BModule, prc: PSym, name: string, params, rettype: Snippet,
|
||||
isStatic = false, ignoreAttributes = false) =
|
||||
# on nifc, builds full variable
|
||||
if isStatic:
|
||||
builder.add("static ")
|
||||
let noreturn = isNoReturn(m, prc)
|
||||
if not ignoreAttributes:
|
||||
if sfPure in prc.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add("__declspec(naked) ")
|
||||
if noreturn and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add("__declspec(noreturn) ")
|
||||
builder.add(CallingConvToStr[prc.typ.callConv])
|
||||
builder.add("_PTR(")
|
||||
builder.add(rettype)
|
||||
builder.add(", ")
|
||||
builder.add(name)
|
||||
builder.add(")")
|
||||
builder.add(params)
|
||||
if not ignoreAttributes:
|
||||
if sfPure in prc.flags and hasAttribute in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add(" __attribute__((naked))")
|
||||
if noreturn and hasAttribute in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add(" __attribute__((noreturn))")
|
||||
# ensure we are just adding a variable:
|
||||
builder.addLineEnd(";")
|
||||
|
||||
proc addProcVar(builder: var Builder, callConv: TCallingConvention,
|
||||
name: string, params, rettype: Snippet,
|
||||
isStatic = false, isVolatile = false) =
|
||||
# on nifc, builds full variable
|
||||
if isStatic:
|
||||
builder.add("static ")
|
||||
builder.add(CallingConvToStr[callConv])
|
||||
builder.add("_PTR(")
|
||||
builder.add(rettype)
|
||||
builder.add(", ")
|
||||
if isVolatile:
|
||||
builder.add("volatile ")
|
||||
builder.add(name)
|
||||
builder.add(")")
|
||||
builder.add(params)
|
||||
# ensure we are just adding a variable:
|
||||
builder.addLineEnd(";")
|
||||
|
||||
proc addProcVar(builder: var Builder,
|
||||
name: string, params, rettype: Snippet,
|
||||
isStatic = false, isVolatile = false) =
|
||||
# no callconv
|
||||
if isStatic:
|
||||
builder.add("static ")
|
||||
builder.add(rettype)
|
||||
builder.add(" (*")
|
||||
if isVolatile:
|
||||
builder.add("volatile ")
|
||||
builder.add(name)
|
||||
builder.add(")")
|
||||
builder.add(params)
|
||||
# ensure we are just adding a variable:
|
||||
builder.addLineEnd(";")
|
||||
|
||||
type VarInitializerKind = enum
|
||||
Assignment, CppConstructor
|
||||
|
||||
proc addVar(builder: var Builder, m: BModule, s: PSym, name: string, typ: Snippet, kind = Local, visibility: DeclVisibility = None, initializer: Snippet = "", initializerKind: VarInitializerKind = Assignment) =
|
||||
if sfCodegenDecl in s.flags:
|
||||
builder.add(runtimeFormat(s.cgDeclFrmt, [typ, name]))
|
||||
if initializer.len != 0:
|
||||
if initializerKind == Assignment:
|
||||
builder.add(" = ")
|
||||
builder.add(initializer)
|
||||
builder.addLineEnd(";")
|
||||
return
|
||||
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
||||
builder.add("NIM_ALIGN(" & $s.alignment & ") ")
|
||||
builder.addVisibilityPrefix(visibility)
|
||||
if kind == Threadvar:
|
||||
if optThreads in m.config.globalOptions:
|
||||
let sym = s.typ.sym
|
||||
if sym != nil and sfCppNonPod in sym.flags:
|
||||
builder.add("NIM_THREAD_LOCAL ")
|
||||
else: builder.add("NIM_THREADVAR ")
|
||||
else:
|
||||
builder.addVarHeader(kind)
|
||||
builder.add(typ)
|
||||
if sfRegister in s.flags: builder.add(" register")
|
||||
if sfVolatile in s.flags: builder.add(" volatile")
|
||||
if sfNoalias in s.flags: builder.add(" NIM_NOALIAS")
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
if initializer.len != 0:
|
||||
if initializerKind == Assignment:
|
||||
builder.add(" = ")
|
||||
builder.add(initializer)
|
||||
builder.addLineEnd(";")
|
||||
|
||||
proc addInclude(builder: var Builder, value: Snippet) =
|
||||
builder.addLineEnd("#include " & value)
|
||||
@@ -1,259 +0,0 @@
|
||||
proc constType(t: Snippet): Snippet =
|
||||
# needs manipulation of `t` in nifc
|
||||
"NIM_CONST " & t
|
||||
|
||||
proc constPtrType(t: Snippet): Snippet =
|
||||
t & "* NIM_CONST"
|
||||
|
||||
proc ptrConstType(t: Snippet): Snippet =
|
||||
"NIM_CONST " & t & "*"
|
||||
|
||||
proc ptrType(t: Snippet): Snippet =
|
||||
t & "*"
|
||||
|
||||
proc cppRefType(t: Snippet): Snippet =
|
||||
t & "&"
|
||||
|
||||
const
|
||||
CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL",
|
||||
"N_STDCALL", "N_CDECL", "N_SAFECALL",
|
||||
"N_SYSCALL", # this is probably not correct for all platforms,
|
||||
# but one can #define it to what one wants
|
||||
"N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_THISCALL", "N_CLOSURE", "N_NOCONV",
|
||||
"N_NOCONV" #ccMember is N_NOCONV
|
||||
]
|
||||
|
||||
proc procPtrTypeUnnamed(rettype, params: Snippet): Snippet =
|
||||
rettype & "(*)" & params
|
||||
|
||||
proc procPtrTypeUnnamedNimCall(rettype, params: Snippet): Snippet =
|
||||
rettype & "(N_RAW_NIMCALL*)" & params
|
||||
|
||||
proc procPtrTypeUnnamed(callConv: TCallingConvention, rettype, params: Snippet): Snippet =
|
||||
CallingConvToStr[callConv] & "_PTR(" & rettype & ", )" & params
|
||||
|
||||
type CppCaptureKind = enum None, ByReference, ByCopy
|
||||
|
||||
template addCppLambda(builder: var Builder, captures: CppCaptureKind, params: Snippet, body: typed) =
|
||||
builder.add("[")
|
||||
case captures
|
||||
of None: discard
|
||||
of ByReference: builder.add("&")
|
||||
of ByCopy: builder.add("=")
|
||||
builder.add("] ")
|
||||
builder.add(params)
|
||||
builder.addLineEndIndent(" {")
|
||||
body
|
||||
builder.addLineEndDedent("}")
|
||||
|
||||
proc cCast(typ, value: Snippet): Snippet =
|
||||
"((" & typ & ") " & value & ")"
|
||||
|
||||
proc wrapPar(value: Snippet): Snippet =
|
||||
# used for expression group, no-op on sexp
|
||||
"(" & value & ")"
|
||||
|
||||
proc removeSinglePar(value: Snippet): Snippet =
|
||||
# removes a single paren layer expected to exist, to silence Wparentheses-equality
|
||||
assert value[0] == '(' and value[^1] == ')'
|
||||
value[1..^2]
|
||||
|
||||
template addCast(builder: var Builder, typ: Snippet, valueBody: typed) =
|
||||
## adds a cast to `typ` with value built by `valueBody`
|
||||
builder.add "(("
|
||||
builder.add typ
|
||||
builder.add ") "
|
||||
valueBody
|
||||
builder.add ")"
|
||||
|
||||
proc cAddr(value: Snippet): Snippet =
|
||||
"(&" & value & ")"
|
||||
|
||||
proc cLabelAddr(value: TLabel): Snippet =
|
||||
"&&" & value
|
||||
|
||||
proc cDeref(value: Snippet): Snippet =
|
||||
"(*" & value & ")"
|
||||
|
||||
proc subscript(a, b: Snippet): Snippet =
|
||||
a & "[" & b & "]"
|
||||
|
||||
proc dotField(a, b: Snippet): Snippet =
|
||||
a & "." & b
|
||||
|
||||
proc derefField(a, b: Snippet): Snippet =
|
||||
a & "->" & b
|
||||
|
||||
type CallBuilder = object
|
||||
needsComma: bool
|
||||
|
||||
proc initCallBuilder(builder: var Builder, callee: Snippet): CallBuilder =
|
||||
result = CallBuilder(needsComma: false)
|
||||
builder.add(callee)
|
||||
builder.add("(")
|
||||
|
||||
const cArgumentSeparator = ", "
|
||||
|
||||
proc addArgumentSeparator(builder: var Builder) =
|
||||
# no-op on NIFC
|
||||
# used by "single argument" builders
|
||||
builder.add(cArgumentSeparator)
|
||||
|
||||
template addArgument(builder: var Builder, call: var CallBuilder, valueBody: typed) =
|
||||
if call.needsComma:
|
||||
builder.addArgumentSeparator()
|
||||
else:
|
||||
call.needsComma = true
|
||||
valueBody
|
||||
|
||||
proc finishCallBuilder(builder: var Builder, call: CallBuilder) =
|
||||
builder.add(")")
|
||||
|
||||
template addCall(builder: var Builder, call: out CallBuilder, callee: Snippet, body: typed) =
|
||||
call = initCallBuilder(builder, callee)
|
||||
body
|
||||
finishCallBuilder(builder, call)
|
||||
|
||||
proc addCall(builder: var Builder, callee: Snippet, args: varargs[Snippet]) =
|
||||
builder.add(callee)
|
||||
builder.add("(")
|
||||
if args.len != 0:
|
||||
builder.add(args[0])
|
||||
for i in 1 ..< args.len:
|
||||
builder.add(", ")
|
||||
builder.add(args[i])
|
||||
builder.add(")")
|
||||
|
||||
proc cCall(callee: Snippet, args: varargs[Snippet]): Snippet =
|
||||
result = callee
|
||||
result.add("(")
|
||||
if args.len != 0:
|
||||
result.add(args[0])
|
||||
for i in 1 ..< args.len:
|
||||
result.add(", ")
|
||||
result.add(args[i])
|
||||
result.add(")")
|
||||
|
||||
proc addSizeof(builder: var Builder, val: Snippet) =
|
||||
builder.add("sizeof(")
|
||||
builder.add(val)
|
||||
builder.add(")")
|
||||
|
||||
proc addAlignof(builder: var Builder, val: Snippet) =
|
||||
builder.add("NIM_ALIGNOF(")
|
||||
builder.add(val)
|
||||
builder.add(")")
|
||||
|
||||
proc addOffsetof(builder: var Builder, val, member: Snippet) =
|
||||
builder.add("offsetof(")
|
||||
builder.add(val)
|
||||
builder.add(", ")
|
||||
builder.add(member)
|
||||
builder.add(")")
|
||||
|
||||
template cSizeof(val: Snippet): Snippet =
|
||||
"sizeof(" & val & ")"
|
||||
|
||||
template cAlignof(val: Snippet): Snippet =
|
||||
"NIM_ALIGNOF(" & val & ")"
|
||||
|
||||
template cOffsetof(val, member: Snippet): Snippet =
|
||||
"offsetof(" & val & ", " & member & ")"
|
||||
|
||||
type TypedBinaryOp = enum
|
||||
Add, Sub, Mul, Div, Mod
|
||||
Shr, Shl, BitAnd, BitOr, BitXor
|
||||
|
||||
const typedBinaryOperators: array[TypedBinaryOp, string] = [
|
||||
Add: "+",
|
||||
Sub: "-",
|
||||
Mul: "*",
|
||||
Div: "/",
|
||||
Mod: "%",
|
||||
Shr: ">>",
|
||||
Shl: "<<",
|
||||
BitAnd: "&",
|
||||
BitOr: "|",
|
||||
BitXor: "^"
|
||||
]
|
||||
|
||||
type TypedUnaryOp = enum
|
||||
Neg, BitNot
|
||||
|
||||
const typedUnaryOperators: array[TypedUnaryOp, string] = [
|
||||
Neg: "-",
|
||||
BitNot: "~",
|
||||
]
|
||||
|
||||
type UntypedBinaryOp = enum
|
||||
LessEqual, LessThan, GreaterEqual, GreaterThan, Equal, NotEqual
|
||||
And, Or
|
||||
|
||||
const untypedBinaryOperators: array[UntypedBinaryOp, string] = [
|
||||
LessEqual: "<=",
|
||||
LessThan: "<",
|
||||
GreaterEqual: ">=",
|
||||
GreaterThan: ">",
|
||||
Equal: "==",
|
||||
NotEqual: "!=",
|
||||
And: "&&",
|
||||
Or: "||"
|
||||
]
|
||||
|
||||
type UntypedUnaryOp = enum
|
||||
Not
|
||||
|
||||
const untypedUnaryOperators: array[UntypedUnaryOp, string] = [
|
||||
Not: "!"
|
||||
]
|
||||
|
||||
proc addOp(builder: var Builder, binOp: TypedBinaryOp, t: Snippet, a, b: Snippet) =
|
||||
builder.add('(')
|
||||
builder.add(a)
|
||||
builder.add(' ')
|
||||
builder.add(typedBinaryOperators[binOp])
|
||||
builder.add(' ')
|
||||
builder.add(b)
|
||||
builder.add(')')
|
||||
|
||||
proc addOp(builder: var Builder, unOp: TypedUnaryOp, t: Snippet, a: Snippet) =
|
||||
builder.add('(')
|
||||
builder.add(typedUnaryOperators[unOp])
|
||||
builder.add('(')
|
||||
builder.add(a)
|
||||
builder.add("))")
|
||||
|
||||
proc addOp(builder: var Builder, binOp: UntypedBinaryOp, a, b: Snippet) =
|
||||
builder.add('(')
|
||||
builder.add(a)
|
||||
builder.add(' ')
|
||||
builder.add(untypedBinaryOperators[binOp])
|
||||
builder.add(' ')
|
||||
builder.add(b)
|
||||
builder.add(')')
|
||||
|
||||
proc addOp(builder: var Builder, unOp: UntypedUnaryOp, a: Snippet) =
|
||||
builder.add('(')
|
||||
builder.add(untypedUnaryOperators[unOp])
|
||||
builder.add('(')
|
||||
builder.add(a)
|
||||
builder.add("))")
|
||||
|
||||
template cOp(binOp: TypedBinaryOp, t: Snippet, a, b: Snippet): Snippet =
|
||||
'(' & a & ' ' & typedBinaryOperators[binOp] & ' ' & b & ')'
|
||||
|
||||
template cOp(binOp: TypedUnaryOp, t: Snippet, a: Snippet): Snippet =
|
||||
'(' & typedUnaryOperators[binOp] & '(' & a & "))"
|
||||
|
||||
template cOp(binOp: UntypedBinaryOp, a, b: Snippet): Snippet =
|
||||
'(' & a & ' ' & untypedBinaryOperators[binOp] & ' ' & b & ')'
|
||||
|
||||
template cOp(binOp: UntypedUnaryOp, a: Snippet): Snippet =
|
||||
'(' & untypedUnaryOperators[binOp] & '(' & a & "))"
|
||||
|
||||
template cIfExpr(cond, a, b: Snippet): Snippet =
|
||||
# XXX used for `min` and `max`, maybe add nifc primitives for these
|
||||
"(" & cond & " ? " & a & " : " & b & ")"
|
||||
|
||||
template cUnlikely(val: Snippet): Snippet =
|
||||
"NIM_UNLIKELY(" & val & ")"
|
||||
@@ -1,329 +0,0 @@
|
||||
template addAssignmentWithValue(builder: var Builder, lhs: Snippet, valueBody: typed) =
|
||||
builder.add(lhs)
|
||||
builder.add(" = ")
|
||||
valueBody
|
||||
builder.addLineEnd(";")
|
||||
|
||||
template addFieldAssignmentWithValue(builder: var Builder, lhs: Snippet, name: string, valueBody: typed) =
|
||||
builder.add(lhs)
|
||||
builder.add("." & name & " = ")
|
||||
valueBody
|
||||
builder.addLineEnd(";")
|
||||
|
||||
template addAssignment(builder: var Builder, lhs, rhs: Snippet) =
|
||||
builder.addAssignmentWithValue(lhs):
|
||||
builder.add(rhs)
|
||||
|
||||
template addFieldAssignment(builder: var Builder, lhs: Snippet, name: string, rhs: Snippet) =
|
||||
builder.addFieldAssignmentWithValue(lhs, name):
|
||||
builder.add(rhs)
|
||||
|
||||
template addMutualFieldAssignment(builder: var Builder, lhs, rhs: Snippet, name: string) =
|
||||
builder.addFieldAssignmentWithValue(lhs, name):
|
||||
builder.add(rhs)
|
||||
builder.add("." & name)
|
||||
|
||||
template addAssignment(builder: var Builder, lhs: Snippet, rhs: int | int64 | uint64 | Int128) =
|
||||
builder.addAssignmentWithValue(lhs):
|
||||
builder.addIntValue(rhs)
|
||||
|
||||
template addFieldAssignment(builder: var Builder, lhs: Snippet, name: string, rhs: int | int64 | uint64 | Int128) =
|
||||
builder.addFieldAssignmentWithValue(lhs, name):
|
||||
builder.addIntValue(rhs)
|
||||
|
||||
template addDerefFieldAssignment(builder: var Builder, lhs: Snippet, name: string, rhs: Snippet) =
|
||||
builder.add(lhs)
|
||||
builder.add("->" & name & " = ")
|
||||
builder.add(rhs)
|
||||
builder.addLineEnd(";")
|
||||
|
||||
template addSubscriptAssignment(builder: var Builder, lhs: Snippet, index: Snippet, rhs: Snippet) =
|
||||
builder.add(lhs)
|
||||
builder.add("[" & index & "] = ")
|
||||
builder.add(rhs)
|
||||
builder.addLineEnd(";")
|
||||
|
||||
template addStmt(builder: var Builder, stmtBody: typed) =
|
||||
## makes an expression built by `stmtBody` into a statement
|
||||
stmtBody
|
||||
builder.addLineEnd(";")
|
||||
|
||||
proc addCallStmt(builder: var Builder, callee: Snippet, args: varargs[Snippet]) =
|
||||
builder.addStmt():
|
||||
builder.addCall(callee, args)
|
||||
|
||||
# XXX blocks need indent tracker in `Builder` object
|
||||
|
||||
template addSingleIfStmt(builder: var Builder, cond: Snippet, body: typed) =
|
||||
builder.add("if (")
|
||||
builder.add(cond)
|
||||
builder.addLineEndIndent(") {")
|
||||
body
|
||||
builder.addLineEndDedent("}")
|
||||
|
||||
template addSingleIfStmtWithCond(builder: var Builder, condBody: typed, body: typed) =
|
||||
builder.add("if (")
|
||||
condBody
|
||||
builder.addLineEndIndent(") {")
|
||||
body
|
||||
builder.addLineEndDedent("}")
|
||||
|
||||
proc initIfStmt(builder: var Builder): IfBuilder =
|
||||
IfBuilder(state: WaitingIf)
|
||||
|
||||
proc finishIfStmt(builder: var Builder, stmt: IfBuilder) =
|
||||
assert stmt.state != InBlock
|
||||
builder.addNewline()
|
||||
|
||||
template addIfStmt(builder: var Builder, stmt: out IfBuilder, body: typed) =
|
||||
stmt = initIfStmt(builder)
|
||||
body
|
||||
finishIfStmt(builder, stmt)
|
||||
|
||||
proc initElifBranch(builder: var Builder, stmt: var IfBuilder, cond: Snippet) =
|
||||
case stmt.state
|
||||
of WaitingIf:
|
||||
builder.add("if (")
|
||||
of WaitingElseIf:
|
||||
builder.add(" else if (")
|
||||
else: assert false, $stmt.state
|
||||
builder.add(cond)
|
||||
builder.addLineEndIndent(") {")
|
||||
stmt.state = InBlock
|
||||
|
||||
proc initElseBranch(builder: var Builder, stmt: var IfBuilder) =
|
||||
assert stmt.state == WaitingElseIf, $stmt.state
|
||||
builder.addLineEndIndent(" else {")
|
||||
stmt.state = InBlock
|
||||
|
||||
proc finishBranch(builder: var Builder, stmt: var IfBuilder) =
|
||||
builder.addDedent("}")
|
||||
stmt.state = WaitingElseIf
|
||||
|
||||
template addElifBranch(builder: var Builder, stmt: var IfBuilder, cond: Snippet, body: typed) =
|
||||
initElifBranch(builder, stmt, cond)
|
||||
body
|
||||
finishBranch(builder, stmt)
|
||||
|
||||
template addElseBranch(builder: var Builder, stmt: var IfBuilder, body: typed) =
|
||||
initElseBranch(builder, stmt)
|
||||
body
|
||||
finishBranch(builder, stmt)
|
||||
|
||||
proc initForRange(builder: var Builder, i, start, bound: Snippet, inclusive: bool = false) =
|
||||
builder.add("for (")
|
||||
builder.add(i)
|
||||
builder.add(" = ")
|
||||
builder.add(start)
|
||||
builder.add("; ")
|
||||
builder.add(i)
|
||||
if inclusive:
|
||||
builder.add(" <= ")
|
||||
else:
|
||||
builder.add(" < ")
|
||||
builder.add(bound)
|
||||
builder.add("; ")
|
||||
builder.add(i)
|
||||
builder.addLineEndIndent("++) {")
|
||||
|
||||
proc initForStep(builder: var Builder, i, start, bound, step: Snippet, inclusive: bool = false) =
|
||||
builder.add("for (")
|
||||
builder.add(i)
|
||||
builder.add(" = ")
|
||||
builder.add(start)
|
||||
builder.add("; ")
|
||||
builder.add(i)
|
||||
if inclusive:
|
||||
builder.add(" <= ")
|
||||
else:
|
||||
builder.add(" < ")
|
||||
builder.add(bound)
|
||||
builder.add("; ")
|
||||
builder.add(i)
|
||||
builder.add(" += ")
|
||||
builder.add(step)
|
||||
builder.addLineEndIndent(") {")
|
||||
|
||||
proc finishFor(builder: var Builder) {.inline.} =
|
||||
builder.addLineEndDedent("}")
|
||||
|
||||
template addForRangeExclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
|
||||
initForRange(builder, i, start, bound, false)
|
||||
body
|
||||
finishFor(builder)
|
||||
|
||||
template addForRangeInclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
|
||||
initForRange(builder, i, start, bound, true)
|
||||
body
|
||||
finishFor(builder)
|
||||
|
||||
template addSwitchStmt(builder: var Builder, val: Snippet, body: typed) =
|
||||
builder.add("switch (")
|
||||
builder.add(val)
|
||||
builder.addLineEnd(") {") # no indent
|
||||
body
|
||||
builder.addLineEnd("}")
|
||||
|
||||
template addSingleSwitchCase(builder: var Builder, val: Snippet, body: typed) =
|
||||
builder.add("case ")
|
||||
builder.add(val)
|
||||
builder.addLineEndIndent(":")
|
||||
body
|
||||
builder.addLineEndDedent("")
|
||||
|
||||
type
|
||||
SwitchCaseState = enum
|
||||
None, Of, Else, Finished
|
||||
SwitchCaseBuilder = object
|
||||
state: SwitchCaseState
|
||||
|
||||
proc addCase(builder: var Builder, info: var SwitchCaseBuilder, val: Snippet) =
|
||||
if info.state != Of:
|
||||
assert info.state == None
|
||||
info.state = Of
|
||||
builder.add("case ")
|
||||
builder.add(val)
|
||||
builder.addLineEndIndent(":")
|
||||
|
||||
proc addCaseRange(builder: var Builder, info: var SwitchCaseBuilder, first, last: Snippet) =
|
||||
if info.state != Of:
|
||||
assert info.state == None
|
||||
info.state = Of
|
||||
builder.add("case ")
|
||||
builder.add(first)
|
||||
builder.add(" ... ")
|
||||
builder.add(last)
|
||||
builder.addLineEndIndent(":")
|
||||
|
||||
proc addCaseElse(builder: var Builder, info: var SwitchCaseBuilder) =
|
||||
assert info.state == None
|
||||
info.state = Else
|
||||
builder.addLineEndIndent("default:")
|
||||
|
||||
template addSwitchCase(builder: var Builder, info: out SwitchCaseBuilder, caseBody, body: typed) =
|
||||
info = SwitchCaseBuilder(state: None)
|
||||
caseBody
|
||||
info.state = Finished
|
||||
body
|
||||
builder.addLineEndDedent("")
|
||||
|
||||
template addSwitchElse(builder: var Builder, body: typed) =
|
||||
builder.addLineEndIndent("default:")
|
||||
body
|
||||
builder.addLineEndDedent("")
|
||||
|
||||
proc addBreak(builder: var Builder) =
|
||||
builder.addLineEnd("break;")
|
||||
|
||||
type ScopeBuilder = object
|
||||
inside: bool
|
||||
|
||||
proc initScope(builder: var Builder): ScopeBuilder =
|
||||
builder.addLineEndIndent("{")
|
||||
result = ScopeBuilder(inside: true)
|
||||
|
||||
proc finishScope(builder: var Builder, scope: var ScopeBuilder) =
|
||||
assert scope.inside, "scope not inited"
|
||||
builder.addLineEndDedent("}")
|
||||
scope.inside = false
|
||||
|
||||
template addScope(builder: var Builder, body: typed) =
|
||||
builder.addLineEndIndent("{")
|
||||
body
|
||||
builder.addLineEndDedent("}")
|
||||
|
||||
type WhileBuilder = object
|
||||
inside: bool
|
||||
|
||||
proc initWhileStmt(builder: var Builder, cond: Snippet): WhileBuilder =
|
||||
builder.add("while (")
|
||||
builder.add(cond)
|
||||
builder.addLineEndIndent(") {")
|
||||
result = WhileBuilder(inside: true)
|
||||
|
||||
proc finishWhileStmt(builder: var Builder, stmt: var WhileBuilder) =
|
||||
assert stmt.inside, "while stmt not inited"
|
||||
builder.addLineEndDedent("}")
|
||||
stmt.inside = false
|
||||
|
||||
template addWhileStmt(builder: var Builder, cond: Snippet, body: typed) =
|
||||
builder.add("while (")
|
||||
builder.add(cond)
|
||||
builder.addLineEndIndent(") {")
|
||||
body
|
||||
builder.addLineEndDedent("}")
|
||||
|
||||
proc addLabel(builder: var Builder, name: TLabel) =
|
||||
builder.add(name)
|
||||
builder.addLineEnd(": ;")
|
||||
|
||||
proc addReturn(builder: var Builder) =
|
||||
builder.addLineEnd("return;")
|
||||
|
||||
proc addReturn(builder: var Builder, value: Snippet) =
|
||||
builder.add("return ")
|
||||
builder.add(value)
|
||||
builder.addLineEnd(";")
|
||||
|
||||
proc addGoto(builder: var Builder, label: TLabel) =
|
||||
builder.add("goto ")
|
||||
builder.add(label)
|
||||
builder.addLineEnd(";")
|
||||
|
||||
proc addComputedGoto(builder: var Builder, value: Snippet) =
|
||||
builder.add("goto *")
|
||||
builder.add(value)
|
||||
builder.addLineEnd(";")
|
||||
|
||||
proc addIncr(builder: var Builder, val: Snippet) =
|
||||
builder.add(val)
|
||||
builder.addLineEnd("++;")
|
||||
|
||||
proc addDecr(builder: var Builder, val: Snippet) =
|
||||
builder.add(val)
|
||||
builder.addLineEnd("--;")
|
||||
|
||||
proc addInPlaceOp(builder: var Builder, binOp: TypedBinaryOp, t: Snippet, a, b: Snippet) =
|
||||
builder.add(a)
|
||||
builder.add(' ')
|
||||
builder.add(typedBinaryOperators[binOp])
|
||||
builder.add("= ")
|
||||
builder.add(b)
|
||||
builder.addLineEnd(";")
|
||||
|
||||
proc addInPlaceOp(builder: var Builder, binOp: UntypedBinaryOp, a, b: Snippet) =
|
||||
builder.add(a)
|
||||
builder.add(' ')
|
||||
builder.add(untypedBinaryOperators[binOp])
|
||||
builder.add("= ")
|
||||
builder.add(b)
|
||||
builder.addLineEnd(";")
|
||||
|
||||
proc cInPlaceOp(binOp: TypedBinaryOp, t: Snippet, a, b: Snippet): Snippet =
|
||||
result = ""
|
||||
result.add(a)
|
||||
result.add(' ')
|
||||
result.add(typedBinaryOperators[binOp])
|
||||
result.add("= ")
|
||||
result.add(b)
|
||||
result.add(";\n")
|
||||
|
||||
proc cInPlaceOp(binOp: UntypedBinaryOp, a, b: Snippet): Snippet =
|
||||
result = ""
|
||||
result.add(a)
|
||||
result.add(' ')
|
||||
result.add(untypedBinaryOperators[binOp])
|
||||
result.add("= ")
|
||||
result.add(b)
|
||||
result.add(";\n")
|
||||
|
||||
template addCPragma(builder: var Builder, val: Snippet) =
|
||||
builder.addNewline()
|
||||
builder.add("#pragma ")
|
||||
builder.add(val)
|
||||
builder.addNewline()
|
||||
|
||||
proc addDiscard(builder: var Builder, val: Snippet) =
|
||||
builder.add("(void)")
|
||||
builder.add(val)
|
||||
builder.addLineEnd(";")
|
||||
@@ -84,21 +84,20 @@ proc cleanupTemp(p: BProc; returnType: PType, tmp: TLoc): bool =
|
||||
let dtor = getAttachedOp(p.module.g.graph, returnType, attachedDestructor)
|
||||
var op = initLocExpr(p, newSymNode(dtor))
|
||||
var callee = rdLoc(op)
|
||||
let destroyArg =
|
||||
if dtor.typ.firstParamType.kind == tyVar:
|
||||
cAddr(rdLoc(tmp))
|
||||
let destroy = if dtor.typ.firstParamType.kind == tyVar:
|
||||
callee & "(&" & rdLoc(tmp) & ")"
|
||||
else:
|
||||
rdLoc(tmp)
|
||||
let destroy = cCall(callee, destroyArg)
|
||||
callee & "(" & rdLoc(tmp) & ")"
|
||||
raiseExitCleanup(p, destroy)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
result: var Builder, call: var CallBuilder) =
|
||||
callee, params: Rope) =
|
||||
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
|
||||
genLineDir(p, ri)
|
||||
var pl = callee & "(" & params
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
if typ.returnType != nil:
|
||||
@@ -107,6 +106,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
# perhaps generate no temp if the call doesn't have side effects
|
||||
flags.incl needTempForOpenArray
|
||||
if isInvalidReturnType(p.config, typ):
|
||||
if params.len != 0: pl.add(", ")
|
||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
|
||||
# Great, we can use 'd':
|
||||
@@ -114,39 +114,33 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
elif d.k notin {locTemp} and not hasNoInit(ri):
|
||||
# reset before pass as 'result' var:
|
||||
discard "resetLoc(p, d)"
|
||||
let rad = addrLoc(p.config, d)
|
||||
result.addArgument(call):
|
||||
result.add(rad)
|
||||
result.finishCallBuilder(call)
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(result))
|
||||
pl.add(addrLoc(p.config, d))
|
||||
pl.add(");\n")
|
||||
line(p, cpsStmts, pl)
|
||||
else:
|
||||
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
|
||||
let ratmp = addrLoc(p.config, tmp)
|
||||
result.addArgument(call):
|
||||
result.add(ratmp)
|
||||
result.finishCallBuilder(call)
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(result))
|
||||
pl.add(addrLoc(p.config, tmp))
|
||||
pl.add(");\n")
|
||||
line(p, cpsStmts, pl)
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
result.finishCallBuilder(call)
|
||||
pl.add(")")
|
||||
if p.module.compileToCpp:
|
||||
if lfSingleUse in d.flags:
|
||||
# do not generate spurious temporaries for C++! For C we're better off
|
||||
# with them to prevent undefined behaviour and because the codegen
|
||||
# is free to emit expressions multiple times!
|
||||
d.k = locCall
|
||||
d.snippet = extract(result)
|
||||
d.snippet = pl
|
||||
excl d.flags, lfSingleUse
|
||||
else:
|
||||
if d.k == locNone and p.splitDecls == 0 and p.config.exc != excGoto:
|
||||
d = getTempCpp(p, typ.returnType, extract(result))
|
||||
d = getTempCpp(p, typ.returnType, pl)
|
||||
else:
|
||||
if d.k == locNone: d = getTemp(p, typ.returnType)
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.snippet = extract(result)
|
||||
list.snippet = pl
|
||||
genAssignment(p, d, list, {needAssignCall}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
|
||||
@@ -157,7 +151,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
d = getTemp(p, typ.returnType)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.snippet = extract(result)
|
||||
list.snippet = pl
|
||||
genAssignment(p, d, list, flags+{needAssignCall}) # no need for deep copying
|
||||
if canRaise:
|
||||
if not (useTemp and cleanupTemp(p, typ.returnType, d)):
|
||||
@@ -165,16 +159,15 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
else:
|
||||
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.snippet = extract(result)
|
||||
list.snippet = pl
|
||||
genAssignment(p, tmp, list, flags+{needAssignCall}) # no need for deep copying
|
||||
if canRaise:
|
||||
if not cleanupTemp(p, typ.returnType, tmp):
|
||||
raiseExit(p)
|
||||
genAssignment(p, d, tmp, {})
|
||||
else:
|
||||
finishCallBuilder(result, call)
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(result))
|
||||
pl.add(");\n")
|
||||
line(p, cpsStmts, pl)
|
||||
if canRaise: raiseExit(p)
|
||||
|
||||
proc genBoundsCheck(p: BProc; arr, a, b: TLoc; arrTyp: PType)
|
||||
@@ -206,58 +199,49 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
|
||||
if optBoundsCheck in p.options:
|
||||
genBoundsCheck(p, a, b, c, ty)
|
||||
if prepareForMutation:
|
||||
let bra = byRefLoc(p, a)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimPrepareStrMutationV2"),
|
||||
bra)
|
||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||
let dest = getTypeDesc(p.module, destType)
|
||||
let ra = rdLoc(a)
|
||||
let rb = rdLoc(b)
|
||||
let rc = rdLoc(c)
|
||||
let lengthExpr = cOp(Add, NimInt, cOp(Sub, NimInt, rc, rb), cIntValue(1))
|
||||
let lengthExpr = "($1)-($2)+1" % [rdLoc(c), rdLoc(b)]
|
||||
case ty.kind
|
||||
of tyArray:
|
||||
let first = toInt64(firstOrd(p.config, ty))
|
||||
if first == 0:
|
||||
result = (cCast(ptrType(dest), cOp(Add, NimInt, ra, rb)), lengthExpr)
|
||||
result = ("($3*)(($1)+($2))" % [rdLoc(a), rdLoc(b), dest],
|
||||
lengthExpr)
|
||||
else:
|
||||
let lit = cIntLiteral(first)
|
||||
result = (cCast(ptrType(dest), cOp(Add, NimInt, ra, cOp(Sub, NimInt, rb, lit))), lengthExpr)
|
||||
var lit = newRopeAppender()
|
||||
intLiteral(first, lit)
|
||||
result = ("($4*)($1)+(($2)-($3))" %
|
||||
[rdLoc(a), rdLoc(b), lit, dest],
|
||||
lengthExpr)
|
||||
of tyOpenArray, tyVarargs:
|
||||
let data = if reifiedOpenArray(q[1]): dotField(ra, "Field0") else: ra
|
||||
result = (cCast(ptrType(dest), cOp(Add, NimInt, data, rb)), lengthExpr)
|
||||
if reifiedOpenArray(q[1]):
|
||||
result = ("($3*)($1.Field0)+($2)" % [rdLoc(a), rdLoc(b), dest],
|
||||
lengthExpr)
|
||||
else:
|
||||
result = ("($3*)($1)+($2)" % [rdLoc(a), rdLoc(b), dest],
|
||||
lengthExpr)
|
||||
of tyUncheckedArray, tyCstring:
|
||||
result = (cCast(ptrType(dest), cOp(Add, NimInt, ra, rb)), lengthExpr)
|
||||
result = ("($3*)($1)+($2)" % [rdLoc(a), rdLoc(b), dest],
|
||||
lengthExpr)
|
||||
of tyString, tySequence:
|
||||
let atyp = skipTypes(a.t, abstractInst)
|
||||
if formalType.skipTypes(abstractInst).kind in {tyVar} and atyp.kind == tyString and
|
||||
optSeqDestructors in p.config.globalOptions and not p.config.usesSso():
|
||||
let bra = byRefLoc(p, a)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimPrepareStrMutationV2"),
|
||||
bra)
|
||||
if p.config.usesSso() and
|
||||
skipTypes(a.t, abstractVar + abstractInst).kind == tyString:
|
||||
let strPtr = if atyp.kind in {tyVar} and not compileToCpp(p.module): ra
|
||||
else: addrLoc(p.config, a)
|
||||
result = (
|
||||
cCast(ptrType(dest), cOp(Add, NimInt,
|
||||
cCall(cgsymValue(p.module, "nimStrData"), strPtr), rb)),
|
||||
lengthExpr)
|
||||
optSeqDestructors in p.config.globalOptions:
|
||||
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))],
|
||||
lengthExpr)
|
||||
else:
|
||||
var val: Snippet
|
||||
if atyp.kind in {tyVar} and not compileToCpp(p.module):
|
||||
val = cDeref(ra)
|
||||
else:
|
||||
val = ra
|
||||
result = (
|
||||
cIfExpr(dataFieldAccessor(p, val),
|
||||
cCast(ptrType(dest), cOp(Add, NimInt, dataField(p, val), rb)),
|
||||
NimNil),
|
||||
lengthExpr)
|
||||
result = ("(($5) ? (($4*)$1$3+($2)) : NIM_NIL)" %
|
||||
[rdLoc(a), rdLoc(b), dataField(p), 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 Builder) =
|
||||
proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
|
||||
var q = skipConv(n)
|
||||
var skipped = false
|
||||
while q.kind == nkStmtListExpr and q.len > 0:
|
||||
@@ -272,82 +256,42 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Builder) =
|
||||
genStmts(p, q[i])
|
||||
q = q.lastSon
|
||||
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ.elementType)
|
||||
result.add(x)
|
||||
result.addArgumentSeparator()
|
||||
result.add(y)
|
||||
result.add x & ", " & y
|
||||
else:
|
||||
var a = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n)
|
||||
case skipTypes(a.t, abstractVar+{tyStatic}).kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
let ra = rdLoc(a)
|
||||
if reifiedOpenArray(n):
|
||||
if a.t.kind in {tyVar, tyLent}:
|
||||
result.add(derefField(ra, "Field0"))
|
||||
result.addArgumentSeparator()
|
||||
result.add(derefField(ra, "Field1"))
|
||||
result.add "$1->Field0, $1->Field1" % [rdLoc(a)]
|
||||
else:
|
||||
result.add(dotField(ra, "Field0"))
|
||||
result.addArgumentSeparator()
|
||||
result.add(dotField(ra, "Field1"))
|
||||
result.add "$1.Field0, $1.Field1" % [rdLoc(a)]
|
||||
else:
|
||||
result.add(ra)
|
||||
result.addArgumentSeparator()
|
||||
result.add(ra & "Len_0")
|
||||
result.add "$1, $1Len_0" % [rdLoc(a)]
|
||||
of tyString, tySequence:
|
||||
let ntyp = skipTypes(n.typ, abstractInst)
|
||||
if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and
|
||||
optSeqDestructors in p.config.globalOptions and not p.config.usesSso():
|
||||
let bra = byRefLoc(p, a)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimPrepareStrMutationV2"),
|
||||
bra)
|
||||
if p.config.usesSso() and
|
||||
skipTypes(n.typ, abstractVar + abstractInst).kind == tyString:
|
||||
if ntyp.kind in {tyVar} and not compileToCpp(p.module):
|
||||
let ra = a.rdLoc
|
||||
result.add(cCall(cgsymValue(p.module, "nimStrData"), ra))
|
||||
result.addArgumentSeparator()
|
||||
result.add(cCall(cgsymValue(p.module, "nimStrLen"), cDeref(ra)))
|
||||
else:
|
||||
result.add(cCall(cgsymValue(p.module, "nimStrData"), addrLoc(p.config, a)))
|
||||
result.addArgumentSeparator()
|
||||
result.add(lenExpr(p, a))
|
||||
elif ntyp.kind in {tyVar} and not compileToCpp(p.module):
|
||||
let ra = a.rdLoc
|
||||
var t = TLoc(snippet: cDeref(ra))
|
||||
let lt = lenExpr(p, t)
|
||||
result.add(cIfExpr(dataFieldAccessor(p, t.snippet), dataField(p, t.snippet), NimNil))
|
||||
result.addArgumentSeparator()
|
||||
result.add(lt)
|
||||
optSeqDestructors in p.config.globalOptions:
|
||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||
if ntyp.kind in {tyVar} and not compileToCpp(p.module):
|
||||
var t = TLoc(snippet: "(*$1)" % [a.rdLoc])
|
||||
result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
|
||||
[a.rdLoc, lenExpr(p, t), dataField(p),
|
||||
dataFieldAccessor(p, "*" & a.rdLoc)]
|
||||
else:
|
||||
let ra = a.rdLoc
|
||||
let la = lenExpr(p, a)
|
||||
result.add(cIfExpr(dataFieldAccessor(p, ra), dataField(p, ra), NimNil))
|
||||
result.addArgumentSeparator()
|
||||
result.add(la)
|
||||
result.add "($4) ? ($1$3) : NIM_NIL, $2" %
|
||||
[a.rdLoc, lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)]
|
||||
of tyArray:
|
||||
let ra = rdLoc(a)
|
||||
result.add(ra)
|
||||
result.addArgumentSeparator()
|
||||
result.addIntValue(lengthOrd(p.config, a.t))
|
||||
result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))]
|
||||
of tyPtr, tyRef:
|
||||
case elementType(a.t).kind
|
||||
of tyString, tySequence:
|
||||
let ra = a.rdLoc
|
||||
var t = TLoc(snippet: cDeref(ra))
|
||||
let lt = lenExpr(p, t)
|
||||
if p.config.usesSso():
|
||||
result.add(cCall(cgsymValue(p.module, "nimStrData"), ra))
|
||||
result.addArgumentSeparator()
|
||||
result.add(cCall(cgsymValue(p.module, "nimStrLen"), t.snippet))
|
||||
else:
|
||||
result.add(cIfExpr(dataFieldAccessor(p, t.snippet), dataField(p, t.snippet), NimNil))
|
||||
result.addArgumentSeparator()
|
||||
result.add(lt)
|
||||
var t = TLoc(snippet: "(*$1)" % [a.rdLoc])
|
||||
result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
|
||||
[a.rdLoc, lenExpr(p, t), dataField(p),
|
||||
dataFieldAccessor(p, "*" & a.rdLoc)]
|
||||
of tyArray:
|
||||
let ra = rdLoc(a)
|
||||
result.add(ra)
|
||||
result.addArgumentSeparator()
|
||||
result.addIntValue(lengthOrd(p.config, elementType(a.t)))
|
||||
result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, elementType(a.t)))]
|
||||
else:
|
||||
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
|
||||
else: internalError(p.config, "openArrayLoc: " & typeToString(a.t))
|
||||
@@ -356,7 +300,7 @@ proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc =
|
||||
# Bug https://github.com/status-im/nimbus-eth2/issues/1549
|
||||
# Aliasing is preferred over stack overflows.
|
||||
# Also don't regress for non ARC-builds, too risky.
|
||||
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc} and
|
||||
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
|
||||
getSize(p.config, a.lode.typ) < 1024:
|
||||
result = getTemp(p, a.lode.typ, needsInit=false)
|
||||
genAssignment(p, result, a, {})
|
||||
@@ -367,13 +311,11 @@ proc expressionsNeedsTmp(p: BProc, a: TLoc): TLoc =
|
||||
result = getTemp(p, a.lode.typ, needsInit=false)
|
||||
genAssignment(p, result, a, {})
|
||||
|
||||
proc genArgStringToCString(p: BProc, n: PNode; result: var Builder; needsTmp: bool) {.inline.} =
|
||||
proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} =
|
||||
var a = initLocExpr(p, n[0])
|
||||
let tmp = withTmpIfNeeded(p, a, needsTmp)
|
||||
let ra = if p.config.usesSso(): byRefLoc(p, tmp) else: tmp.rdLoc
|
||||
result.addCall(cgsymValue(p.module, "nimToCStringConv"), ra)
|
||||
appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc])
|
||||
|
||||
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; needsTmp = false) =
|
||||
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) =
|
||||
var a: TLoc
|
||||
if n.kind == nkStringToCString:
|
||||
genArgStringToCString(p, n, result, needsTmp)
|
||||
@@ -394,8 +336,8 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; n
|
||||
# variable. Thus, we create a temporary pointer variable instead.
|
||||
let needsIndirect = mapType(p.config, n[0].typ, mapTypeChooser(n[0]) == skParam) != ctArray
|
||||
if needsIndirect:
|
||||
n.typ = n.typ.exactReplica
|
||||
n.typ.incl tfVarIsPtr
|
||||
n.typ() = n.typ.exactReplica
|
||||
n.typ.flags.incl tfVarIsPtr
|
||||
a = initLocExprSingleUse(p, n)
|
||||
a = withTmpIfNeeded(p, a, needsTmp)
|
||||
if needsIndirect: a.flags.incl lfIndirect
|
||||
@@ -414,11 +356,12 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; n
|
||||
if param.typ.kind in {tyVar, tyPtr, tyRef, tySink}:
|
||||
let typ = skipTypes(param.typ, abstractPtrs)
|
||||
if not sameBackendTypePickyAliases(typ, n.typ.skipTypes(abstractPtrs)):
|
||||
a.snippet = cCast(getTypeDesc(p.module, param.typ), rdCharLoc(a))
|
||||
a.snippet = "(($1) ($2))" %
|
||||
[getTypeDesc(p.module, param.typ), rdCharLoc(a)]
|
||||
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
|
||||
#assert result != nil
|
||||
|
||||
proc genArgNoParam(p: BProc, n: PNode; result: var Builder; needsTmp = false) =
|
||||
proc genArgNoParam(p: BProc, n: PNode; result: var Rope; needsTmp = false) =
|
||||
var a: TLoc
|
||||
if n.kind == nkStringToCString:
|
||||
genArgStringToCString(p, n, result, needsTmp)
|
||||
@@ -444,6 +387,35 @@ proc skipTrivialIndirections(n: PNode): PNode =
|
||||
result = result[1]
|
||||
else: break
|
||||
|
||||
proc getPotentialWrites(n: PNode; mutate: bool; result: var seq[PNode]) =
|
||||
case n.kind:
|
||||
of nkLiterals, nkIdent, nkFormalParams: discard
|
||||
of nkSym:
|
||||
if mutate: result.add n
|
||||
of nkAsgn, nkFastAsgn, nkSinkAsgn:
|
||||
getPotentialWrites(n[0], true, result)
|
||||
getPotentialWrites(n[1], mutate, result)
|
||||
of nkAddr, nkHiddenAddr:
|
||||
getPotentialWrites(n[0], true, result)
|
||||
of nkBracketExpr, nkDotExpr, nkCheckedFieldExpr:
|
||||
getPotentialWrites(n[0], mutate, result)
|
||||
of nkCallKinds:
|
||||
case n.getMagic:
|
||||
of mIncl, mExcl, mInc, mDec, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mAddr, mNew, mNewFinalize, mWasMoved, mDestroy:
|
||||
getPotentialWrites(n[1], true, result)
|
||||
for i in 2..<n.len:
|
||||
getPotentialWrites(n[i], mutate, result)
|
||||
of mSwap:
|
||||
for i in 1..<n.len:
|
||||
getPotentialWrites(n[i], true, result)
|
||||
else:
|
||||
for i in 1..<n.len:
|
||||
getPotentialWrites(n[i], mutate, result)
|
||||
else:
|
||||
for s in n:
|
||||
getPotentialWrites(s, mutate, result)
|
||||
|
||||
proc getPotentialReads(n: PNode; result: var seq[PNode]) =
|
||||
case n.kind:
|
||||
of nkLiterals, nkIdent, nkFormalParams: discard
|
||||
@@ -452,7 +424,7 @@ proc getPotentialReads(n: PNode; result: var seq[PNode]) =
|
||||
for s in n:
|
||||
getPotentialReads(s, result)
|
||||
|
||||
proc genParams(p: BProc, ri: PNode, typ: PType; result: var Builder, argBuilder: var CallBuilder) =
|
||||
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)
|
||||
@@ -474,22 +446,21 @@ proc genParams(p: BProc, ri: PNode, typ: PType; result: var Builder, argBuilder:
|
||||
# Optimization: don't use a temp, if we would only take the address anyway
|
||||
needTmp[i - 1] = false
|
||||
|
||||
var oldLen = result.len
|
||||
for i in 1..<ri.len:
|
||||
if i < typ.n.len:
|
||||
assert(typ.n[i].kind == nkSym)
|
||||
let paramType = typ.n[i]
|
||||
if not paramType.typ.isCompileTimeOnly:
|
||||
var arg = newBuilder("")
|
||||
genArg(p, ri[i], paramType.sym, ri, arg, needTmp[i-1])
|
||||
if arg.buf.len != 0:
|
||||
result.addArgument(argBuilder):
|
||||
result.add(extract(arg))
|
||||
if oldLen != result.len:
|
||||
result.add(", ")
|
||||
oldLen = result.len
|
||||
genArg(p, ri[i], paramType.sym, ri, result, needTmp[i-1])
|
||||
else:
|
||||
var arg = newBuilder("")
|
||||
genArgNoParam(p, ri[i], arg, needTmp[i-1])
|
||||
if arg.buf.len != 0:
|
||||
result.addArgument(argBuilder):
|
||||
result.add(extract(arg))
|
||||
if oldLen != result.len:
|
||||
result.add(", ")
|
||||
oldLen = result.len
|
||||
genArgNoParam(p, ri[i], result, needTmp[i-1])
|
||||
|
||||
proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
|
||||
if sym.flags * {sfImportc, sfNonReloadable} == {} and sym.loc.k == locProc and
|
||||
@@ -503,39 +474,21 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var typ = skipTypes(ri[0].typ, abstractInstOwned)
|
||||
assert(typ.kind == tyProc)
|
||||
|
||||
var params = newRopeAppender()
|
||||
genParams(p, ri, typ, params)
|
||||
|
||||
var callee = rdLoc(op)
|
||||
if p.hcrOn and ri[0].kind == nkSym:
|
||||
callee.addActualSuffixForHCR(p.module.module, ri[0].sym)
|
||||
|
||||
var res = newBuilder("")
|
||||
var call = initCallBuilder(res, callee)
|
||||
genParams(p, ri, typ, res, call)
|
||||
fixupCall(p, le, ri, d, res, call)
|
||||
fixupCall(p, le, ri, d, callee, params)
|
||||
|
||||
proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
|
||||
template callProc(rp, params, pTyp: Snippet): Snippet =
|
||||
let e = dotField(rp, "ClE_0")
|
||||
let p = dotField(rp, "ClP_0")
|
||||
let eCall =
|
||||
# note `params` here is actually multiple params
|
||||
if params.len == 0:
|
||||
cCall(p, e)
|
||||
else:
|
||||
cCall(p, params, e)
|
||||
cIfExpr(e,
|
||||
eCall,
|
||||
cCall(cCast(pTyp, p), params))
|
||||
proc addComma(r: Rope): Rope =
|
||||
if r.len == 0: r else: r & ", "
|
||||
|
||||
template callIter(rp, params: Snippet): Snippet =
|
||||
# we know the env exists
|
||||
let e = dotField(rp, "ClE_0")
|
||||
let p = dotField(rp, "ClP_0")
|
||||
# note `params` here is actually multiple params
|
||||
if params.len == 0:
|
||||
cCall(p, e)
|
||||
else:
|
||||
cCall(p, params, e)
|
||||
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 = initLocExpr(p, ri[0])
|
||||
|
||||
@@ -543,23 +496,20 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var typ = skipTypes(ri[0].typ, abstractInstOwned)
|
||||
assert(typ.kind == tyProc)
|
||||
|
||||
var params = newBuilder("")
|
||||
var argBuilder = default(CallBuilder) # not initCallBuilder, we just want the params
|
||||
genParams(p, ri, typ, params, argBuilder)
|
||||
var pl = newRopeAppender()
|
||||
genParams(p, ri, typ, pl)
|
||||
|
||||
template genCallPattern {.dirty.} =
|
||||
let rp = rdLoc(op)
|
||||
let pars = extract(params)
|
||||
p.s(cpsStmts).addStmt():
|
||||
if tfIterator in typ.flags:
|
||||
p.s(cpsStmts).add(callIter(rp, pars))
|
||||
else:
|
||||
p.s(cpsStmts).add(callProc(rp, pars, rawProc))
|
||||
if tfIterator in typ.flags:
|
||||
lineF(p, cpsStmts, PatIter & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
|
||||
else:
|
||||
lineF(p, cpsStmts, PatProc & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
|
||||
|
||||
let rawProc = getClosureType(p.module, typ, clHalf)
|
||||
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
|
||||
if typ.returnType != nil:
|
||||
if isInvalidReturnType(p.config, typ):
|
||||
if ri.len > 1: pl.add(", ")
|
||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
|
||||
# Great, we can use 'd':
|
||||
@@ -568,14 +518,12 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
elif d.k notin {locTemp} and not hasNoInit(ri):
|
||||
# reset before pass as 'result' var:
|
||||
discard "resetLoc(p, d)"
|
||||
params.addArgument(argBuilder):
|
||||
params.add(addrLoc(p.config, d))
|
||||
pl.add(addrLoc(p.config, d))
|
||||
genCallPattern()
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
|
||||
params.addArgument(argBuilder):
|
||||
params.add(addrLoc(p.config, tmp))
|
||||
pl.add(addrLoc(p.config, tmp))
|
||||
genCallPattern()
|
||||
if canRaise: raiseExit(p)
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
@@ -583,24 +531,20 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
if d.k == locNone: d = getTemp(p, typ.returnType)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
|
||||
let rp = rdLoc(op)
|
||||
let pars = extract(params)
|
||||
if tfIterator in typ.flags:
|
||||
list.snippet = callIter(rp, pars)
|
||||
list.snippet = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
else:
|
||||
list.snippet = callProc(rp, pars, rawProc)
|
||||
list.snippet = PatProc % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
var tmp: TLoc = getTemp(p, typ.returnType)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
|
||||
let rp = rdLoc(op)
|
||||
let pars = extract(params)
|
||||
if tfIterator in typ.flags:
|
||||
list.snippet = callIter(rp, pars)
|
||||
list.snippet = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
else:
|
||||
list.snippet = callProc(rp, pars, rawProc)
|
||||
list.snippet = PatProc % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
genAssignment(p, tmp, list, {})
|
||||
if canRaise: raiseExit(p)
|
||||
genAssignment(p, d, tmp, {})
|
||||
@@ -608,8 +552,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
genCallPattern()
|
||||
if canRaise: raiseExit(p)
|
||||
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder;
|
||||
argBuilder: var CallBuilder) =
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope;
|
||||
argsCounter: var int) =
|
||||
if i < typ.n.len:
|
||||
# 'var T' is 'T&' in C++. This means we ignore the request of
|
||||
# any nkHiddenAddr when it's a 'var T'.
|
||||
@@ -618,17 +562,20 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder;
|
||||
if paramType.typ.isCompileTimeOnly:
|
||||
discard
|
||||
elif paramType.typ.kind in {tyVar} and ri[i].kind == nkHiddenAddr:
|
||||
result.addArgument(argBuilder):
|
||||
genArgNoParam(p, ri[i][0], result)
|
||||
if argsCounter > 0: result.add ", "
|
||||
genArgNoParam(p, ri[i][0], result)
|
||||
inc argsCounter
|
||||
else:
|
||||
result.addArgument(argBuilder):
|
||||
genArgNoParam(p, ri[i], result) #, typ.n[i].sym)
|
||||
if argsCounter > 0: result.add ", "
|
||||
genArgNoParam(p, ri[i], result) #, typ.n[i].sym)
|
||||
inc argsCounter
|
||||
else:
|
||||
if tfVarargs notin typ.flags:
|
||||
localError(p.config, ri.info, "wrong argument count")
|
||||
else:
|
||||
result.addArgument(argBuilder):
|
||||
genArgNoParam(p, ri[i], result)
|
||||
if argsCounter > 0: result.add ", "
|
||||
genArgNoParam(p, ri[i], result)
|
||||
inc argsCounter
|
||||
|
||||
discard """
|
||||
Dot call syntax in C++
|
||||
@@ -685,7 +632,7 @@ proc skipAddrDeref(node: PNode): PNode =
|
||||
else:
|
||||
result = node
|
||||
|
||||
proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder) =
|
||||
proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope) =
|
||||
# for better or worse c2nim translates the 'this' argument to a 'var T'.
|
||||
# However manual wrappers may also use 'ptr T'. In any case we support both
|
||||
# for convenience.
|
||||
@@ -720,15 +667,15 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder) =
|
||||
genArgNoParam(p, ri, result) #, typ.n[i].sym)
|
||||
result.add(".")
|
||||
|
||||
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Builder) =
|
||||
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Rope) =
|
||||
var i = 0
|
||||
var j = 1
|
||||
while i < pat.len:
|
||||
case pat[i]
|
||||
of '@':
|
||||
var callBuilder = default(CallBuilder) # not init call builder
|
||||
var argsCounter = 0
|
||||
for k in j..<ri.len:
|
||||
genOtherArg(p, ri, k, typ, result, callBuilder)
|
||||
genOtherArg(p, ri, k, typ, result, argsCounter)
|
||||
inc i
|
||||
of '#':
|
||||
if i+1 < pat.len and pat[i+1] in {'+', '@'}:
|
||||
@@ -738,11 +685,11 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Bu
|
||||
if pat[i+1] == '+': genArgNoParam(p, ri[0], result)
|
||||
result.add("(")
|
||||
if 1 < ri.len:
|
||||
var callBuilder: CallBuilder = default(CallBuilder)
|
||||
genOtherArg(p, ri, 1, typ, result, callBuilder)
|
||||
var argsCounterB = 0
|
||||
genOtherArg(p, ri, 1, typ, result, argsCounterB)
|
||||
for k in j+1..<ri.len:
|
||||
var callBuilder: CallBuilder = default(CallBuilder)
|
||||
genOtherArg(p, ri, k, typ, result, callBuilder)
|
||||
var argsCounterB = 0
|
||||
genOtherArg(p, ri, k, typ, result, argsCounterB)
|
||||
result.add(")")
|
||||
else:
|
||||
localError(p.config, ri.info, "call expression expected for C++ pattern")
|
||||
@@ -756,15 +703,15 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Bu
|
||||
genArgNoParam(p, arg, result)
|
||||
#result.add debugTree(arg, 0, 10)
|
||||
else:
|
||||
var callBuilder = default(CallBuilder) # not init call builder
|
||||
genOtherArg(p, ri, j, typ, result, callBuilder)
|
||||
var argsCounter = 0
|
||||
genOtherArg(p, ri, j, typ, result, argsCounter)
|
||||
inc j
|
||||
inc i
|
||||
of '\'':
|
||||
var idx, stars: int = 0
|
||||
if scanCppGenericSlot(pat, i, idx, stars):
|
||||
var t = resolveStarsInCppType(typ, idx, stars)
|
||||
if t == nil: result.add(CVoid)
|
||||
if t == nil: result.add("void")
|
||||
else: result.add(getTypeDesc(p.module, t))
|
||||
else:
|
||||
let start = i
|
||||
@@ -783,7 +730,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
let pat = $ri[0].sym.loc.snippet
|
||||
internalAssert p.config, pat.len > 0
|
||||
if pat.contains({'#', '(', '@', '\''}):
|
||||
var pl = newBuilder("")
|
||||
var pl = newRopeAppender()
|
||||
genPatternCall(p, ri, pat, typ, pl)
|
||||
# simpler version of 'fixupCall' that works with the pl+params combination:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
@@ -793,32 +740,32 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
# with them to prevent undefined behaviour and because the codegen
|
||||
# is free to emit expressions multiple times!
|
||||
d.k = locCall
|
||||
d.snippet = extract(pl)
|
||||
d.snippet = pl
|
||||
excl d.flags, lfSingleUse
|
||||
else:
|
||||
if d.k == locNone: d = getTemp(p, typ.returnType)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.snippet = extract(pl)
|
||||
list.snippet = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(pl))
|
||||
pl.add(";\n")
|
||||
line(p, cpsStmts, pl)
|
||||
else:
|
||||
var pl = newBuilder("")
|
||||
var pl = newRopeAppender()
|
||||
var argsCounter = 0
|
||||
if 1 < ri.len:
|
||||
genThisArg(p, ri, 1, typ, pl)
|
||||
pl.add(op.snippet)
|
||||
var res = newBuilder("")
|
||||
var call = initCallBuilder(res, extract(pl))
|
||||
var params = newRopeAppender()
|
||||
for i in 2..<ri.len:
|
||||
genOtherArg(p, ri, i, typ, res, call)
|
||||
fixupCall(p, le, ri, d, res, call)
|
||||
genOtherArg(p, ri, i, typ, params, argsCounter)
|
||||
fixupCall(p, le, ri, d, pl, params)
|
||||
|
||||
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
# generates a crappy ObjC call
|
||||
var op = initLocExpr(p, ri[0])
|
||||
var pl = newBuilder("[")
|
||||
var pl = "["
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
@@ -860,27 +807,24 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
if d.k == locNone: d = getTemp(p, typ.returnType, needsInit=true)
|
||||
pl.add("Result: ")
|
||||
pl.add(addrLoc(p.config, d))
|
||||
pl.add("]")
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(pl))
|
||||
pl.add("];\n")
|
||||
line(p, cpsStmts, pl)
|
||||
else:
|
||||
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
|
||||
pl.add(addrLoc(p.config, tmp))
|
||||
pl.add("]")
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(pl))
|
||||
pl.add("];\n")
|
||||
line(p, cpsStmts, pl)
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
else:
|
||||
pl.add("]")
|
||||
if d.k == locNone: d = getTemp(p, typ.returnType)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc = initLoc(locCall, ri, OnUnknown)
|
||||
list.snippet = extract(pl)
|
||||
list.snippet = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
pl.add("]")
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(extract(pl))
|
||||
pl.add("];\n")
|
||||
line(p, cpsStmts, pl)
|
||||
|
||||
proc notYetAlive(n: PNode): bool {.inline.} =
|
||||
let r = getRoot(n)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,17 +16,16 @@
|
||||
## implementation.
|
||||
|
||||
template detectVersion(field, corename) =
|
||||
if m.g.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc, gcHooks}:
|
||||
result = 2
|
||||
else:
|
||||
result = 1
|
||||
if m.g.field == 0:
|
||||
let core = getCompilerProc(m.g.graph, corename)
|
||||
if core == nil or core.kind != skConst:
|
||||
m.g.field = 1
|
||||
else:
|
||||
m.g.field = toInt(ast.getInt(core.astdef))
|
||||
result = m.g.field
|
||||
|
||||
proc detectStrVersion(m: BModule): int =
|
||||
if m.g.config.usesSso() and
|
||||
m.g.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc, gcHooks}:
|
||||
result = 3
|
||||
else:
|
||||
detectVersion(strVersion, "nimStrVersion")
|
||||
detectVersion(strVersion, "nimStrVersion")
|
||||
|
||||
proc detectSeqVersion(m: BModule): int =
|
||||
detectVersion(seqVersion, "nimSeqVersion")
|
||||
@@ -37,84 +36,52 @@ proc genStringLiteralDataOnlyV1(m: BModule, s: string; result: var Rope) =
|
||||
cgsym(m, "TGenericSeq")
|
||||
let tmp = getTempName(m)
|
||||
result.add tmp
|
||||
var res = newBuilder("")
|
||||
res.addVarWithTypeAndInitializer(AlwaysConst, name = tmp):
|
||||
res.addSimpleStruct(m, name = "", baseType = ""):
|
||||
res.addField(name = "Sup", typ = "TGenericSeq")
|
||||
res.addArrayField(name = "data", elementType = NimChar, len = s.len + 1)
|
||||
do:
|
||||
var strInit: StructInitializer
|
||||
res.addStructInitializer(strInit, kind = siOrderedStruct):
|
||||
res.addField(strInit, name = "Sup"):
|
||||
var seqInit: StructInitializer
|
||||
res.addStructInitializer(seqInit, kind = siOrderedStruct):
|
||||
res.addField(seqInit, name = "len"):
|
||||
res.addIntValue(s.len)
|
||||
res.addField(seqInit, name = "reserved"):
|
||||
res.add(cCast(NimInt, cOp(BitOr, NimUint, cCast(NimUint, cIntValue(s.len)), NimStrlitFlag)))
|
||||
res.addField(strInit, name = "data"):
|
||||
res.add(makeCString(s))
|
||||
m.s[cfsStrData].add(extract(res))
|
||||
m.s[cfsStrData].addf("STRING_LITERAL($1, $2, $3);$n",
|
||||
[tmp, makeCString(s), rope(s.len)])
|
||||
|
||||
proc genStringLiteralV1(m: BModule; n: PNode; result: var Builder) =
|
||||
proc genStringLiteralV1(m: BModule; n: PNode; result: var Rope) =
|
||||
if s.isNil:
|
||||
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), NimNil))
|
||||
appcg(m, result, "((#NimStringDesc*) NIM_NIL)", [])
|
||||
else:
|
||||
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
||||
var name: string = ""
|
||||
if id == m.labels:
|
||||
# string literal not found in the cache:
|
||||
genStringLiteralDataOnlyV1(m, n.strVal, name)
|
||||
appcg(m, result, "((#NimStringDesc*) &", [])
|
||||
genStringLiteralDataOnlyV1(m, n.strVal, result)
|
||||
result.add ")"
|
||||
else:
|
||||
name = m.tmpBase & $id
|
||||
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), cAddr(name)))
|
||||
appcg(m, result, "((#NimStringDesc*) &$1$2)",
|
||||
[m.tmpBase, id])
|
||||
|
||||
# ------ Version 2: destructor based strings and seqs -----------------------
|
||||
|
||||
proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) =
|
||||
var res = newBuilder("")
|
||||
res.addVarWithTypeAndInitializer(
|
||||
if isConst: AlwaysConst else: Global,
|
||||
name = result):
|
||||
res.addSimpleStruct(m, name = "", baseType = ""):
|
||||
res.addField(name = "cap", typ = NimInt)
|
||||
res.addArrayField(name = "data", elementType = NimChar, len = s.len + 1)
|
||||
do:
|
||||
var structInit: StructInitializer
|
||||
res.addStructInitializer(structInit, kind = siOrderedStruct):
|
||||
res.addField(structInit, name = "cap"):
|
||||
res.add(cOp(BitOr, NimInt, cIntValue(s.len), NimStrlitFlag))
|
||||
res.addField(structInit, name = "data"):
|
||||
res.add(makeCString(s))
|
||||
m.s[cfsStrData].add(extract(res))
|
||||
m.s[cfsStrData].addf("static $4 struct {$n" &
|
||||
" NI cap; NIM_CHAR data[$2+1];$n" &
|
||||
"} $1 = { $2 | NIM_STRLIT_FLAG, $3 };$n",
|
||||
[result, rope(s.len), makeCString(s),
|
||||
rope(if isConst: "const" else: "")])
|
||||
|
||||
proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Builder) =
|
||||
proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Rope) =
|
||||
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
||||
var litName: string
|
||||
if id == m.labels:
|
||||
let pureLit = getTempName(m)
|
||||
genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst)
|
||||
let tmp = getTempName(m)
|
||||
result.add tmp
|
||||
cgsym(m, "NimStrPayload")
|
||||
cgsym(m, "NimStringV2")
|
||||
# string literal not found in the cache:
|
||||
litName = getTempName(m)
|
||||
genStringLiteralDataOnlyV2(m, n.strVal, litName, isConst)
|
||||
m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
|
||||
[tmp, rope(n.strVal.len), pureLit, rope(if isConst: "const" else: "")])
|
||||
else:
|
||||
litName = m.tmpBase & $id
|
||||
let tmp = getTempName(m)
|
||||
result.add tmp
|
||||
var res = newBuilder("")
|
||||
res.addVarWithInitializer(
|
||||
if isConst: AlwaysConst else: Global,
|
||||
name = tmp,
|
||||
typ = "NimStringV2"):
|
||||
var strInit: StructInitializer
|
||||
res.addStructInitializer(strInit, kind = siOrderedStruct):
|
||||
res.addField(strInit, name = "len"):
|
||||
res.addIntValue(n.strVal.len)
|
||||
res.addField(strInit, name = "p"):
|
||||
res.add(cCast(ptrType("NimStrPayload"), cAddr(litName)))
|
||||
m.s[cfsStrData].add(extract(res))
|
||||
let tmp = getTempName(m)
|
||||
result.add tmp
|
||||
m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
|
||||
[tmp, rope(n.strVal.len), m.tmpBase & rope(id),
|
||||
rope(if isConst: "const" else: "")])
|
||||
|
||||
proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Builder) =
|
||||
proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Rope) =
|
||||
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
||||
var pureLit: Rope
|
||||
if id == m.labels:
|
||||
@@ -125,198 +92,7 @@ proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Bu
|
||||
genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst)
|
||||
else:
|
||||
pureLit = m.tmpBase & rope(id)
|
||||
var strInit: StructInitializer
|
||||
result.addStructInitializer(strInit, kind = siOrderedStruct):
|
||||
result.addField(strInit, name = "len"):
|
||||
result.addIntValue(n.strVal.len)
|
||||
result.addField(strInit, name = "p"):
|
||||
result.add(cCast(ptrType("NimStrPayload"), cAddr(pureLit)))
|
||||
|
||||
proc ssoCharLit(ch: char): string =
|
||||
## Return a C char literal for ch, with proper escaping.
|
||||
const hexDigits = "0123456789abcdef"
|
||||
result = "'"
|
||||
case ch
|
||||
of '\'': result.add("\\'")
|
||||
of '\\': result.add("\\\\")
|
||||
of '\0': result.add("\\0")
|
||||
of '\n': result.add("\\n")
|
||||
of '\r': result.add("\\r")
|
||||
of '\t': result.add("\\t")
|
||||
elif ch.ord < 32 or ch.ord == 127:
|
||||
result.add("\\x")
|
||||
result.add(hexDigits[ch.ord shr 4])
|
||||
result.add(hexDigits[ch.ord and 0xf])
|
||||
else:
|
||||
result.add(ch)
|
||||
result.add('\'')
|
||||
|
||||
proc ssoBytesLit(m: BModule; s: string; slen: int): string =
|
||||
## Compute the `bytes` field value for the new SmallString layout.
|
||||
## byte 0 = slen, bytes 1-7 = inline chars 0-6 (zero-padded).
|
||||
## On LE: slen in bits 0-7, char[i] in bits (i+1)*8..(i+1)*8+7.
|
||||
## On BE: slen in bits 56-63, char[i] in bits (6-i)*8..(6-i)*8+7.
|
||||
const AlwaysAvail = 7
|
||||
var val: uint64
|
||||
if CPU[m.g.config.target.targetCPU].endian == littleEndian:
|
||||
val = uint64(slen)
|
||||
for i in 0..<min(s.len, AlwaysAvail):
|
||||
val = val or (uint64(s[i]) shl (uint(i + 1) * 8))
|
||||
else:
|
||||
val = uint64(slen) shl 56
|
||||
for i in 0..<min(s.len, AlwaysAvail):
|
||||
val = val or (uint64(s[i]) shl (uint(AlwaysAvail - 1 - i) * 8))
|
||||
# Cast to NU (C name for Nim's uint, = NU64 on 64-bit). NU64 = uint64_t.
|
||||
result = cCast("NU", $val & "ULL")
|
||||
|
||||
proc ssoMoreLit(m: BModule; s: string): string =
|
||||
## For medium string literals (AlwaysAvail < len <= PayloadSize), encode
|
||||
## chars[AlwaysAvail..ptrSize-1] in the 'more' pointer field bit-pattern.
|
||||
## The last pointer byte is always '\0' (null terminator), guaranteed by
|
||||
## PayloadSize = AlwaysAvail + ptrSize - 1. slen <= PayloadSize guards
|
||||
## prevent any code from dereferencing this as an actual pointer.
|
||||
const AlwaysAvail = 7
|
||||
let ptrSize = m.g.config.target.ptrSize
|
||||
var val: uint64 = 0
|
||||
for i in 0..<ptrSize:
|
||||
let ch: uint64 = if AlwaysAvail + i < s.len: uint64(s[AlwaysAvail + i]) else: 0
|
||||
if CPU[m.g.config.target.targetCPU].endian == littleEndian:
|
||||
val = val or (ch shl (uint(i) * 8))
|
||||
else:
|
||||
val = val or (ch shl (uint(ptrSize - 1 - i) * 8))
|
||||
result = cCast(ptrType("LongString"), "(uintptr_t)" & $val)
|
||||
|
||||
proc genStringLiteralV3Const(m: BModule; n: PNode; isConst: bool; result: var Builder) =
|
||||
# Inline SmallString struct initializer for use inside const aggregate types.
|
||||
# Layout: {bytes: NimUint, more: ptr LongString}
|
||||
# bytes = slen (low byte) | char[0]<<8 | char[1]<<16 | ... | char[6]<<56
|
||||
const AlwaysAvail = 7
|
||||
let s = n.strVal
|
||||
|
||||
cgsym(m, "SmallString")
|
||||
cgsym(m, "LongString")
|
||||
|
||||
let payloadSize = AlwaysAvail + m.g.config.target.ptrSize - 1
|
||||
var si: StructInitializer
|
||||
result.addStructInitializer(si, kind = siOrderedStruct):
|
||||
if s.len <= AlwaysAvail:
|
||||
result.addField(si, name = "bytes"):
|
||||
result.add(ssoBytesLit(m, s, s.len))
|
||||
result.addField(si, name = "more"):
|
||||
result.add(NimNil)
|
||||
elif s.len <= payloadSize:
|
||||
# Medium string: bytes holds slen + chars 0-6; more holds chars 7..PayloadSize-1.
|
||||
result.addField(si, name = "bytes"):
|
||||
result.add(ssoBytesLit(m, s, s.len))
|
||||
result.addField(si, name = "more"):
|
||||
result.add(ssoMoreLit(m, s))
|
||||
else:
|
||||
# Emit the LongString block into cfsStrData and reference it inline.
|
||||
let dataName = getTempName(m)
|
||||
var res = newBuilder("")
|
||||
res.addVarWithTypeAndInitializer(
|
||||
if isConst: AlwaysConst else: Global,
|
||||
name = dataName):
|
||||
res.addSimpleStruct(m, name = "", baseType = ""):
|
||||
res.addField(name = "rc", typ = NimInt)
|
||||
res.addField(name = "fullLen", typ = NimInt)
|
||||
res.addField(name = "capImpl", typ = NimInt)
|
||||
res.addArrayField(name = "data", elementType = NimChar, len = s.len + 1)
|
||||
do:
|
||||
var di: StructInitializer
|
||||
res.addStructInitializer(di, kind = siOrderedStruct):
|
||||
res.addField(di, name = "fullLen"):
|
||||
res.addIntValue(s.len)
|
||||
res.addField(di, name = "rc"):
|
||||
res.addIntValue(1)
|
||||
res.addField(di, name = "capImpl"):
|
||||
res.addIntValue(0) # static, never freed
|
||||
res.addField(di, name = "data"):
|
||||
res.add(makeCString(s))
|
||||
m.s[cfsStrData].add(extract(res))
|
||||
# slen = StaticSlen (254): marks this as a static (never-freed) long string.
|
||||
result.addField(si, name = "bytes"):
|
||||
result.add(ssoBytesLit(m, s, 254))
|
||||
result.addField(si, name = "more"):
|
||||
result.add(cCast(ptrType("LongString"), cAddr(dataName)))
|
||||
|
||||
# ------ Version 3: SmallString (SSO) strings --------------------------------
|
||||
|
||||
proc genStringLiteralV3(m: BModule; n: PNode; isConst: bool; result: var Builder) =
|
||||
# SmallString literal. Always generate a fresh SmallString variable (like v2
|
||||
# always generates a fresh outer NimStringV2). For long strings, cache the
|
||||
# LongString payload to avoid duplicates within a module.
|
||||
const AlwaysAvail = 7 # must match strs_v3.nim
|
||||
let s = n.strVal
|
||||
let tmp = getTempName(m)
|
||||
result.add tmp
|
||||
|
||||
cgsym(m, "SmallString")
|
||||
cgsym(m, "LongString")
|
||||
|
||||
let payloadSize = AlwaysAvail + m.g.config.target.ptrSize - 1
|
||||
var res = newBuilder("")
|
||||
if s.len <= AlwaysAvail:
|
||||
# Short: bytes holds slen + all chars (zero-padded), more = NULL.
|
||||
res.addVarWithInitializer(
|
||||
if isConst: AlwaysConst else: Global,
|
||||
name = tmp, typ = "SmallString"):
|
||||
var si: StructInitializer
|
||||
res.addStructInitializer(si, kind = siOrderedStruct):
|
||||
res.addField(si, name = "bytes"):
|
||||
res.add(ssoBytesLit(m, s, s.len))
|
||||
res.addField(si, name = "more"):
|
||||
res.add(NimNil)
|
||||
elif s.len <= payloadSize:
|
||||
# Medium: bytes holds slen + chars 0-6; more holds chars 7..PayloadSize-1 as raw bits.
|
||||
res.addVarWithInitializer(
|
||||
if isConst: AlwaysConst else: Global,
|
||||
name = tmp, typ = "SmallString"):
|
||||
var si: StructInitializer
|
||||
res.addStructInitializer(si, kind = siOrderedStruct):
|
||||
res.addField(si, name = "bytes"):
|
||||
res.add(ssoBytesLit(m, s, s.len))
|
||||
res.addField(si, name = "more"):
|
||||
res.add(ssoMoreLit(m, s))
|
||||
else:
|
||||
# Long: cache the LongString block to emit it only once per module per string.
|
||||
# Always generate a fresh SmallString pointing at the (possibly cached) block.
|
||||
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
||||
var dataName: string
|
||||
if id == m.labels:
|
||||
dataName = getTempName(m)
|
||||
res.addVarWithTypeAndInitializer(
|
||||
if isConst: AlwaysConst else: Global,
|
||||
name = dataName):
|
||||
res.addSimpleStruct(m, name = "", baseType = ""):
|
||||
res.addField(name = "rc", typ = NimInt)
|
||||
res.addField(name = "fullLen", typ = NimInt)
|
||||
res.addField(name = "capImpl", typ = NimInt)
|
||||
res.addArrayField(name = "data", elementType = NimChar, len = s.len + 1)
|
||||
do:
|
||||
var di: StructInitializer
|
||||
res.addStructInitializer(di, kind = siOrderedStruct):
|
||||
res.addField(di, name = "fullLen"):
|
||||
res.addIntValue(s.len)
|
||||
res.addField(di, name = "rc"):
|
||||
res.addIntValue(1)
|
||||
res.addField(di, name = "capImpl"):
|
||||
res.addIntValue(0) # bit 0 = 0: static, never freed
|
||||
res.addField(di, name = "data"):
|
||||
res.add(makeCString(s))
|
||||
else:
|
||||
dataName = m.tmpBase & $id
|
||||
# slen = StaticSlen (254): marks this as a static (never-freed) long string.
|
||||
res.addVarWithInitializer(
|
||||
if isConst: AlwaysConst else: Global,
|
||||
name = tmp, typ = "SmallString"):
|
||||
var si: StructInitializer
|
||||
res.addStructInitializer(si, kind = siOrderedStruct):
|
||||
res.addField(si, name = "bytes"):
|
||||
res.add(ssoBytesLit(m, s, 254))
|
||||
res.addField(si, name = "more"):
|
||||
res.add(cCast(ptrType("LongString"), cAddr(dataName)))
|
||||
m.s[cfsStrData].add(extract(res))
|
||||
result.addf "{$1, (NimStrPayload*)&$2}", [rope(n.strVal.len), pureLit]
|
||||
|
||||
# ------ Version selector ---------------------------------------------------
|
||||
|
||||
@@ -328,18 +104,15 @@ proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
|
||||
let tmp = getTempName(m)
|
||||
genStringLiteralDataOnlyV2(m, s, tmp, isConst)
|
||||
result.add tmp
|
||||
of 3:
|
||||
localError(m.config, info, "genStringLiteralDataOnly not supported for SmallString (nimsso)")
|
||||
else:
|
||||
localError(m.config, info, "cannot determine how to produce code for string literal")
|
||||
|
||||
proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Builder) =
|
||||
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), NimNil))
|
||||
proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Rope) =
|
||||
appcg(m, result, "((#NimStringDesc*) NIM_NIL)", [])
|
||||
|
||||
proc genStringLiteral(m: BModule; n: PNode; result: var Builder) =
|
||||
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")
|
||||
|
||||
@@ -27,28 +27,25 @@ proc specializeResetN(p: BProc, accessor: Rope, n: PNode;
|
||||
if disc.loc.snippet == "": fillObjectFields(p.module, typ)
|
||||
if disc.loc.t == nil:
|
||||
internalError(p.config, n.info, "specializeResetN()")
|
||||
let discField = dotField(accessor, disc.loc.snippet)
|
||||
p.s(cpsStmts).addSwitchStmt(discField):
|
||||
for i in 1..<n.len:
|
||||
let branch = n[i]
|
||||
assert branch.kind in {nkOfBranch, nkElse}
|
||||
var caseBuilder: SwitchCaseBuilder
|
||||
p.s(cpsStmts).addSwitchCase(caseBuilder):
|
||||
if branch.kind == nkOfBranch:
|
||||
genCaseRange(p, branch, caseBuilder)
|
||||
else:
|
||||
p.s(cpsStmts).addCaseElse(caseBuilder)
|
||||
do:
|
||||
specializeResetN(p, accessor, lastSon(branch), typ)
|
||||
p.s(cpsStmts).addBreak()
|
||||
specializeResetT(p, discField, disc.loc.t)
|
||||
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.snippet])
|
||||
for i in 1..<n.len:
|
||||
let branch = n[i]
|
||||
assert branch.kind in {nkOfBranch, nkElse}
|
||||
if branch.kind == nkOfBranch:
|
||||
genCaseRange(p, branch)
|
||||
else:
|
||||
lineF(p, cpsStmts, "default:$n", [])
|
||||
specializeResetN(p, accessor, lastSon(branch), typ)
|
||||
lineF(p, cpsStmts, "break;$n", [])
|
||||
lineF(p, cpsStmts, "} $n", [])
|
||||
specializeResetT(p, "$1.$2" % [accessor, disc.loc.snippet], disc.loc.t)
|
||||
of nkSym:
|
||||
let field = n.sym
|
||||
if field.typ.kind == tyVoid: return
|
||||
if field.loc.snippet == "": fillObjectFields(p.module, typ)
|
||||
if field.loc.t == nil:
|
||||
internalError(p.config, n.info, "specializeResetN()")
|
||||
specializeResetT(p, dotField(accessor, field.loc.snippet), field.loc.t)
|
||||
specializeResetT(p, "$1.$2" % [accessor, field.loc.snippet], field.loc.t)
|
||||
else: internalError(p.config, n.info, "specializeResetN()")
|
||||
|
||||
proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
@@ -61,8 +58,10 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
of tyArray:
|
||||
let arraySize = lengthOrd(p.config, typ.indexType)
|
||||
var i: TLoc = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt))
|
||||
p.s(cpsStmts).addForRangeExclusive(i.snippet, cIntValue(0), cIntValue(arraySize)):
|
||||
specializeResetT(p, subscript(accessor, i.snippet), typ.elementType)
|
||||
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
|
||||
[i.snippet, arraySize])
|
||||
specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.snippet]), typ.elementType)
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
of tyObject:
|
||||
var x = typ.baseClass
|
||||
if x != nil: x = x.skipTypes(skipPtrs)
|
||||
@@ -70,42 +69,35 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
if typ.n != nil:
|
||||
if typ.sym != nil and sfImportc in typ.sym.flags:
|
||||
# imported C struct, nimZeroMem
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimZeroMem"),
|
||||
cCast(ptrType(CPointer), cAddr(accessor)),
|
||||
cSizeof(getTypeDesc(p.module, typ)))
|
||||
lineCg(p, cpsStmts, "#nimZeroMem((void**)&$1, sizeof($2));$n",
|
||||
[accessor, getTypeDesc(p.module, typ)])
|
||||
else:
|
||||
specializeResetN(p, accessor, typ.n, typ)
|
||||
of tyTuple:
|
||||
let typ = getUniqueType(typ)
|
||||
for i, a in typ.ikids:
|
||||
specializeResetT(p, dotField(accessor, "Field" & $i), a)
|
||||
specializeResetT(p, ropecg(p.module, "$1.Field$2", [accessor, i]), a)
|
||||
|
||||
of tyString, tyRef, tySequence:
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "unsureAsgnRef"),
|
||||
cCast(ptrType(CPointer), cAddr(accessor)),
|
||||
NimNil)
|
||||
lineCg(p, cpsStmts, "#unsureAsgnRef((void**)&$1, NIM_NIL);$n", [accessor])
|
||||
|
||||
of tyProc:
|
||||
if typ.callConv == ccClosure:
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "unsureAsgnRef"),
|
||||
cCast(ptrType(CPointer), cAddr(dotField(accessor, "ClE_0"))),
|
||||
NimNil)
|
||||
p.s(cpsStmts).addFieldAssignment(accessor, "ClP_0", NimNil)
|
||||
lineCg(p, cpsStmts, "#unsureAsgnRef((void**)&$1.ClE_0, NIM_NIL);$n", [accessor])
|
||||
lineCg(p, cpsStmts, "$1.ClP_0 = NIM_NIL;$n", [accessor])
|
||||
else:
|
||||
p.s(cpsStmts).addAssignment(accessor, NimNil)
|
||||
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
|
||||
of tyChar, tyBool, tyEnum, tyRange, tyInt..tyUInt64:
|
||||
p.s(cpsStmts).addAssignment(accessor, cIntValue(0))
|
||||
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
|
||||
of tyCstring, tyPointer, tyPtr, tyVar, tyLent:
|
||||
p.s(cpsStmts).addAssignment(accessor, NimNil)
|
||||
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
|
||||
of tySet:
|
||||
case mapSetType(p.config, typ)
|
||||
of ctArray:
|
||||
let t = getTypeDesc(p.module, typ)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimZeroMem"),
|
||||
accessor,
|
||||
cSizeof(t))
|
||||
lineCg(p, cpsStmts, "#nimZeroMem($1, sizeof($2));$n",
|
||||
[accessor, getTypeDesc(p.module, typ)])
|
||||
of ctInt8, ctInt16, ctInt32, ctInt64:
|
||||
p.s(cpsStmts).addAssignment(accessor, cIntValue(0))
|
||||
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
|
||||
else:
|
||||
raiseAssert "unexpected set type kind"
|
||||
of tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,12 +19,9 @@ proc accessThreadLocalVar(p: BProc, s: PSym) =
|
||||
if emulatedThreadVars(p.config) and threadVarAccessed notin p.flags:
|
||||
p.flags.incl threadVarAccessed
|
||||
incl p.module.flags, usesThreadVars
|
||||
p.procSec(cpsLocals).addVar(kind = Local,
|
||||
name = "NimTV_",
|
||||
typ = ptrType("NimThreadVars"))
|
||||
p.procSec(cpsInit).addAssignment("NimTV_",
|
||||
cCast(ptrType("NimThreadVars"),
|
||||
cCall(cgsymValue(p.module, "GetThreadLocalVars"))))
|
||||
p.procSec(cpsLocals).addf("\tNimThreadVars* NimTV_;$n", [])
|
||||
p.procSec(cpsInit).add(
|
||||
ropecg(p.module, "\tNimTV_ = (NimThreadVars*) #GetThreadLocalVars();$n", []))
|
||||
|
||||
proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
|
||||
if emulatedThreadVars(m.config):
|
||||
@@ -33,32 +30,30 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
|
||||
# allocator for it :-(
|
||||
if not containsOrIncl(m.g.nimtvDeclared, s.id):
|
||||
m.g.nimtvDeps.add(s.loc.t)
|
||||
m.g.nimtv.addField(name = s.loc.snippet, typ = getTypeDesc(m, s.loc.t))
|
||||
m.g.nimtv.addf("$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.snippet])
|
||||
else:
|
||||
let vis =
|
||||
if isExtern: Extern
|
||||
elif lfExportLib in s.loc.flags: ExportLibVar
|
||||
else: Private
|
||||
m.s[cfsVars].addVar(m, s,
|
||||
name = s.loc.snippet,
|
||||
typ = getTypeDesc(m, s.loc.t),
|
||||
kind = Threadvar,
|
||||
visibility = vis)
|
||||
if isExtern: m.s[cfsVars].add("extern ")
|
||||
elif lfExportLib in s.loc.flags: m.s[cfsVars].add("N_LIB_EXPORT_VAR ")
|
||||
else: m.s[cfsVars].add("N_LIB_PRIVATE ")
|
||||
if optThreads in m.config.globalOptions:
|
||||
let sym = s.typ.sym
|
||||
if sym != nil and sfCppNonPod in sym.flags:
|
||||
m.s[cfsVars].add("NIM_THREAD_LOCAL ")
|
||||
else: m.s[cfsVars].add("NIM_THREADVAR ")
|
||||
m.s[cfsVars].add(getTypeDesc(m, s.loc.t))
|
||||
m.s[cfsVars].addf(" $1;$n", [s.loc.snippet])
|
||||
|
||||
proc generateThreadLocalStorage(m: BModule) =
|
||||
if m.g.nimtv.buf.len != 0 and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
|
||||
if m.g.nimtv != "" and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
|
||||
for t in items(m.g.nimtvDeps): discard getTypeDesc(m, t)
|
||||
finishTypeDescriptions(m)
|
||||
m.s[cfsSeqTypes].addTypedef(name = "NimThreadVars"):
|
||||
m.s[cfsSeqTypes].addSimpleStruct(m, name = "", baseType = ""):
|
||||
m.s[cfsSeqTypes].add(extract(m.g.nimtv))
|
||||
m.s[cfsSeqTypes].addf("typedef struct {$1} NimThreadVars;$n", [m.g.nimtv])
|
||||
|
||||
proc generateThreadVarsSize(m: BModule) =
|
||||
if m.g.nimtv.buf.len != 0:
|
||||
if m.g.nimtv != "":
|
||||
let externc = if m.config.backend == backendCpp or
|
||||
sfCompileToCpp in m.module.flags: ExternC
|
||||
else: None
|
||||
m.s[cfsProcs].addDeclWithVisibility(externc):
|
||||
m.s[cfsProcs].addProcHeader("NimThreadVarsSize", NimInt, cProcParams())
|
||||
m.s[cfsProcs].finishProcHeaderWithBody():
|
||||
m.s[cfsProcs].addReturn(cCast(NimInt, cSizeof("NimThreadVars")))
|
||||
sfCompileToCpp in m.module.flags: "extern \"C\" "
|
||||
else: ""
|
||||
m.s[cfsProcs].addf(
|
||||
"$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n",
|
||||
[externc.rope])
|
||||
|
||||
@@ -16,16 +16,13 @@ type
|
||||
p: BProc
|
||||
visitorFrmt: string
|
||||
|
||||
const
|
||||
visitorFrmt = "#nimGCvisit((void*)$1, $2);$n"
|
||||
|
||||
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType)
|
||||
proc genCaseRange(p: BProc, branch: PNode, info: var SwitchCaseBuilder)
|
||||
proc genCaseRange(p: BProc, branch: PNode)
|
||||
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc
|
||||
|
||||
proc visit(p: BProc, data, visitor: Snippet) =
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimGCvisit"),
|
||||
cCast(CPointer, data),
|
||||
visitor)
|
||||
|
||||
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
|
||||
typ: PType) =
|
||||
if n == nil: return
|
||||
@@ -40,32 +37,29 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
|
||||
if disc.loc.snippet == "": fillObjectFields(c.p.module, typ)
|
||||
if disc.loc.t == nil:
|
||||
internalError(c.p.config, n.info, "genTraverseProc()")
|
||||
let discField = dotField(accessor, disc.loc.snippet)
|
||||
p.s(cpsStmts).addSwitchStmt(discField):
|
||||
for i in 1..<n.len:
|
||||
let branch = n[i]
|
||||
assert branch.kind in {nkOfBranch, nkElse}
|
||||
var caseBuilder: SwitchCaseBuilder
|
||||
p.s(cpsStmts).addSwitchCase(caseBuilder):
|
||||
if branch.kind == nkOfBranch:
|
||||
genCaseRange(c.p, branch, caseBuilder)
|
||||
else:
|
||||
p.s(cpsStmts).addCaseElse(caseBuilder)
|
||||
do:
|
||||
genTraverseProc(c, accessor, lastSon(branch), typ)
|
||||
p.s(cpsStmts).addBreak()
|
||||
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.snippet])
|
||||
for i in 1..<n.len:
|
||||
let branch = n[i]
|
||||
assert branch.kind in {nkOfBranch, nkElse}
|
||||
if branch.kind == nkOfBranch:
|
||||
genCaseRange(c.p, branch)
|
||||
else:
|
||||
lineF(p, cpsStmts, "default:$n", [])
|
||||
genTraverseProc(c, accessor, lastSon(branch), typ)
|
||||
lineF(p, cpsStmts, "break;$n", [])
|
||||
lineF(p, cpsStmts, "} $n", [])
|
||||
of nkSym:
|
||||
let field = n.sym
|
||||
if field.typ.kind == tyVoid: return
|
||||
if field.loc.snippet == "": fillObjectFields(c.p.module, typ)
|
||||
if field.loc.t == nil:
|
||||
internalError(c.p.config, n.info, "genTraverseProc()")
|
||||
genTraverseProc(c, dotField(accessor, field.loc.snippet), field.loc.t)
|
||||
genTraverseProc(c, "$1.$2" % [accessor, field.loc.snippet], field.loc.t)
|
||||
else: internalError(c.p.config, n.info, "genTraverseProc()")
|
||||
|
||||
proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
|
||||
if not m.compileToCpp:
|
||||
result = dotField(accessor, "Sup")
|
||||
result = "$1.Sup" % [accessor]
|
||||
else:
|
||||
result = accessor
|
||||
|
||||
@@ -82,14 +76,16 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
let arraySize = lengthOrd(c.p.config, typ.indexType)
|
||||
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
|
||||
var oldCode = p.s(cpsStmts)
|
||||
var oldLen, newLen: int
|
||||
p.s(cpsStmts).addForRangeExclusive(i.snippet, cIntValue(0), cIntValue(arraySize)):
|
||||
oldLen = p.s(cpsStmts).buf.len
|
||||
genTraverseProc(c, subscript(accessor, i.snippet), typ.elementType)
|
||||
newLen = p.s(cpsStmts).buf.len
|
||||
if oldLen == newLen:
|
||||
freeze oldCode
|
||||
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
|
||||
[i.snippet, arraySize])
|
||||
let oldLen = p.s(cpsStmts).len
|
||||
genTraverseProc(c, ropecg(c.p.module, "$1[$2]", [accessor, i.snippet]), typ.elementType)
|
||||
if p.s(cpsStmts).len == oldLen:
|
||||
# do not emit dummy long loops for faster debug builds:
|
||||
p.s(cpsStmts) = oldCode
|
||||
else:
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
of tyObject:
|
||||
var x = typ.baseClass
|
||||
if x != nil: x = x.skipTypes(skipPtrs)
|
||||
@@ -98,25 +94,23 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
of tyTuple:
|
||||
let typ = getUniqueType(typ)
|
||||
for i, a in typ.ikids:
|
||||
genTraverseProc(c, dotField(accessor, "Field" & $i), a)
|
||||
genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", [accessor, i]), a)
|
||||
of tyRef:
|
||||
visit(p, accessor, c.visitorFrmt)
|
||||
lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
|
||||
of tySequence:
|
||||
if optSeqDestructors notin c.p.module.config.globalOptions:
|
||||
visit(p, accessor, c.visitorFrmt)
|
||||
lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
|
||||
elif containsGarbageCollectedRef(typ.elementType):
|
||||
# destructor based seqs are themselves not traced but their data is, if
|
||||
# they contain a GC'ed type:
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimGCvisitSeq"),
|
||||
cCast(CPointer, accessor),
|
||||
c.visitorFrmt)
|
||||
lineCg(p, cpsStmts, "#nimGCvisitSeq((void*)$1, $2);$n", [accessor, c.visitorFrmt])
|
||||
#genTraverseProcSeq(c, accessor, typ)
|
||||
of tyString:
|
||||
if tfHasAsgn notin typ.flags:
|
||||
visit(p, accessor, c.visitorFrmt)
|
||||
lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
|
||||
of tyProc:
|
||||
if typ.callConv == ccClosure:
|
||||
visit(p, dotField(accessor, "ClE_0"), c.visitorFrmt)
|
||||
lineCg(p, cpsStmts, visitorFrmt, [ropecg(c.p.module, "$1.ClE_0", [accessor]), c.visitorFrmt])
|
||||
else:
|
||||
discard
|
||||
|
||||
@@ -125,17 +119,18 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
assert typ.kind == tySequence
|
||||
var i = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
|
||||
var oldCode = p.s(cpsStmts)
|
||||
var oldLen, newLen: int
|
||||
freeze oldCode
|
||||
var a = TLoc(snippet: accessor)
|
||||
let le = lenExpr(c.p, a)
|
||||
|
||||
p.s(cpsStmts).addForRangeExclusive(i.snippet, cIntValue(0), le):
|
||||
oldLen = p.s(cpsStmts).buf.len
|
||||
genTraverseProc(c, subscript(dataField(c.p, accessor), i.snippet), typ.elementType)
|
||||
newLen = p.s(cpsStmts).buf.len
|
||||
if newLen == oldLen:
|
||||
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
|
||||
[i.snippet, lenExpr(c.p, a)])
|
||||
let oldLen = p.s(cpsStmts).len
|
||||
genTraverseProc(c, "$1$3[$2]" % [accessor, i.snippet, dataField(c.p)], typ.elementType)
|
||||
if p.s(cpsStmts).len == oldLen:
|
||||
# do not emit dummy long loops for faster debug builds:
|
||||
p.s(cpsStmts) = oldCode
|
||||
else:
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
|
||||
proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
|
||||
var p = newProc(nil, m)
|
||||
@@ -144,10 +139,11 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
|
||||
hcrOn = m.hcrOn
|
||||
typ = origTyp.skipTypes(abstractInstOwned)
|
||||
markerName = if hcrOn: result & "_actual" else: result
|
||||
header = "static N_NIMCALL(void, $1)(void* p, NI op)" % [markerName]
|
||||
t = getTypeDesc(m, typ)
|
||||
|
||||
p.s(cpsLocals).addVar(kind = Local, name = "a", typ = t)
|
||||
p.s(cpsInit).addAssignment("a", cCast(t, "p"))
|
||||
lineF(p, cpsLocals, "$1 a;$n", [t])
|
||||
lineF(p, cpsInit, "a = ($1)p;$n", [t])
|
||||
|
||||
var c = TTraversalClosure(p: p,
|
||||
visitorFrmt: "op" # "#nimGCvisit((void*)$1, op);$n"
|
||||
@@ -161,40 +157,18 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
|
||||
# C's arrays are broken beyond repair:
|
||||
genTraverseProc(c, "a".rope, typ.elementType)
|
||||
else:
|
||||
genTraverseProc(c, cDeref("a"), typ.elementType)
|
||||
genTraverseProc(c, "(*a)".rope, typ.elementType)
|
||||
|
||||
var headerBuilder = newBuilder("")
|
||||
headerBuilder.addProcHeaderWithParams(ccNimCall, markerName, CVoid):
|
||||
var paramBuilder: ProcParamBuilder
|
||||
headerBuilder.addProcParams(paramBuilder):
|
||||
headerBuilder.addParam(paramBuilder, name = "p", typ = CPointer)
|
||||
headerBuilder.addParam(paramBuilder, name = "op", typ = NimInt)
|
||||
let header = extract(headerBuilder)
|
||||
let generatedProc = "$1 {$n$2$3$4}\n" %
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
|
||||
|
||||
m.s[cfsProcHeaders].addDeclWithVisibility(StaticProc):
|
||||
m.s[cfsProcHeaders].add(header)
|
||||
m.s[cfsProcHeaders].finishProcHeaderAsProto()
|
||||
m.s[cfsProcs].addDeclWithVisibility(StaticProc):
|
||||
m.s[cfsProcs].add(header)
|
||||
m.s[cfsProcs].finishProcHeaderWithBody():
|
||||
m.s[cfsProcs].add(extract(p.s(cpsLocals)))
|
||||
m.s[cfsProcs].add(extract(p.s(cpsInit)))
|
||||
m.s[cfsProcs].add(extract(p.s(cpsStmts)))
|
||||
m.s[cfsProcHeaders].addf("$1;\n", [header])
|
||||
m.s[cfsProcs].add(generatedProc)
|
||||
|
||||
if hcrOn:
|
||||
var desc = newBuilder("")
|
||||
var unnamedParamBuilder: ProcParamBuilder
|
||||
desc.addProcParams(unnamedParamBuilder):
|
||||
desc.addUnnamedParam(unnamedParamBuilder, CPointer)
|
||||
desc.addUnnamedParam(unnamedParamBuilder, NimInt)
|
||||
let unnamedParams = extract(desc)
|
||||
m.s[cfsProcHeaders].addProcVar(ccNimCall, result, unnamedParams, CVoid)
|
||||
m.s[cfsDynLibInit].addAssignmentWithValue(result):
|
||||
m.s[cfsDynLibInit].addCast(procPtrTypeUnnamed(ccNimCall, CVoid, unnamedParams)):
|
||||
m.s[cfsDynLibInit].addCall("hcrRegisterProc",
|
||||
getModuleDllPath(m),
|
||||
'"' & result & '"',
|
||||
cCast(CPointer, markerName))
|
||||
m.s[cfsProcHeaders].addf("N_NIMCALL_PTR(void, $1)(void*, NI);\n", [result])
|
||||
m.s[cfsDynLibInit].addf("\t$1 = (N_NIMCALL_PTR(void, )(void*, NI)) hcrRegisterProc($3, \"$1\", (void*)$2);\n",
|
||||
[result, markerName, getModuleDllPath(m)])
|
||||
|
||||
proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
|
||||
discard genTypeInfoV1(m, s.loc.t, info)
|
||||
@@ -205,28 +179,17 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
|
||||
|
||||
if sfThread in s.flags and emulatedThreadVars(m.config):
|
||||
accessThreadLocalVar(p, s)
|
||||
sLoc = derefField("NimTV_", sLoc)
|
||||
sLoc = "NimTV_->" & sLoc
|
||||
|
||||
var c = TTraversalClosure(p: p,
|
||||
visitorFrmt: cIntValue(0) # "#nimGCvisit((void*)$1, 0);$n"
|
||||
visitorFrmt: "0" # "#nimGCvisit((void*)$1, 0);$n"
|
||||
)
|
||||
|
||||
let header = "static N_NIMCALL(void, $1)(void)" % [result]
|
||||
genTraverseProc(c, sLoc, s.loc.t)
|
||||
|
||||
var headerBuilder = newBuilder("")
|
||||
headerBuilder.addProcHeaderWithParams(ccNimCall, result, CVoid):
|
||||
var paramBuilder: ProcParamBuilder
|
||||
headerBuilder.addProcParams(paramBuilder):
|
||||
# (void)
|
||||
discard
|
||||
let header = extract(headerBuilder)
|
||||
let generatedProc = "$1 {$n$2$3$4}$n" %
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
|
||||
|
||||
m.s[cfsProcHeaders].addDeclWithVisibility(StaticProc):
|
||||
m.s[cfsProcHeaders].add(header)
|
||||
m.s[cfsProcHeaders].finishProcHeaderAsProto()
|
||||
m.s[cfsProcs].addDeclWithVisibility(StaticProc):
|
||||
m.s[cfsProcs].add(header)
|
||||
m.s[cfsProcs].finishProcHeaderWithBody():
|
||||
m.s[cfsProcs].add(extract(p.s(cpsLocals)))
|
||||
m.s[cfsProcs].add(extract(p.s(cpsInit)))
|
||||
m.s[cfsProcs].add(extract(p.s(cpsStmts)))
|
||||
m.s[cfsProcHeaders].addf("$1;$n", [header])
|
||||
m.s[cfsProcs].add(generatedProc)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -90,6 +90,9 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
|
||||
if s.typ.sym != nil and sfForward in s.typ.sym.flags:
|
||||
# forwarded objects are *always* passed by pointers for consistency!
|
||||
result = true
|
||||
elif s.typ.kind == tySink and conf.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcHooks}:
|
||||
# bug #23354:
|
||||
result = false
|
||||
elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3):
|
||||
result = true # requested anyway
|
||||
elif (tfFinal in pt.flags) and (pt[0] == nil):
|
||||
|
||||
1626
compiler/cgen.nim
1626
compiler/cgen.nim
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
ast, ropes, options,
|
||||
lineinfos, pathutils, modulegraphs, cbuilderbase
|
||||
lineinfos, pathutils, modulegraphs
|
||||
|
||||
import std/[intsets, tables, sets]
|
||||
|
||||
@@ -43,12 +43,12 @@ type
|
||||
ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
|
||||
ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
|
||||
ctCString
|
||||
TCFileSections* = array[TCFileSection, Builder] # represents a generated C file
|
||||
TCFileSections* = array[TCFileSection, Rope] # represents a generated C file
|
||||
TCProcSection* = enum # the sections a generated C proc consists of
|
||||
cpsLocals, # section of local variables for C proc
|
||||
cpsInit, # section for init of variables for C proc
|
||||
cpsStmts # section of local statements for C proc
|
||||
TCProcSections* = array[TCProcSection, Builder] # represents a generated C proc
|
||||
TCProcSections* = array[TCProcSection, Rope] # represents a generated C proc
|
||||
BModule* = ref TCGen
|
||||
BProc* = ref TCProc
|
||||
TBlock* = object
|
||||
@@ -75,13 +75,10 @@ type
|
||||
flags*: set[TCProcFlag]
|
||||
lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements
|
||||
currLineInfo*: TLineInfo # AST codegen will make this superfluous
|
||||
nestedTryStmts*: seq[tuple[fin: PNode, inExcept: bool, isHidden: bool, label: Natural]]
|
||||
nestedTryStmts*: seq[tuple[fin: PNode, inExcept: bool, label: Natural]]
|
||||
# in how many nested try statements we are
|
||||
# (the vars must be volatile then)
|
||||
# `inExcept` is true when we are in the except part of a try block.
|
||||
# `isHidden` is true for compiler-injected `nkHiddenTryStmt` wrappers
|
||||
# (e.g. ARC's destructor try/finally around `except T as e:` bodies);
|
||||
# finallyActions walks past such wrappers to reach the user's try.
|
||||
# bool is true when are in the except part of a try block
|
||||
finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when
|
||||
# using return in finally statements
|
||||
labels*: Natural # for generating unique labels in the C proc
|
||||
@@ -118,11 +115,11 @@ type
|
||||
# computing alive data on our own.
|
||||
|
||||
BModuleList* = ref object of RootObj
|
||||
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Builder
|
||||
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
|
||||
mapping*: Rope # the generated mapping file (if requested)
|
||||
mods*: seq[BModule] # list of all compiled modules
|
||||
modules*: seq[BModule] # list of all compiled modules
|
||||
modulesClosed*: seq[BModule] # list of the same compiled modules, but in the order they were closed
|
||||
forwardedProcs*: seq[PSym] # procs that did not yet have a body
|
||||
forwardedProcs*: seq[PSym] # proc:s that did not yet have a body
|
||||
generatedHeader*: BModule
|
||||
typeInfoMarker*: TypeCacheWithOwner
|
||||
typeInfoMarkerV2*: TypeCacheWithOwner
|
||||
@@ -130,7 +127,7 @@ type
|
||||
graph*: ModuleGraph
|
||||
strVersion*, seqVersion*: int # version of the string/seq implementation to use
|
||||
|
||||
nimtv*: Builder # Nim thread vars; the struct body
|
||||
nimtv*: Rope # Nim thread vars; the struct body
|
||||
nimtvDeps*: seq[PType] # type deps: every module needs whole struct
|
||||
nimtvDeclared*: IntSet # so that every var/field exists only once
|
||||
# in the struct
|
||||
@@ -158,22 +155,20 @@ type
|
||||
forwTypeCache*: TypeCache # cache for forward declarations of types
|
||||
declaredThings*: IntSet # things we have declared in this .c file
|
||||
declaredProtos*: IntSet # prototypes we have declared in this .c file
|
||||
queue*: seq[PSym] # queue of procs to generate
|
||||
alive*: IntSet # symbol IDs of alive data as computed by `dce.nim`
|
||||
headerFiles*: seq[string] # needed headers to include
|
||||
typeInfoMarker*: TypeCache # needed for generating type information
|
||||
typeInfoMarkerV2*: TypeCache
|
||||
initProc*: BProc # code for init procedure
|
||||
preInitProc*: BProc # code executed before the init proc
|
||||
hcrCreateTypeInfosProc*: Builder # type info globals are in here when HCR=on
|
||||
hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on
|
||||
inHcrInitGuard*: bool # We are currently within a HCR reloading guard.
|
||||
hcrInitGuard*: IfBuilder
|
||||
typeStack*: TTypeSeq # used for type generation
|
||||
dataCache*: TNodeTable
|
||||
typeNodes*, nimTypes*: int # used for type info generation
|
||||
typeNodesName*, nimTypesName*: Rope # used for type info generation
|
||||
labels*: Natural # for generating unique module-scope names
|
||||
extensionLoaders*: array['0'..'9', Builder] # special procs for the
|
||||
extensionLoaders*: array['0'..'9', Rope] # special procs for the
|
||||
# OpenGL wrapper
|
||||
sigConflicts*: CountTable[SigHash]
|
||||
g*: BModuleList
|
||||
@@ -182,25 +177,22 @@ template config*(m: BModule): ConfigRef = m.g.config
|
||||
template config*(p: BProc): ConfigRef = p.module.g.config
|
||||
template vccAndC*(p: BProc): bool = p.module.config.cCompiler == ccVcc and p.module.config.backend == backendC
|
||||
|
||||
proc delayedCodegen*(m: BModule): bool {.inline.} =
|
||||
useAliveDataFromDce in m.flags or m.config.globalOptions.contains(optCompress)
|
||||
|
||||
proc includeHeader*(this: BModule; header: string) =
|
||||
if not this.headerFiles.contains header:
|
||||
this.headerFiles.add header
|
||||
|
||||
proc s*(p: BProc, s: TCProcSection): var Builder {.inline.} =
|
||||
proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
|
||||
# section in the current block
|
||||
result = p.blocks[^1].sections[s]
|
||||
|
||||
proc procSec*(p: BProc, s: TCProcSection): var Builder {.inline.} =
|
||||
proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
|
||||
# top level proc sections
|
||||
result = p.blocks[0].sections[s]
|
||||
|
||||
proc initBlock*(): TBlock =
|
||||
result = TBlock()
|
||||
for i in low(result.sections)..high(result.sections):
|
||||
result.sections[i] = newBuilder("")
|
||||
result.sections[i] = newRopeAppender()
|
||||
|
||||
proc newProc*(prc: PSym, module: BModule): BProc =
|
||||
result = BProc(
|
||||
|
||||
@@ -55,7 +55,7 @@ proc methodCall*(n: PNode; conf: ConfigRef): PNode =
|
||||
# replace ordinary method by dispatcher method:
|
||||
let disp = getDispatcher(result[0].sym)
|
||||
if disp != nil:
|
||||
result[0].typ = disp.typ
|
||||
result[0].typ() = disp.typ
|
||||
result[0].sym = disp
|
||||
# change the arguments to up/downcasts to fit the dispatcher's parameters:
|
||||
for i in 1..<result.len:
|
||||
@@ -123,8 +123,8 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) =
|
||||
|
||||
proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
|
||||
var disp = copySym(s, idgen)
|
||||
incl(disp, sfDispatcher)
|
||||
excl(disp, sfExported)
|
||||
incl(disp.flags, sfDispatcher)
|
||||
excl(disp.flags, sfExported)
|
||||
let old = disp.typ
|
||||
disp.typ = copyType(disp.typ, idgen, disp.typ.owner)
|
||||
copyTypeProps(g, idgen.module, disp.typ, old)
|
||||
@@ -133,7 +133,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
|
||||
if disp.typ.callConv == ccInline: disp.typ.callConv = ccNimCall
|
||||
disp.ast = copyTree(s.ast)
|
||||
disp.ast[bodyPos] = newNodeI(nkEmpty, s.info)
|
||||
disp.locImpl.snippet = ""
|
||||
disp.loc.snippet = ""
|
||||
if s.typ.returnType != nil:
|
||||
if disp.ast.len > resultPos:
|
||||
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, idgen)
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
|
||||
import
|
||||
ast, msgs, idents,
|
||||
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos, trees
|
||||
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos
|
||||
|
||||
import std/tables
|
||||
|
||||
@@ -199,7 +199,7 @@ proc newStateAssgn(ctx: var Ctx, toValue: PNode): PNode =
|
||||
proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
|
||||
result = newSym(skVar, getIdent(ctx.g.cache, name), ctx.idgen, ctx.fn, ctx.fn.info)
|
||||
result.typ = typ
|
||||
result.flagsImpl.incl sfNoInit
|
||||
result.flags.incl sfNoInit
|
||||
assert(not typ.isNil, "Env var needs a type")
|
||||
|
||||
let envParam = getEnvParam(ctx.fn)
|
||||
@@ -457,7 +457,7 @@ proc newNotCall(g: ModuleGraph; e: PNode): PNode =
|
||||
|
||||
proc boolLit(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
|
||||
result = newIntLit(g, info, ord value)
|
||||
result.typ = getSysType(g, info, tyBool)
|
||||
result.typ() = getSysType(g, info, tyBool)
|
||||
|
||||
proc captureVar(c: var Ctx, s: PSym) =
|
||||
if c.varStates.getOrDefault(s.itemId) != localRequiresLifting:
|
||||
@@ -727,7 +727,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||
n[0] = ex
|
||||
result.add(n)
|
||||
|
||||
of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkObjDownConv, nkObjUpConv,
|
||||
of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkObjDownConv,
|
||||
nkDerefExpr, nkHiddenDeref:
|
||||
var ns = false
|
||||
for i in ord(n.kind == nkCast)..<n.len:
|
||||
@@ -818,7 +818,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
let (st, ex) = exprToStmtList(n[1])
|
||||
n.transitionSonsKind(nkBlockStmt)
|
||||
n.typ = nil
|
||||
n.typ() = nil
|
||||
n[1] = st
|
||||
result.add(n)
|
||||
result.add(ex)
|
||||
@@ -1390,34 +1390,18 @@ proc optimizeStates(ctx: var Ctx) =
|
||||
for i in 0 .. ctx.states.high:
|
||||
ctx.states[i].label.intVal = i
|
||||
|
||||
proc detectCapturedSym(c: var Ctx, s: PSym, stateIdx: int) =
|
||||
if s.kind in {skResult, skVar, skLet, skForVar, skTemp} and sfGlobal notin s.flags and s.owner == c.fn and s != c.externExcSym:
|
||||
let vs = c.varStates.getOrDefault(s.itemId, localNotSeen)
|
||||
if vs == localNotSeen: # First seing this variable
|
||||
c.varStates[s.itemId] = stateIdx
|
||||
elif vs == localRequiresLifting:
|
||||
discard # Sym already marked
|
||||
elif vs != stateIdx:
|
||||
c.captureVar(s)
|
||||
|
||||
proc isClosureIterLocal(c: Ctx, s: PSym): bool =
|
||||
s.kind in {skResult, skVar, skLet, skForVar, skTemp} and
|
||||
sfGlobal notin s.flags and s.owner == c.fn and s != c.externExcSym
|
||||
|
||||
proc detectCapturedVars(c: var Ctx, n: PNode, stateIdx: int) =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
let s = n.sym
|
||||
detectCapturedSym(c, s, stateIdx)
|
||||
of nkAddr, nkHiddenAddr:
|
||||
let s = getRoot(n)
|
||||
if s != nil and isClosureIterLocal(c, s):
|
||||
detectCapturedSym(c, s, stateIdx)
|
||||
# bug #25596; lifetime extension for `addr`-taken locals as
|
||||
# we claim ARC/ORC do destruction based on scopes, not on last-usages.
|
||||
c.captureVar(s)
|
||||
for i in 0 ..< n.safeLen:
|
||||
detectCapturedVars(c, n[i], stateIdx)
|
||||
if s.kind in {skResult, skVar, skLet, skForVar, skTemp} and sfGlobal notin s.flags and s.owner == c.fn and s != c.externExcSym:
|
||||
let vs = c.varStates.getOrDefault(s.itemId, localNotSeen)
|
||||
if vs == localNotSeen: # First seing this variable
|
||||
c.varStates[s.itemId] = stateIdx
|
||||
elif vs == localRequiresLifting:
|
||||
discard # Sym already marked
|
||||
elif vs != stateIdx:
|
||||
c.captureVar(s)
|
||||
of nkReturnStmt:
|
||||
if n[0].kind in {nkAsgn, nkFastAsgn, nkSinkAsgn}:
|
||||
# we have a `result = result` expression produced by the closure
|
||||
|
||||
@@ -245,12 +245,11 @@ proc processCompile(conf: ConfigRef; filename: string) =
|
||||
extccomp.addExternalFileToCompile(conf, found)
|
||||
|
||||
const
|
||||
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'yrc', 'atomicArc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
|
||||
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'atomicArc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
|
||||
errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
|
||||
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console', 'lib' or 'staticlib' expected, but '$1' found"
|
||||
errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found"
|
||||
errInvalidFeatureButXFound = Feature.toSeq.map(proc(val:Feature): string = "'$1'" % $val).join(", ") & " expected, but '$1' found"
|
||||
errDefaultOrSsoExpectedButXFound = "'default' or 'sso' expected, but '$1' found"
|
||||
|
||||
template warningOptionNoop(switch: string) =
|
||||
warningDeprecated(conf, info, "'$#' is deprecated, now a noop" % switch)
|
||||
@@ -267,7 +266,6 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
|
||||
of "markandsweep": result = conf.selectedGC == gcMarkAndSweep
|
||||
of "destructors", "arc": result = conf.selectedGC == gcArc
|
||||
of "orc": result = conf.selectedGC == gcOrc
|
||||
of "yrc": result = conf.selectedGC == gcYrc
|
||||
of "hooks": result = conf.selectedGC == gcHooks
|
||||
of "go": result = conf.selectedGC == gcGo
|
||||
of "none": result = conf.selectedGC == gcNone
|
||||
@@ -307,13 +305,6 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
|
||||
else:
|
||||
result = false
|
||||
localError(conf, info, errInvalidExceptionSystem % arg)
|
||||
of "strings":
|
||||
case arg.normalize
|
||||
of "default": result = conf.selectedStrings == stringDefault
|
||||
of "sso": result = conf.selectedStrings == stringSso
|
||||
else:
|
||||
result = false
|
||||
localError(conf, info, errDefaultOrSsoExpectedButXFound % arg)
|
||||
of "experimental":
|
||||
try:
|
||||
result = conf.features.contains parseEnum[Feature](arg)
|
||||
@@ -483,7 +474,6 @@ proc parseCommand*(command: string): Command =
|
||||
of "cpp", "compiletocpp": cmdCompileToCpp
|
||||
of "objc", "compiletooc": cmdCompileToOC
|
||||
of "js", "compiletojs": cmdCompileToJS
|
||||
of "nif": cmdCompileToNif
|
||||
of "r": cmdCrun
|
||||
of "m": cmdM
|
||||
of "run": cmdTcc
|
||||
@@ -503,11 +493,10 @@ proc parseCommand*(command: string): Command =
|
||||
of "gendepend": cmdGendepend
|
||||
of "dump": cmdDump
|
||||
of "parse": cmdParse
|
||||
of "rod": cmdRod
|
||||
of "secret": cmdInteractive
|
||||
of "nop", "help": cmdNop
|
||||
of "jsonscript": cmdJsonscript
|
||||
of "nifc": cmdNifC # generate C from NIF files
|
||||
of "ic": cmdIc # generate .build.nif for nifmake
|
||||
else: cmdUnknown
|
||||
|
||||
proc setCmd*(conf: ConfigRef, cmd: Command) =
|
||||
@@ -519,12 +508,6 @@ proc setCmd*(conf: ConfigRef, cmd: Command) =
|
||||
of cmdCompileToCpp: conf.backend = backendCpp
|
||||
of cmdCompileToOC: conf.backend = backendObjc
|
||||
of cmdCompileToJS: conf.backend = backendJs
|
||||
of cmdCompileToNif: conf.backend = backendNif
|
||||
of cmdNifC:
|
||||
conf.backend = backendC # NIF to C compilation
|
||||
of cmdM:
|
||||
# cmdM requires optCompress for proper IC handling (include files, etc.)
|
||||
conf.globalOptions.incl optCompress
|
||||
else: discard
|
||||
|
||||
proc setCommandEarly*(conf: ConfigRef, command: string) =
|
||||
@@ -579,7 +562,6 @@ proc unregisterArcOrc*(conf: ConfigRef) =
|
||||
undefSymbol(conf.symbols, "gcdestructors")
|
||||
undefSymbol(conf.symbols, "gcarc")
|
||||
undefSymbol(conf.symbols, "gcorc")
|
||||
undefSymbol(conf.symbols, "gcyrc")
|
||||
undefSymbol(conf.symbols, "gcatomicarc")
|
||||
undefSymbol(conf.symbols, "nimSeqsV2")
|
||||
undefSymbol(conf.symbols, "nimV2")
|
||||
@@ -613,10 +595,6 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
|
||||
conf.selectedGC = gcOrc
|
||||
defineSymbol(conf.symbols, "gcorc")
|
||||
registerArcOrc(pass, conf)
|
||||
of "yrc":
|
||||
conf.selectedGC = gcYrc
|
||||
defineSymbol(conf.symbols, "gcyrc")
|
||||
registerArcOrc(pass, conf)
|
||||
of "atomicarc":
|
||||
conf.selectedGC = gcAtomicArc
|
||||
defineSymbol(conf.symbols, "gcatomicarc")
|
||||
@@ -758,17 +736,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
processMemoryManagementOption(switch, arg, pass, info, conf)
|
||||
of "mm":
|
||||
processMemoryManagementOption(switch, arg, pass, info, conf)
|
||||
of "strings":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}:
|
||||
case arg.normalize
|
||||
of "default":
|
||||
conf.selectedStrings = stringDefault
|
||||
of "sso":
|
||||
conf.selectedStrings = stringSso
|
||||
defineSymbol(conf.symbols, "nimsso")
|
||||
else:
|
||||
localError(conf, info, errDefaultOrSsoExpectedButXFound % arg)
|
||||
of "warnings", "w":
|
||||
if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf)
|
||||
of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf)
|
||||
@@ -802,8 +769,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
conf.globalOptions.incl optItaniumMangle
|
||||
else:
|
||||
localError(conf, info, "expected nim|cpp but found " & arg)
|
||||
of "compress":
|
||||
conf.globalOptions.incl optCompress
|
||||
of "g": # alias for --debugger:native
|
||||
conf.globalOptions.incl optCDebug
|
||||
conf.options.incl optLineDir
|
||||
@@ -930,7 +895,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
if m.len == 0:
|
||||
localError(conf, info, "Cannot resolve filename: " & arg)
|
||||
else:
|
||||
conf.implicitImports.add(if arg.startsWith(stdPrefix): arg else: m)
|
||||
conf.implicitImports.add m
|
||||
of "include":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}:
|
||||
@@ -970,7 +935,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
var value: int = 10_000_000
|
||||
discard parseSaturatedNatural(arg, value)
|
||||
if value <= 0: localError(conf, info, "maxLoopIterationsVM must be a positive integer greater than zero")
|
||||
if not value > 0: localError(conf, info, "maxLoopIterationsVM must be a positive integer greater than zero")
|
||||
conf.maxLoopIterationsVM = value
|
||||
of "maxcalldepthvm":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
@@ -1024,8 +989,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
# xxx maybe also ic, since not in help?
|
||||
if pass in {passCmd2, passPP}:
|
||||
case arg.normalize
|
||||
of "on": conf.ic = true
|
||||
of "legacy": conf.symbolFiles = v2Sf
|
||||
of "on": conf.symbolFiles = v2Sf
|
||||
of "off": conf.symbolFiles = disabledSf
|
||||
of "writeonly": conf.symbolFiles = writeOnlySf
|
||||
of "readonly": conf.symbolFiles = readOnlySf
|
||||
|
||||
@@ -29,7 +29,7 @@ proc declareSelf(c: PContext; info: TLineInfo) =
|
||||
let ow = getCurrOwner(c)
|
||||
let s = newSym(skType, getIdent(c.cache, "Self"), c.idgen, ow, info)
|
||||
s.typ = newType(tyTypeDesc, c.idgen, ow)
|
||||
s.typ.incl {tfUnresolved, tfPacked}
|
||||
s.typ.flags.incl {tfUnresolved, tfPacked}
|
||||
s.typ.add newType(tyEmpty, c.idgen, ow)
|
||||
addDecl(c, s, info)
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasEnsureMove")
|
||||
defineSymbol("nimHasNoReturnError")
|
||||
|
||||
defineSymbol("nimUseStrictDefs") # deadcode
|
||||
defineSymbol("nimUseStrictDefs")
|
||||
defineSymbol("nimHasNolineTooLong")
|
||||
|
||||
defineSymbol("nimHasCastExtendedVm")
|
||||
@@ -172,8 +172,7 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasDefaultFloatRoundtrip")
|
||||
defineSymbol("nimHasXorSet")
|
||||
|
||||
defineSymbol("nimHasSetLengthSeqUninitMagic")
|
||||
defineSymbol("nimHasPreviewDuplicateModuleError")
|
||||
defineSymbol("nimHasSetLengthSeqUninitMagic")
|
||||
|
||||
defineSymbol("nimHasImplicitRangeConversion")
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
## Generate a .build.nif file for nifmake from a Nim project.
|
||||
## This enables incremental and parallel compilation using the `m` switch.
|
||||
|
||||
import std / [os, tables, sets, times, osproc]
|
||||
import options, msgs, lineinfos, pathutils
|
||||
import std / [os, tables, sets, times, osproc, strutils]
|
||||
import options, msgs, lineinfos
|
||||
|
||||
import "../dist/nimony/src/lib" / [nifstreams, bitabs, nifreader, nifbuilder]
|
||||
import "../dist/nimony/src/lib" / [nifstreams, nifcursors, bitabs, nifreader, nifbuilder]
|
||||
import "../dist/nimony/src/gear2" / modnames
|
||||
|
||||
type
|
||||
@@ -32,7 +32,6 @@ type
|
||||
nodes: seq[Node]
|
||||
processedModules: Table[string, int] # modname -> node index
|
||||
includeStack: seq[string]
|
||||
systemNodeId: int # ID of the system.nim node
|
||||
|
||||
proc toPair(c: DepContext; f: string): FilePair =
|
||||
FilePair(nimFile: f, modname: moduleSuffix(f, cast[seq[string]](c.config.searchPaths)))
|
||||
@@ -48,18 +47,15 @@ proc semmedFile(c: DepContext; f: FilePair): string =
|
||||
|
||||
proc findNifler(): string =
|
||||
# Look for nifler in common locations
|
||||
let nimDir = getAppDir()
|
||||
result = nimDir / "nifler"
|
||||
if not fileExists(result):
|
||||
result = findExe("nifler")
|
||||
|
||||
proc findNifmake(): string =
|
||||
# Look for nifmake in common locations
|
||||
# Try relative to nim executable
|
||||
let nimDir = getAppDir()
|
||||
result = nimDir / "nifmake"
|
||||
if not fileExists(result):
|
||||
result = findExe("nifmake")
|
||||
result = findExe("nifler")
|
||||
if result.len == 0:
|
||||
# Try relative to nim executable
|
||||
let nimDir = getAppDir()
|
||||
result = nimDir / "nifler"
|
||||
if not fileExists(result):
|
||||
result = nimDir / ".." / "nimony" / "bin" / "nifler"
|
||||
if not fileExists(result):
|
||||
result = ""
|
||||
|
||||
proc runNifler(c: DepContext; nimFile: string): bool =
|
||||
## Run nifler deps on a file if needed. Returns true on success.
|
||||
@@ -79,19 +75,22 @@ proc runNifler(c: DepContext; nimFile: string): bool =
|
||||
let exitCode = execShellCmd(cmd)
|
||||
result = exitCode == 0
|
||||
|
||||
proc resolveImport(c: DepContext; origin, toResolve: string): string =
|
||||
## Resolve an import path using the compiler's normal module lookup rules.
|
||||
result = findModule(c.config, toResolve, origin).string
|
||||
proc resolveFile(c: DepContext; origin, toResolve: string): string =
|
||||
## Resolve an import path relative to origin file
|
||||
# Handle std/ prefix
|
||||
var path = toResolve
|
||||
if path.startsWith("std/"):
|
||||
path = path.substr(4)
|
||||
|
||||
proc resolveInclude(c: DepContext; origin, toResolve: string): string =
|
||||
## Resolve an include path relative to the including file or the search paths.
|
||||
# Try relative to origin first
|
||||
let originDir = parentDir(origin)
|
||||
result = originDir / toResolve.addFileExt("nim")
|
||||
result = originDir / path.addFileExt("nim")
|
||||
if fileExists(result):
|
||||
return result
|
||||
|
||||
# Try search paths
|
||||
for searchPath in c.config.searchPaths:
|
||||
result = searchPath.string / toResolve.addFileExt("nim")
|
||||
result = searchPath.string / path.addFileExt("nim")
|
||||
if fileExists(result):
|
||||
return result
|
||||
|
||||
@@ -100,7 +99,7 @@ proc resolveInclude(c: DepContext; origin, toResolve: string): string =
|
||||
proc traverseDeps(c: var DepContext; pair: FilePair; current: Node)
|
||||
|
||||
proc processInclude(c: var DepContext; includePath: string; current: Node) =
|
||||
let resolved = resolveInclude(c, current.files[current.files.len - 1].nimFile, includePath)
|
||||
let resolved = resolveFile(c, current.files[current.files.len - 1].nimFile, includePath)
|
||||
if resolved.len == 0 or not fileExists(resolved):
|
||||
return
|
||||
|
||||
@@ -115,7 +114,7 @@ proc processInclude(c: var DepContext; includePath: string; current: Node) =
|
||||
discard c.includeStack.pop()
|
||||
|
||||
proc processImport(c: var DepContext; importPath: string; current: Node) =
|
||||
let resolved = resolveImport(c, current.files[0].nimFile, importPath)
|
||||
let resolved = resolveFile(c, current.files[0].nimFile, importPath)
|
||||
if resolved.len == 0 or not fileExists(resolved):
|
||||
return
|
||||
|
||||
@@ -126,9 +125,6 @@ proc processImport(c: var DepContext; importPath: string; current: Node) =
|
||||
# New module - create node and process it
|
||||
let newNode = Node(files: @[pair], id: c.nodes.len)
|
||||
current.deps.add newNode.id
|
||||
# Every module depends on system.nim
|
||||
if c.systemNodeId >= 0:
|
||||
newNode.deps.add c.systemNodeId
|
||||
c.processedModules[pair.modname] = newNode.id
|
||||
c.nodes.add newNode
|
||||
traverseDeps(c, pair, newNode)
|
||||
@@ -137,171 +133,6 @@ proc processImport(c: var DepContext; importPath: string; current: Node) =
|
||||
if existingIdx notin current.deps:
|
||||
current.deps.add existingIdx
|
||||
|
||||
proc skipSubtree(s: var Stream; first: PackedToken) =
|
||||
## Consume tokens until the ParLe at `first` is balanced. Caller has
|
||||
## already obtained `first`.
|
||||
if first.kind != ParLe: return
|
||||
var depth = 1
|
||||
while depth > 0:
|
||||
let t = next(s)
|
||||
if t.kind == ParLe: inc depth
|
||||
elif t.kind == ParRi: dec depth
|
||||
elif t.kind == EofToken: return
|
||||
|
||||
proc evalCondExpr(c: DepContext; s: var Stream): bool =
|
||||
## Read exactly one condition expression from `s` and return its truth
|
||||
## value. Consumes tokens whether the expression is recognised or not so
|
||||
## the caller stays in sync. Recognises `defined(IDENT)`, the boolean
|
||||
## operators `not`/`and`/`or`, and the literals `true`/`false`. Anything
|
||||
## else (e.g. a call to an arbitrary proc) is treated as `true` — the
|
||||
## conservative direction, since a false negative here drops a real
|
||||
## dependency from the build graph.
|
||||
let t = next(s)
|
||||
case t.kind
|
||||
of Ident:
|
||||
case pool.strings[t.litId]
|
||||
of "true": result = true
|
||||
of "false": result = false
|
||||
else: result = true
|
||||
of ParLe:
|
||||
let tag = pool.tags[t.tagId]
|
||||
case tag
|
||||
of "call", "cmd", "callstrlit", "infix", "prefix":
|
||||
# First child is the head (function/operator name).
|
||||
let head = next(s)
|
||||
var name = ""
|
||||
if head.kind == Ident: name = pool.strings[head.litId]
|
||||
case name
|
||||
of "defined":
|
||||
let arg = next(s)
|
||||
var sym = ""
|
||||
if arg.kind == Ident: sym = pool.strings[arg.litId]
|
||||
result = sym.len > 0 and isDefined(c.config, sym)
|
||||
of "not":
|
||||
result = not evalCondExpr(c, s)
|
||||
of "and":
|
||||
result = evalCondExpr(c, s)
|
||||
if result: result = evalCondExpr(c, s)
|
||||
else: skipSubtree(s, next(s))
|
||||
of "or":
|
||||
result = evalCondExpr(c, s)
|
||||
if not result: result = evalCondExpr(c, s)
|
||||
else: skipSubtree(s, next(s))
|
||||
else:
|
||||
result = true
|
||||
# Drain whatever remains until the matching ParRi.
|
||||
var depth = 1
|
||||
while depth > 0:
|
||||
let n = next(s)
|
||||
if n.kind == ParLe: inc depth
|
||||
elif n.kind == ParRi: dec depth
|
||||
elif n.kind == EofToken: return
|
||||
of "not":
|
||||
result = not evalCondExpr(c, s)
|
||||
var depth = 1
|
||||
while depth > 0:
|
||||
let n = next(s)
|
||||
if n.kind == ParLe: inc depth
|
||||
elif n.kind == ParRi: dec depth
|
||||
elif n.kind == EofToken: return
|
||||
of "and":
|
||||
result = evalCondExpr(c, s)
|
||||
if result: result = evalCondExpr(c, s)
|
||||
else: skipSubtree(s, next(s))
|
||||
# consume closing ParRi
|
||||
var depth = 1
|
||||
while depth > 0:
|
||||
let n = next(s)
|
||||
if n.kind == ParLe: inc depth
|
||||
elif n.kind == ParRi: dec depth
|
||||
elif n.kind == EofToken: return
|
||||
of "or":
|
||||
result = evalCondExpr(c, s)
|
||||
if not result: result = evalCondExpr(c, s)
|
||||
else: skipSubtree(s, next(s))
|
||||
var depth = 1
|
||||
while depth > 0:
|
||||
let n = next(s)
|
||||
if n.kind == ParLe: inc depth
|
||||
elif n.kind == ParRi: dec depth
|
||||
elif n.kind == EofToken: return
|
||||
else:
|
||||
skipSubtree(s, t)
|
||||
result = true
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc whenMarkerHolds(c: DepContext; s: var Stream): bool =
|
||||
## Caller has just consumed the `(when` ParLe. Read children until the
|
||||
## matching `)`, AND-ing each evaluated condition.
|
||||
result = true
|
||||
while true:
|
||||
# peek by reading; if it's ParRi, we're done
|
||||
let t = next(s)
|
||||
if t.kind == ParRi: return
|
||||
if t.kind == EofToken: return
|
||||
if t.kind == ParLe:
|
||||
# Re-feed by manually evaluating the subtree starting at `t`.
|
||||
# evalCondExpr expects to read its own opener, so handle it directly.
|
||||
let tag = pool.tags[t.tagId]
|
||||
case tag
|
||||
of "call", "cmd", "callstrlit", "infix", "prefix":
|
||||
let head = next(s)
|
||||
var name = ""
|
||||
if head.kind == Ident: name = pool.strings[head.litId]
|
||||
var ok = true
|
||||
case name
|
||||
of "defined":
|
||||
let arg = next(s)
|
||||
var sym = ""
|
||||
if arg.kind == Ident: sym = pool.strings[arg.litId]
|
||||
ok = sym.len > 0 and isDefined(c.config, sym)
|
||||
of "not":
|
||||
ok = not evalCondExpr(c, s)
|
||||
of "and":
|
||||
ok = evalCondExpr(c, s)
|
||||
if ok: ok = evalCondExpr(c, s)
|
||||
of "or":
|
||||
ok = evalCondExpr(c, s)
|
||||
if not ok: ok = evalCondExpr(c, s)
|
||||
else:
|
||||
ok = true
|
||||
# finish the subtree
|
||||
var depth = 1
|
||||
while depth > 0:
|
||||
let n = next(s)
|
||||
if n.kind == ParLe: inc depth
|
||||
elif n.kind == ParRi: dec depth
|
||||
elif n.kind == EofToken: return
|
||||
if not ok: result = false
|
||||
of "not", "and", "or":
|
||||
# Re-emit a synthetic dispatch: rewrap by descending.
|
||||
var ok = true
|
||||
case tag
|
||||
of "not":
|
||||
ok = not evalCondExpr(c, s)
|
||||
of "and":
|
||||
ok = evalCondExpr(c, s)
|
||||
if ok: ok = evalCondExpr(c, s)
|
||||
of "or":
|
||||
ok = evalCondExpr(c, s)
|
||||
if not ok: ok = evalCondExpr(c, s)
|
||||
else: discard
|
||||
var depth = 1
|
||||
while depth > 0:
|
||||
let n = next(s)
|
||||
if n.kind == ParLe: inc depth
|
||||
elif n.kind == ParRi: dec depth
|
||||
elif n.kind == EofToken: return
|
||||
if not ok: result = false
|
||||
else:
|
||||
# Unknown — treat as true and skip.
|
||||
skipSubtree(s, t)
|
||||
elif t.kind == Ident:
|
||||
let v = pool.strings[t.litId]
|
||||
if v == "false": result = false
|
||||
# else (true / unknown ident): keep result
|
||||
|
||||
proc readDepsFile(c: var DepContext; pair: FilePair; current: Node) =
|
||||
## Read a .deps.nif file and process imports/includes
|
||||
let depsPath = c.depsFile(pair)
|
||||
@@ -323,27 +154,12 @@ proc readDepsFile(c: var DepContext; pair: FilePair; current: Node) =
|
||||
if t.kind == ParLe:
|
||||
let tag = pool.tags[t.tagId]
|
||||
case tag
|
||||
of "import", "fromimport", "include":
|
||||
# Read first child. May be a `(when COND...)` marker — parse and
|
||||
# evaluate; if the condition is statically false, skip the import
|
||||
# entirely. Otherwise advance past the marker and parse the path.
|
||||
of "import", "fromimport":
|
||||
# Read import path
|
||||
t = next(s)
|
||||
var live = true
|
||||
if t.kind == ParLe and pool.tags[t.tagId] == "when":
|
||||
# whenMarkerHolds consumes everything up to and including the
|
||||
# closing `)` of the `(when ...)` subtree.
|
||||
live = whenMarkerHolds(c, s)
|
||||
t = next(s)
|
||||
if not live:
|
||||
# Drain the rest of this import/include node.
|
||||
var depth = 1
|
||||
while depth > 0:
|
||||
let n = next(s)
|
||||
if n.kind == ParLe: inc depth
|
||||
elif n.kind == ParRi: dec depth
|
||||
elif n.kind == EofToken: break
|
||||
t = next(s)
|
||||
continue
|
||||
# Check for "when" marker (conditional import)
|
||||
if t.kind == Ident and pool.strings[t.litId] == "when":
|
||||
t = next(s) # skip it, still process the import
|
||||
# Handle path expression (could be ident, string, or infix like std/foo)
|
||||
var importPath = ""
|
||||
if t.kind == Ident:
|
||||
@@ -361,11 +177,26 @@ proc readDepsFile(c: var DepContext; pair: FilePair; current: Node) =
|
||||
if t.kind == Ident: # second part (foo)
|
||||
importPath = importPath & "/" & pool.strings[t.litId]
|
||||
if importPath.len > 0:
|
||||
if tag == "include":
|
||||
processInclude(c, importPath, current)
|
||||
else:
|
||||
processImport(c, importPath, current)
|
||||
# Skip to end of node
|
||||
processImport(c, importPath, current)
|
||||
# Skip to end of import node
|
||||
var depth = 1
|
||||
while depth > 0:
|
||||
t = next(s)
|
||||
if t.kind == ParLe: inc depth
|
||||
elif t.kind == ParRi: dec depth
|
||||
of "include":
|
||||
# Read include path
|
||||
t = next(s)
|
||||
if t.kind == Ident and pool.strings[t.litId] == "when":
|
||||
t = next(s) # skip conditional marker
|
||||
var includePath = ""
|
||||
if t.kind == Ident:
|
||||
includePath = pool.strings[t.litId]
|
||||
elif t.kind == StringLit:
|
||||
includePath = pool.strings[t.litId]
|
||||
if includePath.len > 0:
|
||||
processInclude(c, includePath, current)
|
||||
# Skip to end
|
||||
var depth = 1
|
||||
while depth > 0:
|
||||
t = next(s)
|
||||
@@ -389,14 +220,12 @@ proc traverseDeps(c: var DepContext; pair: FilePair; current: Node) =
|
||||
|
||||
proc generateBuildFile(c: DepContext): string =
|
||||
## Generate the .build.nif file for nifmake
|
||||
let nimcache = getNimcacheDir(c.config).string
|
||||
createDir(nimcache)
|
||||
result = nimcache / c.nodes[0].files[0].modname & ".build.nif"
|
||||
result = getNimcacheDir(c.config).string / c.nodes[0].files[0].modname & ".build.nif"
|
||||
|
||||
var b = nifbuilder.open(result)
|
||||
defer: b.close()
|
||||
|
||||
b.addHeader("nim ic", "nifmake")
|
||||
b.addHeader("nim deps", "nifmake")
|
||||
b.addTree "stmts"
|
||||
|
||||
# Define nifler command
|
||||
@@ -416,22 +245,6 @@ proc generateBuildFile(c: DepContext): string =
|
||||
b.addSymbolDef "nim_m"
|
||||
b.addStrLit getAppFilename()
|
||||
b.addStrLit "m"
|
||||
b.addStrLit "--nimcache:" & nimcache
|
||||
# Add search paths
|
||||
for p in c.config.searchPaths:
|
||||
b.addStrLit "--path:" & p.string
|
||||
b.addTree "args"
|
||||
b.endTree()
|
||||
b.withTree "input":
|
||||
b.addIntLit 0 # main parsed file
|
||||
b.endTree()
|
||||
|
||||
# Define nim nifc command
|
||||
b.addTree "cmd"
|
||||
b.addSymbolDef "nim_nifc"
|
||||
b.addStrLit getAppFilename()
|
||||
b.addStrLit "nifc"
|
||||
b.addStrLit "--nimcache:" & nimcache
|
||||
# Add search paths
|
||||
for p in c.config.searchPaths:
|
||||
b.addStrLit "--path:" & p.string
|
||||
@@ -466,8 +279,6 @@ proc generateBuildFile(c: DepContext): string =
|
||||
b.addTree "do"
|
||||
b.addIdent "nim_m"
|
||||
# Input: all parsed files for this module
|
||||
b.withTree "input":
|
||||
b.addStrLit node.files[0].nimFile
|
||||
for f in node.files:
|
||||
b.addTree "input"
|
||||
b.addStrLit c.parsedFile(f)
|
||||
@@ -481,35 +292,15 @@ proc generateBuildFile(c: DepContext): string =
|
||||
b.addTree "output"
|
||||
b.addStrLit c.semmedFile(pair)
|
||||
b.endTree()
|
||||
b.addTree "args"
|
||||
b.addStrLit pair.nimFile
|
||||
b.endTree()
|
||||
|
||||
# Final compilation step: generate executable from main module
|
||||
let mainNif = c.nodes[0].files[0].nimFile
|
||||
let exeFile = changeFileExt(c.nodes[0].files[0].nimFile, ExeExt)
|
||||
b.addTree "do"
|
||||
b.addIdent "nim_nifc"
|
||||
# Input: .nim file (expanded as argument)
|
||||
b.addTree "input"
|
||||
b.addStrLit mainNif
|
||||
b.endTree()
|
||||
# Also depend on the semmed .nif files of the main module and all its
|
||||
# dependencies. nifmake's topological sort orders nodes by depth; without
|
||||
# these inputs the nim_nifc node sits at depth 1 (no recognized inputs)
|
||||
# alongside the nifler nodes and runs *before* the nim_m steps that
|
||||
# produce the .nif files it needs to read.
|
||||
for node in c.nodes:
|
||||
b.addTree "input"
|
||||
b.addStrLit c.semmedFile(node.files[0])
|
||||
b.endTree()
|
||||
b.addTree "output"
|
||||
b.addStrLit exeFile
|
||||
b.endTree()
|
||||
b.endTree()
|
||||
|
||||
b.endTree() # stmts
|
||||
|
||||
proc commandIc*(conf: ConfigRef) =
|
||||
## Main entry point for `nim ic`
|
||||
proc commandDeps*(conf: ConfigRef) =
|
||||
## Main entry point for `nim deps`
|
||||
when not defined(nimKochBootstrap):
|
||||
let nifler = findNifler()
|
||||
if nifler.len == 0:
|
||||
@@ -529,8 +320,7 @@ proc commandIc*(conf: ConfigRef) =
|
||||
nifler: nifler,
|
||||
nodes: @[],
|
||||
processedModules: initTable[string, int](),
|
||||
includeStack: @[],
|
||||
systemNodeId: -1
|
||||
includeStack: @[]
|
||||
)
|
||||
|
||||
# Create root node for main project file
|
||||
@@ -539,28 +329,12 @@ proc commandIc*(conf: ConfigRef) =
|
||||
c.nodes.add rootNode
|
||||
c.processedModules[rootPair.modname] = 0
|
||||
|
||||
# model the system.nim dependency:
|
||||
let sysNode = Node(files: @[toPair(c, (conf.libpath / RelativeFile"system.nim").string)], id: 1)
|
||||
c.nodes.add sysNode
|
||||
c.systemNodeId = sysNode.id
|
||||
rootNode.deps.add sysNode.id
|
||||
|
||||
# Process dependencies
|
||||
traverseDeps(c, rootPair, rootNode)
|
||||
|
||||
# Generate build file
|
||||
let buildFile = generateBuildFile(c)
|
||||
rawMessage(conf, hintSuccess, "generated: " & buildFile)
|
||||
|
||||
# Automatically run nifmake
|
||||
let nifmake = findNifmake()
|
||||
if nifmake.len == 0:
|
||||
rawMessage(conf, hintSuccess, "run: nifmake run " & buildFile)
|
||||
else:
|
||||
let cmd = quoteShell(nifmake) & " run " & quoteShell(buildFile)
|
||||
rawMessage(conf, hintExecuting, cmd)
|
||||
let exitCode = execShellCmd(cmd)
|
||||
if exitCode != 0:
|
||||
rawMessage(conf, errGenerated, "nifmake failed with exit code: " & $exitCode)
|
||||
rawMessage(conf, hintSuccess, "run: nifmake run " & buildFile)
|
||||
else:
|
||||
rawMessage(conf, errGenerated, "nim ic not available in bootstrap build")
|
||||
rawMessage(conf, errGenerated, "nim deps not available in bootstrap build")
|
||||
|
||||
@@ -483,7 +483,7 @@ proc constructCfg*(s: PSym; body: PNode; root: PSym): ControlFlowGraph =
|
||||
gen(c, body)
|
||||
if root.kind == skResult:
|
||||
genImplicitReturn(c)
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc) or defined(gcYrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
result = c.code # will move
|
||||
else:
|
||||
shallowCopy(result, c.code)
|
||||
|
||||
@@ -19,7 +19,7 @@ import
|
||||
wordrecg, syntaxes, renderer, lexer,
|
||||
packages/docutils/[rst, rstidx, rstgen, dochelpers],
|
||||
trees, types,
|
||||
typesrenderer, lineinfos,
|
||||
typesrenderer, astalgo, lineinfos,
|
||||
pathutils, nimpaths, renderverbatim, packages
|
||||
import packages/docutils/rstast except FileIndex, TLineInfo
|
||||
|
||||
@@ -148,7 +148,7 @@ proc cmpDecimalsIgnoreCase(a, b: string): int =
|
||||
limitB = iB
|
||||
while limitA < aLen and isDigit(a[limitA]): inc limitA
|
||||
while limitB < bLen and isDigit(b[limitB]): inc limitB
|
||||
var pos = max(limitA-iA, limitB-iB)
|
||||
var pos = max(limitA-iA, limitB-iA)
|
||||
while pos > 0:
|
||||
if limitA-pos < iA: # digit in `a` is 0 effectively
|
||||
result = ord('0') - ord(b[limitB-pos])
|
||||
@@ -540,11 +540,10 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string;
|
||||
elif s != nil and s.kind in {skType, skVar, skLet, skConst} and
|
||||
sfExported in s.flags and s.owner != nil and
|
||||
belongsToProjectPackage(d.conf, s.owner) and d.target == outHtml:
|
||||
let href = (if d.module == s.owner: ""
|
||||
else: externalDep(d, s.owner).changeFileExt("html")
|
||||
) & "#" & literal
|
||||
result.addf "<a href=\"$1\"><span class=\"Identifier\">$2</span></a>",
|
||||
[href, escLit]
|
||||
let external = externalDep(d, s.owner)
|
||||
result.addf "<a href=\"$1#$2\"><span class=\"Identifier\">$3</span></a>",
|
||||
[changeFileExt(external, "html"), literal,
|
||||
escLit]
|
||||
else:
|
||||
dispA(d.conf, result, "<span class=\"Identifier\">$1</span>",
|
||||
"\\spanIdentifier{$1}", [escLit])
|
||||
@@ -1328,7 +1327,7 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id
|
||||
if t.startsWith("ref "): t = substr(t, 4)
|
||||
effects[i] = newIdentNode(getIdent(cache, t), n.info)
|
||||
# set the type so that the following analysis doesn't screw up:
|
||||
effects[i].typ = real[i].typ
|
||||
effects[i].typ() = real[i].typ
|
||||
|
||||
result = newTreeI(nkExprColonExpr, n.info,
|
||||
newIdentNode(getIdent(cache, $effectType), n.info), effects)
|
||||
|
||||
@@ -47,7 +47,8 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGener
|
||||
n[bodyPos] = body
|
||||
n[resultPos] = newSymNode(res)
|
||||
result.ast = n
|
||||
incl result.flagsImpl, {sfFromGeneric, sfNeverRaises}
|
||||
incl result.flags, sfFromGeneric
|
||||
incl result.flags, sfNeverRaises
|
||||
|
||||
proc searchObjCaseImpl(obj: PNode; field: PSym): PNode =
|
||||
case obj.kind
|
||||
@@ -109,4 +110,5 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra
|
||||
n[bodyPos] = body
|
||||
n[resultPos] = newSymNode(res)
|
||||
result.ast = n
|
||||
incl result.flagsImpl, {sfFromGeneric, sfNeverRaises}
|
||||
incl result.flags, sfFromGeneric
|
||||
incl result.flags, sfNeverRaises
|
||||
|
||||
@@ -275,7 +275,7 @@ proc unpackObject(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
# the nkPar node:
|
||||
if n.isNil:
|
||||
result = newNode(nkTupleConstr)
|
||||
result.typ = typ
|
||||
result.typ() = typ
|
||||
if typ.n.isNil:
|
||||
internalError(conf, "cannot unpack unnamed tuple")
|
||||
unpackObjectAdd(conf, x, typ.n, result)
|
||||
@@ -298,7 +298,7 @@ proc unpackObject(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
proc unpackArray(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
if n.isNil:
|
||||
result = newNode(nkBracket)
|
||||
result.typ = typ
|
||||
result.typ() = typ
|
||||
newSeq(result.sons, lengthOrd(conf, typ).toInt)
|
||||
else:
|
||||
result = n
|
||||
@@ -319,7 +319,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
template aw(k, v, field: untyped): untyped =
|
||||
if n.isNil:
|
||||
result = newNode(k)
|
||||
result.typ = typ
|
||||
result.typ() = typ
|
||||
else:
|
||||
# check we have the right field:
|
||||
result = n
|
||||
@@ -333,12 +333,12 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
template setNil() =
|
||||
if n.isNil:
|
||||
result = newNode(nkNilLit)
|
||||
result.typ = typ
|
||||
result.typ() = typ
|
||||
else:
|
||||
reset n[]
|
||||
result = n
|
||||
result[] = TNode(kind: nkNilLit)
|
||||
result.typ = typ
|
||||
result.typ() = typ
|
||||
|
||||
template awi(kind, v: untyped): untyped = aw(kind, v, intVal)
|
||||
template awf(kind, v: untyped): untyped = aw(kind, v, floatVal)
|
||||
@@ -427,7 +427,7 @@ proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode =
|
||||
# cast through a pointer needs a new inner object:
|
||||
let y = if x.kind == nkRefTy: newNodeI(nkRefTy, x.info, 1)
|
||||
else: x.copyTree
|
||||
y.typ = x.typ
|
||||
y.typ() = x.typ
|
||||
result = unpack(conf, a, destTyp, y)
|
||||
dealloc a
|
||||
|
||||
@@ -481,7 +481,7 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
|
||||
if aTyp.isNil:
|
||||
internalAssert conf, i+1 < fntyp.len
|
||||
aTyp = fntyp[i+1]
|
||||
args[i+start].typ = aTyp
|
||||
args[i+start].typ() = aTyp
|
||||
sig[i] = mapType(conf, aTyp)
|
||||
if sig[i].isNil: globalError(conf, info, "cannot map FFI type")
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
|
||||
d.add newSymNode(sym, info)
|
||||
result.add d
|
||||
result.add res
|
||||
result.typ = res.typ
|
||||
result.typ() = res.typ
|
||||
|
||||
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
|
||||
conf: ConfigRef;
|
||||
|
||||
@@ -341,7 +341,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, backendNif: discard
|
||||
of backendC: discard
|
||||
of backendInvalid:
|
||||
# during parsing of cfg files; we don't know the backend yet, no point in
|
||||
# guessing wrong thing
|
||||
|
||||
@@ -1104,7 +1104,7 @@ proc settype(n: PNode): PType =
|
||||
|
||||
proc buildOf(it, loc: PNode; o: Operators): PNode =
|
||||
var s = newNodeI(nkCurly, it.info, it.len-1)
|
||||
s.typ = settype(loc)
|
||||
s.typ() = settype(loc)
|
||||
for i in 0..<it.len-1: s[i] = it[i]
|
||||
result = newNodeI(nkCall, it.info, 3)
|
||||
result[0] = newSymNode(o.opContains)
|
||||
@@ -1170,7 +1170,7 @@ proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode =
|
||||
# set field name to discriminator field name
|
||||
a[1] = check[2]
|
||||
# set discriminator field type: important for `neg`
|
||||
a.typ = check[2].typ
|
||||
a.typ() = check[2].typ
|
||||
result[2] = a
|
||||
# 'access.kind != nkDotExpr' can happen for object constructors
|
||||
# which we don't check yet
|
||||
|
||||
178
compiler/ic/bitabs.nim
Normal file
178
compiler/ic/bitabs.nim
Normal file
@@ -0,0 +1,178 @@
|
||||
## A BiTable is a table that can be seen as an optimized pair
|
||||
## of `(Table[LitId, Val], Table[Val, LitId])`.
|
||||
|
||||
import std/hashes
|
||||
import rodfiles
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
type
|
||||
LitId* = distinct uint32
|
||||
|
||||
BiTable*[T] = object
|
||||
vals: seq[T] # indexed by LitId
|
||||
keys: seq[LitId] # indexed by hash(val)
|
||||
|
||||
proc initBiTable*[T](): BiTable[T] = BiTable[T](vals: @[], keys: @[])
|
||||
|
||||
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
|
||||
result = (h + 1) and maxHash
|
||||
|
||||
template maxHash(t): untyped = high(t.keys)
|
||||
template isFilled(x: LitId): bool = x.uint32 > 0'u32
|
||||
|
||||
proc `$`*(x: LitId): string {.borrow.}
|
||||
proc `<`*(x, y: LitId): bool {.borrow.}
|
||||
proc `<=`*(x, y: LitId): bool {.borrow.}
|
||||
proc `==`*(x, y: LitId): bool {.borrow.}
|
||||
proc hash*(x: LitId): Hash {.borrow.}
|
||||
|
||||
|
||||
proc len*[T](t: BiTable[T]): int = t.vals.len
|
||||
|
||||
proc mustRehash(length, counter: int): bool {.inline.} =
|
||||
assert(length > counter)
|
||||
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||
|
||||
const
|
||||
idStart = 1
|
||||
|
||||
template idToIdx(x: LitId): int = x.int - idStart
|
||||
|
||||
proc hasLitId*[T](t: BiTable[T]; x: LitId): bool =
|
||||
let idx = idToIdx(x)
|
||||
result = idx >= 0 and idx < t.vals.len
|
||||
|
||||
proc enlarge[T](t: var BiTable[T]) =
|
||||
var n: seq[LitId]
|
||||
newSeq(n, len(t.keys) * 2)
|
||||
swap(t.keys, n)
|
||||
for i in 0..high(n):
|
||||
let eh = n[i]
|
||||
if isFilled(eh):
|
||||
var j = hash(t.vals[idToIdx eh]) and maxHash(t)
|
||||
while isFilled(t.keys[j]):
|
||||
j = nextTry(j, maxHash(t))
|
||||
t.keys[j] = move n[i]
|
||||
|
||||
proc getKeyId*[T](t: BiTable[T]; v: T): LitId =
|
||||
let origH = hash(v)
|
||||
var h = origH and maxHash(t)
|
||||
if t.keys.len != 0:
|
||||
while true:
|
||||
let litId = t.keys[h]
|
||||
if not isFilled(litId): break
|
||||
if t.vals[idToIdx t.keys[h]] == v: return litId
|
||||
h = nextTry(h, maxHash(t))
|
||||
return LitId(0)
|
||||
|
||||
proc getOrIncl*[T](t: var BiTable[T]; v: T): LitId =
|
||||
let origH = hash(v)
|
||||
var h = origH and maxHash(t)
|
||||
if t.keys.len != 0:
|
||||
while true:
|
||||
let litId = t.keys[h]
|
||||
if not isFilled(litId): break
|
||||
if t.vals[idToIdx t.keys[h]] == v: return litId
|
||||
h = nextTry(h, maxHash(t))
|
||||
# not found, we need to insert it:
|
||||
if mustRehash(t.keys.len, t.vals.len):
|
||||
enlarge(t)
|
||||
# recompute where to insert:
|
||||
h = origH and maxHash(t)
|
||||
while true:
|
||||
let litId = t.keys[h]
|
||||
if not isFilled(litId): break
|
||||
h = nextTry(h, maxHash(t))
|
||||
else:
|
||||
setLen(t.keys, 16)
|
||||
h = origH and maxHash(t)
|
||||
|
||||
result = LitId(t.vals.len + idStart)
|
||||
t.keys[h] = result
|
||||
t.vals.add v
|
||||
|
||||
|
||||
proc `[]`*[T](t: var BiTable[T]; litId: LitId): var T {.inline.} =
|
||||
let idx = idToIdx litId
|
||||
assert idx < t.vals.len
|
||||
result = t.vals[idx]
|
||||
|
||||
proc `[]`*[T](t: BiTable[T]; litId: LitId): lent T {.inline.} =
|
||||
let idx = idToIdx litId
|
||||
assert idx < t.vals.len
|
||||
result = t.vals[idx]
|
||||
|
||||
proc hash*[T](t: BiTable[T]): Hash =
|
||||
## as the keys are hashes of the values, we simply use them instead
|
||||
var h: Hash = 0
|
||||
for i, n in pairs t.keys:
|
||||
h = h !& hash((i, n))
|
||||
result = !$h
|
||||
|
||||
proc store*[T](f: var RodFile; t: BiTable[T]) =
|
||||
storeSeq(f, t.vals)
|
||||
storeSeq(f, t.keys)
|
||||
|
||||
proc load*[T](f: var RodFile; t: var BiTable[T]) =
|
||||
loadSeq(f, t.vals)
|
||||
loadSeq(f, t.keys)
|
||||
|
||||
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]
|
||||
|
||||
echo getOrIncl(t, "hello")
|
||||
|
||||
echo getOrIncl(t, "hello")
|
||||
echo getOrIncl(t, "hello3")
|
||||
echo getOrIncl(t, "hello4")
|
||||
echo getOrIncl(t, "helloasfasdfdsa")
|
||||
echo getOrIncl(t, "hello")
|
||||
echo getKeyId(t, "hello")
|
||||
echo getKeyId(t, "none")
|
||||
|
||||
for i in 0 ..< 100_000:
|
||||
discard t.getOrIncl($i & "___" & $i)
|
||||
|
||||
for i in 0 ..< 100_000:
|
||||
assert t.getOrIncl($i & "___" & $i).idToIdx == i + 4
|
||||
echo "begin"
|
||||
echo t.vals.len
|
||||
|
||||
echo t.vals[0]
|
||||
echo t.vals[1004]
|
||||
|
||||
echo "middle"
|
||||
|
||||
var tf: BiTable[float]
|
||||
|
||||
discard tf.getOrIncl(0.4)
|
||||
discard tf.getOrIncl(16.4)
|
||||
discard tf.getOrIncl(32.4)
|
||||
echo getKeyId(tf, 32.4)
|
||||
|
||||
var f2 = open("testblah.bin", fmWrite)
|
||||
echo store(f2, tf)
|
||||
f2.close
|
||||
|
||||
var f1 = open("testblah.bin", fmRead)
|
||||
|
||||
var t2: BiTable[float]
|
||||
|
||||
echo f1.load(t2)
|
||||
echo t2.vals.len
|
||||
|
||||
echo getKeyId(t2, 32.4)
|
||||
|
||||
echo "end"
|
||||
|
||||
|
||||
f1.close
|
||||
180
compiler/ic/cbackend.nim
Normal file
180
compiler/ic/cbackend.nim
Normal file
@@ -0,0 +1,180 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2021 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## New entry point into our C/C++ code generator. Ideally
|
||||
## somebody would rewrite the old backend (which is 8000 lines of crufty Nim code)
|
||||
## to work on packed trees directly and produce the C code as an AST which can
|
||||
## then be rendered to text in a very simple manner. Unfortunately nobody wrote
|
||||
## this code. So instead we wrap the existing cgen.nim and its friends so that
|
||||
## we call directly into the existing code generation logic but avoiding the
|
||||
## naive, outdated `passes` design. Thus you will see some
|
||||
## `useAliveDataFromDce in flags` checks in the old code -- the old code is
|
||||
## also doing cross-module dependency tracking and DCE that we don't need
|
||||
## anymore. DCE is now done as prepass over the entire packed module graph.
|
||||
|
||||
import std/[packedsets, algorithm, tables]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
import ".."/[ast, options, lineinfos, modulegraphs, cgendata, cgen,
|
||||
pathutils, extccomp, msgs, modulepaths]
|
||||
|
||||
import packed_ast, ic, dce, rodfiles
|
||||
|
||||
proc unpackTree(g: ModuleGraph; thisModule: int;
|
||||
tree: PackedTree; n: NodePos): PNode =
|
||||
var decoder = initPackedDecoder(g.config, g.cache)
|
||||
result = loadNodes(decoder, g.packed, thisModule, tree, n)
|
||||
|
||||
proc setupBackendModule(g: ModuleGraph; m: var LoadedModule) =
|
||||
if g.backend == nil:
|
||||
g.backend = cgendata.newModuleList(g)
|
||||
assert g.backend != nil
|
||||
var bmod = cgen.newModule(BModuleList(g.backend), m.module, g.config)
|
||||
bmod.idgen = idgenFromLoadedModule(m)
|
||||
|
||||
proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var AliveSyms) =
|
||||
var bmod = BModuleList(g.backend).modules[m.module.position]
|
||||
assert bmod != nil
|
||||
bmod.flags.incl useAliveDataFromDce
|
||||
bmod.alive = move alive[m.module.position]
|
||||
|
||||
for p in allNodes(m.fromDisk.topLevel):
|
||||
let n = unpackTree(g, m.module.position, m.fromDisk.topLevel, p)
|
||||
cgen.genTopLevelStmt(bmod, n)
|
||||
|
||||
finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
|
||||
for disp in getDispatchers(g):
|
||||
genProcAux(bmod, disp)
|
||||
m.fromDisk.backendFlags = cgen.whichInitProcs(bmod)
|
||||
|
||||
proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) =
|
||||
for x in mitems(m.fromDisk.emittedTypeInfo):
|
||||
#echo "found type ", x, " for file ", int(origin)
|
||||
g.emittedTypeInfo[x] = origin
|
||||
|
||||
proc addFileToLink(config: ConfigRef; m: PSym) =
|
||||
let filename = AbsoluteFile toFullPath(config, m.position.FileIndex)
|
||||
let ext =
|
||||
if config.backend == backendCpp: ".nim.cpp"
|
||||
elif config.backend == backendObjc: ".nim.m"
|
||||
else: ".nim.c"
|
||||
let cfile = changeFileExt(completeCfilePath(config,
|
||||
mangleModuleName(config, filename).AbsoluteFile), ext)
|
||||
let objFile = completeCfilePath(config, toObjFile(config, cfile))
|
||||
if fileExists(objFile):
|
||||
var cf = Cfile(nimname: m.name.s, cname: cfile,
|
||||
obj: objFile,
|
||||
flags: {CfileFlag.Cached})
|
||||
addFileToCompile(config, cf)
|
||||
|
||||
when defined(debugDce):
|
||||
import os, std/packedsets
|
||||
|
||||
proc storeAliveSymsImpl(asymFile: AbsoluteFile; s: seq[int32]) =
|
||||
var f = rodfiles.create(asymFile.string)
|
||||
f.storeHeader()
|
||||
f.storeSection aliveSymsSection
|
||||
f.storeSeq(s)
|
||||
close f
|
||||
|
||||
template prepare {.dirty.} =
|
||||
let asymFile = toRodFile(config, AbsoluteFile toFullPath(config, position.FileIndex), ".alivesyms")
|
||||
var s = newSeqOfCap[int32](alive[position].len)
|
||||
for a in items(alive[position]): s.add int32(a)
|
||||
sort(s)
|
||||
|
||||
proc storeAliveSyms(config: ConfigRef; position: int; alive: AliveSyms) =
|
||||
prepare()
|
||||
storeAliveSymsImpl(asymFile, s)
|
||||
|
||||
proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool =
|
||||
prepare()
|
||||
var f2 = rodfiles.open(asymFile.string)
|
||||
f2.loadHeader()
|
||||
f2.loadSection aliveSymsSection
|
||||
var oldData: seq[int32] = @[]
|
||||
f2.loadSeq(oldData)
|
||||
f2.close
|
||||
if f2.err == ok and oldData == s:
|
||||
result = false
|
||||
else:
|
||||
when defined(debugDce):
|
||||
let oldAsSet = toPackedSet[int32](oldData)
|
||||
let newAsSet = toPackedSet[int32](s)
|
||||
echo "set of live symbols changed ", asymFile.changeFileExt("rod"), " ", position, " ", f2.err
|
||||
echo "in old but not in new ", oldAsSet.difference(newAsSet), " number of entries in old ", oldAsSet.len
|
||||
echo "in new but not in old ", newAsSet.difference(oldAsSet), " number of entries in new ", newAsSet.len
|
||||
#if execShellCmd(getAppFilename() & " rod " & quoteShell(asymFile.changeFileExt("rod"))) != 0:
|
||||
# echo "command failed"
|
||||
result = true
|
||||
storeAliveSymsImpl(asymFile, s)
|
||||
|
||||
proc genPackedModule(g: ModuleGraph, i: int; alive: var AliveSyms) =
|
||||
# case statement here to enforce exhaustive checks.
|
||||
case g.packed[i].status
|
||||
of undefined:
|
||||
discard "nothing to do"
|
||||
of loading, stored:
|
||||
assert false
|
||||
of storing, outdated:
|
||||
storeAliveSyms(g.config, g.packed[i].module.position, alive)
|
||||
generateCodeForModule(g, g.packed[i], alive)
|
||||
closeRodFile(g, g.packed[i].module)
|
||||
of loaded:
|
||||
if g.packed[i].loadedButAliveSetChanged:
|
||||
generateCodeForModule(g, g.packed[i], alive)
|
||||
else:
|
||||
addFileToLink(g.config, g.packed[i].module)
|
||||
replayTypeInfo(g, g.packed[i], FileIndex(i))
|
||||
|
||||
if g.backend == nil:
|
||||
g.backend = cgendata.newModuleList(g)
|
||||
registerInitProcs(BModuleList(g.backend), g.packed[i].module, g.packed[i].fromDisk.backendFlags)
|
||||
|
||||
proc generateCode*(g: ModuleGraph) =
|
||||
## The single entry point, generate C(++) code for the entire
|
||||
## Nim program aka `ModuleGraph`.
|
||||
resetForBackend(g)
|
||||
var alive = computeAliveSyms(g.packed, g.config)
|
||||
|
||||
when false:
|
||||
for i in 0..<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..<len(g.packed):
|
||||
# case statement here to enforce exhaustive checks.
|
||||
case g.packed[i].status
|
||||
of undefined:
|
||||
discard "nothing to do"
|
||||
of loading, stored:
|
||||
assert false
|
||||
of storing, outdated:
|
||||
setupBackendModule(g, g.packed[i])
|
||||
of loaded:
|
||||
# Even though this module didn't change, DCE might trigger a change.
|
||||
# Consider this case: Module A uses symbol S from B and B does not use
|
||||
# S itself. A is then edited not to use S either. Thus we have to
|
||||
# recompile B in order to remove S from the final result.
|
||||
if aliveSymsChanged(g.config, g.packed[i].module.position, alive):
|
||||
g.packed[i].loadedButAliveSetChanged = true
|
||||
setupBackendModule(g, g.packed[i])
|
||||
|
||||
# Second pass: Code generation.
|
||||
let mainModuleIdx = g.config.projectMainIdx2.int
|
||||
# We need to generate the main module last, because only then
|
||||
# all init procs have been registered:
|
||||
for i in 0..<len(g.packed):
|
||||
if i != mainModuleIdx:
|
||||
genPackedModule(g, i, alive)
|
||||
if mainModuleIdx >= 0:
|
||||
genPackedModule(g, mainModuleIdx, alive)
|
||||
169
compiler/ic/dce.nim
Normal file
169
compiler/ic/dce.nim
Normal file
@@ -0,0 +1,169 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2021 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Dead code elimination (=DCE) for IC.
|
||||
|
||||
import std/[intsets, tables]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
import ".." / [ast, options, lineinfos, types]
|
||||
|
||||
import packed_ast, ic, bitabs
|
||||
|
||||
type
|
||||
AliveSyms* = seq[IntSet]
|
||||
AliveContext* = object ## Purpose is to fill the 'alive' field.
|
||||
stack: seq[(int, TOptions, NodePos)] ## A stack for marking symbols as alive.
|
||||
decoder: PackedDecoder ## We need a PackedDecoder for module ID address translations.
|
||||
thisModule: int ## The module we're currently analysing for DCE.
|
||||
alive: AliveSyms ## The final result of our computation.
|
||||
options: TOptions
|
||||
compilerProcs: Table[string, (int, int32)]
|
||||
|
||||
proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): bool =
|
||||
## "Exported to C" procs are special (these are marked with '.exportc') because these
|
||||
## must not be optimized away!
|
||||
let symPtr = unsafeAddr g[c.thisModule].fromDisk.syms[symId]
|
||||
let flags = symPtr.flags
|
||||
# due to a bug/limitation in the lambda lifting, unused inner procs
|
||||
# are not transformed correctly; issue (#411). However, the whole purpose here
|
||||
# is to eliminate unused procs. So there is no special logic required for this case.
|
||||
if sfCompileTime notin flags:
|
||||
if ({sfExportc, sfCompilerProc} * flags != {}) or
|
||||
(symPtr.kind == skMethod):
|
||||
result = true
|
||||
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
|
||||
|
||||
proc followLater(c: var AliveContext; g: PackedModuleGraph; module: int; item: int32) =
|
||||
## Marks a symbol 'item' as used and later in 'followNow' the symbol's body will
|
||||
## be analysed.
|
||||
if not c.alive[module].containsOrIncl(item):
|
||||
var body = g[module].fromDisk.syms[item].ast
|
||||
if body != emptyNodeId:
|
||||
let opt = g[module].fromDisk.syms[item].options
|
||||
if g[module].fromDisk.syms[item].kind in routineKinds:
|
||||
body = NodeId ithSon(g[module].fromDisk.bodies, NodePos body, bodyPos)
|
||||
c.stack.add((module, opt, NodePos(body)))
|
||||
|
||||
when false:
|
||||
let nid = g[module].fromDisk.syms[item].name
|
||||
if nid != LitId(0):
|
||||
let name = g[module].fromDisk.strings[nid]
|
||||
if name in ["nimFrame", "callDepthLimitReached"]:
|
||||
echo "I was called! ", name, " body exists: ", body != emptyNodeId, " ", module, " ", item
|
||||
|
||||
proc requestCompilerProc(c: var AliveContext; g: PackedModuleGraph; name: string) =
|
||||
let (module, item) = c.compilerProcs[name]
|
||||
followLater(c, g, module, item)
|
||||
|
||||
proc loadTypeKind(t: PackedItemId; c: AliveContext; g: PackedModuleGraph; toSkip: set[TTypeKind]): TTypeKind =
|
||||
template kind(t: ItemId): TTypeKind = g[t.module].fromDisk.types[t.item].kind
|
||||
|
||||
var t2 = translateId(t, g, c.thisModule, c.decoder.config)
|
||||
result = t2.kind
|
||||
while result in toSkip:
|
||||
t2 = translateId(g[t2.module].fromDisk.types[t2.item].types[^1], g, t2.module, c.decoder.config)
|
||||
result = t2.kind
|
||||
|
||||
proc rangeCheckAnalysis(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: NodePos) =
|
||||
## Replicates the logic of `ccgexprs.genRangeChck`.
|
||||
## XXX Refactor so that the duplicated logic is avoided. However, for now it's not clear
|
||||
## the approach has enough merit.
|
||||
var dest = loadTypeKind(n.typ, c, g, abstractVar)
|
||||
if optRangeCheck notin c.options or dest in {tyUInt..tyUInt64}:
|
||||
discard "no need to generate a check because it was disabled"
|
||||
else:
|
||||
let n0t = loadTypeKind(n.firstSon.typ, c, g, {})
|
||||
if n0t in {tyUInt, tyUInt64}:
|
||||
c.requestCompilerProc(g, "raiseRangeErrorNoArgs")
|
||||
else:
|
||||
let raiser =
|
||||
case loadTypeKind(n.typ, c, g, abstractVarRange)
|
||||
of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
|
||||
of tyFloat..tyFloat128: "raiseRangeErrorF"
|
||||
else: "raiseRangeErrorI"
|
||||
c.requestCompilerProc(g, raiser)
|
||||
|
||||
proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: NodePos) =
|
||||
## Marks the symbols we encounter when we traverse the AST at `tree[n]` as alive, unless
|
||||
## it is purely in a declarative context (type section etc.).
|
||||
case n.kind
|
||||
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||
discard "ignore non-sym atoms"
|
||||
of nkSym:
|
||||
# This symbol is alive and everything its body references.
|
||||
followLater(c, g, c.thisModule, tree[n].soperand)
|
||||
of nkModuleRef:
|
||||
let (n1, n2) = sons2(tree, n)
|
||||
assert n1.kind == nkNone
|
||||
assert n2.kind == nkNone
|
||||
let m = n1.litId
|
||||
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,
|
||||
nkCommentStmt, nkIncludeStmt,
|
||||
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
||||
nkFromStmt, nkStaticStmt:
|
||||
discard
|
||||
of nkVarSection, nkLetSection, nkConstSection:
|
||||
# XXX ignore the defining local variable name?
|
||||
for son in sonsReadonly(tree, n):
|
||||
aliveCode(c, g, tree, son)
|
||||
of nkChckRangeF, nkChckRange64, nkChckRange:
|
||||
rangeCheckAnalysis(c, g, tree, n)
|
||||
of nkProcDef, nkConverterDef, nkMethodDef, nkFuncDef, nkIteratorDef:
|
||||
if n.firstSon.kind == nkSym and isNotGeneric(n):
|
||||
let item = tree[n.firstSon].soperand
|
||||
if isExportedToC(c, g, item):
|
||||
# This symbol is alive and everything its body references.
|
||||
followLater(c, g, c.thisModule, item)
|
||||
else:
|
||||
for son in sonsReadonly(tree, n):
|
||||
aliveCode(c, g, tree, son)
|
||||
|
||||
proc followNow(c: var AliveContext; g: PackedModuleGraph) =
|
||||
## Mark all entries in the stack. Marking can add more entries
|
||||
## to the stack but eventually we have looked at every alive symbol.
|
||||
while c.stack.len > 0:
|
||||
let (modId, opt, ast) = c.stack.pop()
|
||||
c.thisModule = modId
|
||||
c.options = opt
|
||||
aliveCode(c, g, g[modId].fromDisk.bodies, ast)
|
||||
|
||||
proc computeAliveSyms*(g: PackedModuleGraph; conf: ConfigRef): AliveSyms =
|
||||
## Entry point for our DCE algorithm.
|
||||
var c = AliveContext(stack: @[], decoder: PackedDecoder(config: conf),
|
||||
thisModule: -1, alive: newSeq[IntSet](g.len),
|
||||
options: conf.options)
|
||||
for i in countdown(len(g)-1, 0):
|
||||
if g[i].status != undefined:
|
||||
c.thisModule = i
|
||||
for p in allNodes(g[i].fromDisk.topLevel):
|
||||
aliveCode(c, g, g[i].fromDisk.topLevel, p)
|
||||
|
||||
followNow(c, g)
|
||||
result = move(c.alive)
|
||||
|
||||
proc isAlive*(a: AliveSyms; module: int, item: int32): bool =
|
||||
## Backends use this to query if a symbol is `alive` which means
|
||||
## we need to produce (C/C++/etc) code for it.
|
||||
result = a[module].contains(item)
|
||||
|
||||
56
compiler/ic/design.rst
Normal file
56
compiler/ic/design.rst
Normal file
@@ -0,0 +1,56 @@
|
||||
====================================
|
||||
Incremental Recompilations
|
||||
====================================
|
||||
|
||||
We split the Nim compiler into a frontend and a backend.
|
||||
The frontend produces a set of `.rod` files. Every `.nim` module
|
||||
produces its own `.rod` file.
|
||||
|
||||
- The IR must be a faithful representation of the AST in memory.
|
||||
- The backend can do its own caching but doesn't have to. In the
|
||||
current implementation the backend also caches its results.
|
||||
|
||||
Advantage of the "set of files" vs the previous global database:
|
||||
- By construction, we either read from the `.rod` file or from the
|
||||
`.nim` file, there can be no inconsistency. There can also be no
|
||||
partial updates.
|
||||
- No dependency to external packages (SQLite). SQLite simply is too
|
||||
slow and the old way of serialization was too slow too. We use a
|
||||
format designed for Nim and expect to base further tools on this
|
||||
file format.
|
||||
|
||||
References to external modules must be (moduleId, symId) pairs.
|
||||
The symbol IDs are module specific. This way no global ID increment
|
||||
mechanism needs to be implemented that we could get wrong. ModuleIds
|
||||
are rod-file specific too.
|
||||
|
||||
|
||||
|
||||
Global state
|
||||
------------
|
||||
|
||||
There is no global state.
|
||||
|
||||
Rod File Format
|
||||
---------------
|
||||
|
||||
It's a simple binary file format. `rodfiles.nim` contains some details.
|
||||
|
||||
|
||||
Backend
|
||||
-------
|
||||
|
||||
Nim programmers have to come to enjoy whole-program dead code elimination,
|
||||
by default. Since this is a "whole program" optimization, it does break
|
||||
modularity. However, thanks to the packed AST representation we can perform
|
||||
this global analysis without having to unpack anything. This is basically
|
||||
a mark&sweep GC algorithm:
|
||||
|
||||
- Start with the top level statements. Every symbol that is referenced
|
||||
from a top level statement is not "dead" and needs to be compiled by
|
||||
the backend.
|
||||
- Every symbol referenced from a referenced symbol also has to be
|
||||
compiled.
|
||||
|
||||
Caching logic: Only if the set of alive symbols is different from the
|
||||
last run, the module has to be regenerated.
|
||||
File diff suppressed because it is too large
Load Diff
1343
compiler/ic/ic.nim
Normal file
1343
compiler/ic/ic.nim
Normal file
File diff suppressed because it is too large
Load Diff
84
compiler/ic/iclineinfos.nim
Normal file
84
compiler/ic/iclineinfos.nim
Normal file
@@ -0,0 +1,84 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2024 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
|
||||
155
compiler/ic/integrity.nim
Normal file
155
compiler/ic/integrity.nim
Normal file
@@ -0,0 +1,155 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2021 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Integrity checking for a set of .rod files.
|
||||
## The set must cover a complete Nim project.
|
||||
|
||||
import std/[sets, tables]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
import ".." / [ast, modulegraphs]
|
||||
import packed_ast, bitabs, ic
|
||||
|
||||
type
|
||||
CheckedContext = object
|
||||
g: ModuleGraph
|
||||
thisModule: int32
|
||||
checkedSyms: HashSet[ItemId]
|
||||
checkedTypes: HashSet[ItemId]
|
||||
|
||||
proc checkType(c: var CheckedContext; typeId: PackedItemId)
|
||||
proc checkForeignSym(c: var CheckedContext; symId: PackedItemId)
|
||||
proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos)
|
||||
|
||||
proc checkTypeObj(c: var CheckedContext; typ: PackedType) =
|
||||
for child in typ.types:
|
||||
checkType(c, child)
|
||||
if typ.n != emptyNodeId:
|
||||
checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos typ.n)
|
||||
if typ.sym != nilItemId:
|
||||
checkForeignSym(c, typ.sym)
|
||||
if typ.owner != nilItemId:
|
||||
checkForeignSym(c, typ.owner)
|
||||
checkType(c, typ.typeInst)
|
||||
|
||||
proc checkType(c: var CheckedContext; typeId: PackedItemId) =
|
||||
if typeId == nilItemId: return
|
||||
let itemId = translateId(typeId, c.g.packed, c.thisModule, c.g.config)
|
||||
if not c.checkedTypes.containsOrIncl(itemId):
|
||||
let oldThisModule = c.thisModule
|
||||
c.thisModule = itemId.module
|
||||
checkTypeObj c, c.g.packed[itemId.module].fromDisk.types[itemId.item]
|
||||
c.thisModule = oldThisModule
|
||||
|
||||
proc checkSym(c: var CheckedContext; s: PackedSym) =
|
||||
if s.name != LitId(0):
|
||||
assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId s.name
|
||||
checkType c, s.typ
|
||||
if s.ast != emptyNodeId:
|
||||
checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos s.ast)
|
||||
if s.owner != nilItemId:
|
||||
checkForeignSym(c, s.owner)
|
||||
|
||||
proc checkLocalSym(c: var CheckedContext; item: int32) =
|
||||
let itemId = ItemId(module: c.thisModule, item: item)
|
||||
if not c.checkedSyms.containsOrIncl(itemId):
|
||||
checkSym c, c.g.packed[c.thisModule].fromDisk.syms[item]
|
||||
|
||||
proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) =
|
||||
let itemId = translateId(symId, c.g.packed, c.thisModule, c.g.config)
|
||||
if not c.checkedSyms.containsOrIncl(itemId):
|
||||
let oldThisModule = c.thisModule
|
||||
c.thisModule = itemId.module
|
||||
checkSym c, c.g.packed[itemId.module].fromDisk.syms[itemId.item]
|
||||
c.thisModule = oldThisModule
|
||||
|
||||
proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
|
||||
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[n].soperand)
|
||||
of directIntLit:
|
||||
discard
|
||||
of externIntLit, nkFloatLit..nkFloat128Lit:
|
||||
assert c.g.packed[c.thisModule].fromDisk.numbers.hasLitId n.litId
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
|
||||
of nkModuleRef:
|
||||
let (n1, n2) = sons2(tree, n)
|
||||
assert n1.kind == 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)
|
||||
|
||||
proc checkTree(c: var CheckedContext; t: PackedTree) =
|
||||
for p in allNodes(t): checkNode(c, t, p)
|
||||
|
||||
proc checkLocalSymIds(c: var CheckedContext; m: PackedModule; symIds: seq[int32]) =
|
||||
for symId in symIds:
|
||||
assert symId >= 0 and symId < m.syms.len, $symId & " " & $m.syms.len
|
||||
|
||||
proc checkModule(c: var CheckedContext; m: PackedModule) =
|
||||
# We check that:
|
||||
# - Every symbol references existing types and symbols.
|
||||
# - Every tree node references existing types and symbols.
|
||||
for _, v in pairs(m.syms):
|
||||
checkLocalSym c, v.id
|
||||
|
||||
checkTree c, m.toReplay
|
||||
checkTree c, m.topLevel
|
||||
|
||||
for e in m.exports:
|
||||
#assert e[1] >= 0 and e[1] < m.syms.len
|
||||
assert e[0] == m.syms[e[1]].name
|
||||
|
||||
for e in m.compilerProcs:
|
||||
#assert e[1] >= 0 and e[1] < m.syms.len
|
||||
assert e[0] == m.syms[e[1]].name
|
||||
|
||||
checkLocalSymIds c, m, m.converters
|
||||
checkLocalSymIds c, m, m.methods
|
||||
checkLocalSymIds c, m, m.trmacros
|
||||
checkLocalSymIds c, m, m.pureEnums
|
||||
#[
|
||||
To do: Check all these fields:
|
||||
|
||||
reexports*: seq[(LitId, PackedItemId)]
|
||||
macroUsages*: seq[(PackedItemId, PackedLineInfo)]
|
||||
|
||||
typeInstCache*: seq[(PackedItemId, PackedItemId)]
|
||||
procInstCache*: seq[PackedInstantiation]
|
||||
attachedOps*: seq[(TTypeAttachedOp, PackedItemId, PackedItemId)]
|
||||
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..<len(g.packed):
|
||||
# case statement here to enforce exhaustive checks.
|
||||
case g.packed[i].status
|
||||
of undefined:
|
||||
discard "nothing to do"
|
||||
of loading:
|
||||
assert false, "cannot check integrity: Module still loading"
|
||||
of stored, storing, outdated, loaded:
|
||||
c.thisModule = int32 i
|
||||
checkModule(c, g.packed[i].fromDisk)
|
||||
183
compiler/ic/navigator.nim
Normal file
183
compiler/ic/navigator.nim
Normal file
@@ -0,0 +1,183 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2021 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Supports the "nim check --ic:on --defusages:FILE,LINE,COL"
|
||||
## IDE-like features. It uses the set of .rod files to accomplish
|
||||
## its task. The set must cover a complete Nim project.
|
||||
|
||||
import std/[sets, tables]
|
||||
|
||||
from std/os import nil
|
||||
from std/private/miscdollars import toLocation
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
import ".." / [ast, modulegraphs, msgs, options]
|
||||
import iclineinfos
|
||||
import packed_ast, bitabs, ic
|
||||
|
||||
type
|
||||
UnpackedLineInfo = object
|
||||
file: LitId
|
||||
line, col: int
|
||||
NavContext = object
|
||||
g: ModuleGraph
|
||||
thisModule: int32
|
||||
trackPos: UnpackedLineInfo
|
||||
alreadyEmitted: HashSet[string]
|
||||
outputSep: char # for easier testing, use short filenames and spaces instead of tabs.
|
||||
|
||||
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 >= 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(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(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..<len(tree):
|
||||
let i = NodePos(i)
|
||||
case tree[i].kind
|
||||
of nkSym:
|
||||
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:
|
||||
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[n2].soperand)
|
||||
let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config)
|
||||
if searchForeignSym(c, itemId, tree[i].info):
|
||||
return itemId
|
||||
else: discard
|
||||
return EmptyItemId
|
||||
|
||||
proc isDecl(tree: PackedTree; n: NodePos): bool =
|
||||
# XXX This is not correct yet.
|
||||
const declarativeNodes = procDefs + {nkMacroDef, nkTemplateDef,
|
||||
nkLetSection, nkVarSection, nkUsingStmt, nkConstSection, nkTypeSection,
|
||||
nkIdentDefs, nkEnumTy, nkVarTuple}
|
||||
result = n.int >= 0 and tree[n].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[fileId]
|
||||
if c.outputSep == ' ':
|
||||
file = os.extractFilename file
|
||||
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..<len(tree):
|
||||
let i = NodePos(i)
|
||||
case tree[i].kind
|
||||
of nkSym:
|
||||
let item = tree[i].soperand
|
||||
if sym.item == item and sym.module == c.thisModule:
|
||||
usage(c, tree[i].info, isDecl(tree, parent(i)))
|
||||
of nkModuleRef:
|
||||
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[i].info, isDecl(tree, parent(i)))
|
||||
else: discard
|
||||
|
||||
proc searchForIncludeFile(g: ModuleGraph; fullPath: string): int =
|
||||
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.
|
||||
if os.cmpPaths(g.packed[i].fromDisk.strings[g.packed[i].fromDisk.includes[k][0]], fullPath) == 0:
|
||||
return i
|
||||
return -1
|
||||
|
||||
proc nav(g: ModuleGraph) =
|
||||
# translate the track position to a packed position:
|
||||
let unpacked = g.config.m.trackPos
|
||||
var mid = unpacked.fileIndex.int
|
||||
|
||||
let fullPath = toFullPath(g.config, unpacked.fileIndex)
|
||||
|
||||
if g.packed[mid].status == undefined:
|
||||
# check if 'mid' is an include file of some other module:
|
||||
mid = searchForIncludeFile(g, fullPath)
|
||||
|
||||
if mid < 0:
|
||||
localError(g.config, unpacked, "unknown file name: " & fullPath)
|
||||
return
|
||||
|
||||
let fileId = g.packed[mid].fromDisk.strings.getKeyId(fullPath)
|
||||
|
||||
if fileId == LitId(0):
|
||||
internalError(g.config, unpacked, "cannot find a valid file ID")
|
||||
return
|
||||
|
||||
var c = NavContext(
|
||||
g: g,
|
||||
thisModule: int32 mid,
|
||||
trackPos: 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)
|
||||
if symId == EmptyItemId:
|
||||
symId = search(c, g.packed[mid].fromDisk.bodies)
|
||||
|
||||
if symId == EmptyItemId:
|
||||
localError(g.config, unpacked, "no symbol at this position")
|
||||
return
|
||||
|
||||
for i in 0..<len(g.packed):
|
||||
# case statement here to enforce exhaustive checks.
|
||||
case g.packed[i].status
|
||||
of undefined:
|
||||
discard "nothing to do"
|
||||
of loading:
|
||||
assert false, "cannot check integrity: Module still loading"
|
||||
of stored, storing, outdated, loaded:
|
||||
c.thisModule = int32 i
|
||||
list(c, g.packed[i].fromDisk.topLevel, symId)
|
||||
list(c, g.packed[i].fromDisk.bodies, symId)
|
||||
|
||||
proc navDefinition*(g: ModuleGraph) = nav(g)
|
||||
proc navUsages*(g: ModuleGraph) = nav(g)
|
||||
proc navDefusages*(g: ModuleGraph) = nav(g)
|
||||
|
||||
proc writeRodFiles*(g: ModuleGraph) =
|
||||
for i in 0..<len(g.packed):
|
||||
case g.packed[i].status
|
||||
of undefined, loading, stored, loaded:
|
||||
discard "nothing to do"
|
||||
of storing, outdated:
|
||||
closeRodFile(g, g.packed[i].module)
|
||||
367
compiler/ic/packed_ast.nim
Normal file
367
compiler/ic/packed_ast.nim
Normal file
@@ -0,0 +1,367 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2020 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Packed AST representation, mostly based on a seq of nodes.
|
||||
## For IC support. Far future: Rewrite the compiler passes to
|
||||
## use this representation directly in all the transformations,
|
||||
## it is superior.
|
||||
|
||||
import std/[hashes, tables, strtabs]
|
||||
import bitabs, rodfiles
|
||||
import ".." / [ast, options]
|
||||
|
||||
import iclineinfos
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
type
|
||||
SymId* = distinct int32
|
||||
ModuleId* = distinct int32
|
||||
NodePos* = distinct int
|
||||
|
||||
NodeId* = distinct int32
|
||||
|
||||
PackedItemId* = object
|
||||
module*: LitId # 0 if it's this module
|
||||
item*: int32 # same as the in-memory representation
|
||||
|
||||
const
|
||||
nilItemId* = PackedItemId(module: LitId(0), item: 0.int32)
|
||||
|
||||
const
|
||||
emptyNodeId* = NodeId(-1)
|
||||
|
||||
type
|
||||
PackedLib* = object
|
||||
kind*: TLibKind
|
||||
generated*: bool
|
||||
isOverridden*: bool
|
||||
name*: LitId
|
||||
path*: NodeId
|
||||
|
||||
PackedSym* = object
|
||||
id*: int32
|
||||
kind*: TSymKind
|
||||
name*: LitId
|
||||
typ*: PackedItemId
|
||||
flags*: TSymFlags
|
||||
magic*: TMagic
|
||||
info*: PackedLineInfo
|
||||
ast*: NodeId
|
||||
owner*: PackedItemId
|
||||
guard*: PackedItemId
|
||||
bitsize*: int
|
||||
alignment*: int # for alignment
|
||||
options*: TOptions
|
||||
position*: int
|
||||
offset*: int32
|
||||
disamb*: int32
|
||||
externalName*: LitId # instead of TLoc
|
||||
locFlags*: TLocFlags
|
||||
annex*: PackedLib
|
||||
when hasFFI:
|
||||
cname*: LitId
|
||||
constraint*: NodeId
|
||||
instantiatedFrom*: PackedItemId
|
||||
|
||||
PackedType* = object
|
||||
id*: int32
|
||||
kind*: TTypeKind
|
||||
callConv*: TCallingConvention
|
||||
#nodekind*: TNodeKind
|
||||
flags*: TTypeFlags
|
||||
types*: seq[PackedItemId]
|
||||
n*: NodeId
|
||||
#nodeflags*: TNodeFlags
|
||||
sym*: PackedItemId
|
||||
owner*: PackedItemId
|
||||
size*: BiggestInt
|
||||
align*: int16
|
||||
paddingAtEnd*: int16
|
||||
# not serialized: loc*: TLoc because it is backend-specific
|
||||
typeInst*: PackedItemId
|
||||
nonUniqueId*: int32
|
||||
|
||||
PackedNode* = object # 8 bytes
|
||||
x: uint32
|
||||
info*: PackedLineInfo
|
||||
|
||||
PackedTree* = object ## usually represents a full Nim module
|
||||
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.}
|
||||
|
||||
proc `==`*(a, b: NodePos): bool {.borrow.}
|
||||
#proc `==`*(a, b: PackedItemId): bool {.borrow.}
|
||||
proc `==`*(a, b: NodeId): bool {.borrow.}
|
||||
|
||||
proc newTreeFrom*(old: PackedTree): PackedTree =
|
||||
result = PackedTree(nodes: @[])
|
||||
when false: result.sh = old.sh
|
||||
|
||||
proc addIdent*(tree: var PackedTree; s: LitId; info: PackedLineInfo) =
|
||||
tree.nodes.add PackedNode(x: toX(nkIdent, uint32(s)), info: info)
|
||||
|
||||
proc addSym*(tree: var PackedTree; s: int32; info: PackedLineInfo) =
|
||||
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(x: toX(nkSym, cast[uint32](s)), info: info)
|
||||
|
||||
proc isAtom*(tree: PackedTree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= nkNilLit
|
||||
|
||||
type
|
||||
PatchPos = distinct int
|
||||
|
||||
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.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
|
||||
dest.nodes.add source.nodes[sourcePos.int]
|
||||
|
||||
proc patch*(tree: var PackedTree; pos: PatchPos) =
|
||||
let pos = pos.int
|
||||
let k = tree.nodes[pos].kind
|
||||
assert k > nkNilLit
|
||||
let distance = int32(tree.nodes.len - pos)
|
||||
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: 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].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].rawSpan
|
||||
inc pos
|
||||
while pos < last:
|
||||
yield NodePos pos
|
||||
nextChild tree, pos
|
||||
|
||||
iterator sons*(dest: var PackedTree; tree: PackedTree; n: NodePos): NodePos =
|
||||
let patchPos = prepare(dest, tree, n)
|
||||
for x in sonsReadonly(tree, n): yield x
|
||||
patch dest, patchPos
|
||||
|
||||
iterator isons*(dest: var PackedTree; tree: PackedTree;
|
||||
n: NodePos): (int, NodePos) =
|
||||
var i = 0
|
||||
for ch0 in sons(dest, tree, n):
|
||||
yield (i, ch0)
|
||||
inc i
|
||||
|
||||
iterator sonsFrom1*(tree: PackedTree; n: NodePos): NodePos =
|
||||
var pos = n.int
|
||||
assert tree.nodes[pos].kind > nkNilLit
|
||||
let last = pos + tree.nodes[pos].rawSpan
|
||||
inc pos
|
||||
if pos < last:
|
||||
nextChild tree, pos
|
||||
while pos < last:
|
||||
yield NodePos pos
|
||||
nextChild tree, pos
|
||||
|
||||
iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos =
|
||||
var count = 0
|
||||
for child in sonsReadonly(tree, n):
|
||||
inc count
|
||||
var pos = n.int
|
||||
assert tree.nodes[pos].kind > nkNilLit
|
||||
let last = pos + tree.nodes[pos].rawSpan
|
||||
inc pos
|
||||
while pos < last and count > 2:
|
||||
yield NodePos pos
|
||||
dec count
|
||||
nextChild tree, pos
|
||||
|
||||
proc parentImpl(tree: PackedTree; n: NodePos): NodePos =
|
||||
# finding the parent of a node is rather easy:
|
||||
var pos = n.int - 1
|
||||
while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].rawSpan - 1 < n.int)):
|
||||
dec pos
|
||||
#assert pos >= 0, "node has no parent"
|
||||
result = NodePos(pos)
|
||||
|
||||
template parent*(n: NodePos): NodePos = parentImpl(tree, n)
|
||||
|
||||
proc hasXsons*(tree: PackedTree; n: NodePos; x: int): bool =
|
||||
var count = 0
|
||||
if tree.nodes[n.int].kind > nkNilLit:
|
||||
for child in sonsReadonly(tree, n): inc count
|
||||
result = count == x
|
||||
|
||||
proc hasAtLeastXsons*(tree: PackedTree; n: NodePos; x: int): bool =
|
||||
if tree.nodes[n.int].kind > nkNilLit:
|
||||
var count = 0
|
||||
for child in sonsReadonly(tree, n):
|
||||
inc count
|
||||
if count >= x: return true
|
||||
return false
|
||||
|
||||
proc firstSon*(tree: PackedTree; n: NodePos): NodePos {.inline.} =
|
||||
NodePos(n.int+1)
|
||||
proc kind*(tree: PackedTree; n: NodePos): TNodeKind {.inline.} =
|
||||
tree.nodes[n.int].kind
|
||||
proc litId*(tree: PackedTree; n: NodePos): LitId {.inline.} =
|
||||
LitId tree.nodes[n.int].uoperand
|
||||
proc info*(tree: PackedTree; n: NodePos): PackedLineInfo {.inline.} =
|
||||
tree.nodes[n.int].info
|
||||
|
||||
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
|
||||
|
||||
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].rawSpan
|
||||
|
||||
proc sons2*(tree: PackedTree; n: NodePos): (NodePos, NodePos) =
|
||||
assert(not isAtom(tree, n.int))
|
||||
let a = n.int+1
|
||||
let b = a + span(tree, a)
|
||||
result = (NodePos a, NodePos b)
|
||||
|
||||
proc sons3*(tree: PackedTree; n: NodePos): (NodePos, NodePos, NodePos) =
|
||||
assert(not isAtom(tree, n.int))
|
||||
let a = n.int+1
|
||||
let b = a + span(tree, a)
|
||||
let c = b + span(tree, b)
|
||||
result = (NodePos a, NodePos b, NodePos c)
|
||||
|
||||
proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos =
|
||||
result = default(NodePos)
|
||||
if tree.nodes[n.int].kind > nkNilLit:
|
||||
var count = 0
|
||||
for child in sonsReadonly(tree, n):
|
||||
if count == i: return child
|
||||
inc count
|
||||
assert false, "node has no i-th child"
|
||||
|
||||
when false:
|
||||
proc `@`*(tree: PackedTree; lit: LitId): lent string {.inline.} =
|
||||
tree.sh.strings[lit]
|
||||
|
||||
template kind*(n: NodePos): TNodeKind = tree.nodes[n.int].kind
|
||||
template info*(n: NodePos): PackedLineInfo = tree.nodes[n.int].info
|
||||
template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].uoperand
|
||||
|
||||
template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].soperand
|
||||
|
||||
proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1)
|
||||
|
||||
const
|
||||
externIntLit* = {nkCharLit,
|
||||
nkIntLit,
|
||||
nkInt8Lit,
|
||||
nkInt16Lit,
|
||||
nkInt32Lit,
|
||||
nkInt64Lit,
|
||||
nkUIntLit,
|
||||
nkUInt8Lit,
|
||||
nkUInt16Lit,
|
||||
nkUInt32Lit,
|
||||
nkUInt64Lit}
|
||||
|
||||
externSIntLit* = {nkIntLit, nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit}
|
||||
externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit}
|
||||
directIntLit* = nkNone
|
||||
|
||||
template copyInto*(dest, n, body) =
|
||||
let patchPos = prepare(dest, tree, n)
|
||||
body
|
||||
patch dest, patchPos
|
||||
|
||||
template copyIntoKind*(dest, kind, info, body) =
|
||||
let patchPos = prepare(dest, kind, info)
|
||||
body
|
||||
patch dest, patchPos
|
||||
|
||||
proc getNodeId*(tree: PackedTree): NodeId {.inline.} = NodeId tree.nodes.len
|
||||
|
||||
iterator allNodes*(tree: PackedTree): NodePos =
|
||||
var p = 0
|
||||
while p < tree.len:
|
||||
yield NodePos(p)
|
||||
let s = span(tree, p)
|
||||
inc p, s
|
||||
|
||||
proc toPackedItemId*(item: int32): PackedItemId {.inline.} =
|
||||
PackedItemId(module: LitId(0), item: item)
|
||||
|
||||
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
|
||||
@@ -19,6 +19,8 @@ import std/tables
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
import packed_ast, ic, bitabs
|
||||
|
||||
proc replayStateChanges*(module: PSym; g: ModuleGraph) =
|
||||
let list = module.ast
|
||||
assert list != nil
|
||||
@@ -86,3 +88,84 @@ proc replayStateChanges*(module: PSym; g: ModuleGraph) =
|
||||
g.cacheSeqs[destKey].add val
|
||||
else:
|
||||
internalAssert g.config, false
|
||||
|
||||
proc replayBackendProcs*(g: ModuleGraph; module: int) =
|
||||
for it in mitems(g.packed[module].fromDisk.attachedOps):
|
||||
let key = translateId(it[0], g.packed, module, g.config)
|
||||
let op = it[1]
|
||||
let tmp = translateId(it[2], g.packed, module, g.config)
|
||||
let symId = FullId(module: tmp.module, packed: it[2])
|
||||
g.attachedOps[op][key] = LazySym(id: symId, sym: nil)
|
||||
|
||||
for it in mitems(g.packed[module].fromDisk.enumToStringProcs):
|
||||
let key = translateId(it[0], g.packed, module, g.config)
|
||||
let tmp = translateId(it[1], g.packed, module, g.config)
|
||||
let symId = FullId(module: tmp.module, packed: it[1])
|
||||
g.enumToStringProcs[key] = LazySym(id: symId, sym: nil)
|
||||
|
||||
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
|
||||
## to imply. This is cheaper than deduplication of identical
|
||||
## generic instantiations. However, deduplication is more
|
||||
## powerful and general and I hope to implement it soon too
|
||||
## (famous last words).
|
||||
assert g.packed[module].status == loaded
|
||||
for it in g.packed[module].fromDisk.typeInstCache:
|
||||
let key = translateId(it[0], g.packed, module, g.config)
|
||||
g.typeInstCache.mgetOrPut(key, @[]).add LazyType(id: FullId(module: module, packed: it[1]), typ: nil)
|
||||
|
||||
for it in mitems(g.packed[module].fromDisk.procInstCache):
|
||||
let key = translateId(it.key, g.packed, module, g.config)
|
||||
let sym = translateId(it.sym, g.packed, module, g.config)
|
||||
var concreteTypes = newSeq[FullId](it.concreteTypes.len)
|
||||
for i in 0..high(it.concreteTypes):
|
||||
let tmp = translateId(it.concreteTypes[i], g.packed, module, g.config)
|
||||
concreteTypes[i] = FullId(module: tmp.module, packed: it.concreteTypes[i])
|
||||
|
||||
g.procInstCache.mgetOrPut(key, @[]).add LazyInstantiation(
|
||||
module: module, sym: FullId(module: sym.module, packed: it.sym),
|
||||
concreteTypes: concreteTypes, inst: nil)
|
||||
|
||||
for it in mitems(g.packed[module].fromDisk.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.methodsPerGenericType.mgetOrPut(key, @[]).add (col, LazySym(id: symId, sym: nil))
|
||||
|
||||
replayBackendProcs(g, module)
|
||||
|
||||
for it in mitems(g.packed[module].fromDisk.methods):
|
||||
let sym = loadSymFromId(g.config, g.cache, g.packed, module,
|
||||
PackedItemId(module: LitId(0), item: it))
|
||||
methodDef(g, g.idgen, sym)
|
||||
|
||||
when false:
|
||||
# not used anymore:
|
||||
for it in mitems(g.packed[module].fromDisk.compilerProcs):
|
||||
let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it[1]))
|
||||
g.lazyCompilerprocs[g.packed[module].fromDisk.sh.strings[it[0]]] = symId
|
||||
|
||||
for it in mitems(g.packed[module].fromDisk.converters):
|
||||
let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it))
|
||||
g.ifaces[module].converters.add LazySym(id: symId, sym: nil)
|
||||
|
||||
for it in mitems(g.packed[module].fromDisk.trmacros):
|
||||
let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it))
|
||||
g.ifaces[module].patterns.add LazySym(id: symId, sym: nil)
|
||||
|
||||
for it in mitems(g.packed[module].fromDisk.pureEnums):
|
||||
let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it))
|
||||
g.ifaces[module].pureEnums.add LazySym(id: symId, sym: nil)
|
||||
|
||||
283
compiler/ic/rodfiles.nim
Normal file
283
compiler/ic/rodfiles.nim
Normal file
@@ -0,0 +1,283 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2020 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Low level binary format used by the compiler to store and load various AST
|
||||
## and related data.
|
||||
##
|
||||
## NB: this is incredibly low level and if you're interested in how the
|
||||
## compiler works and less a storage format, you're probably looking for
|
||||
## the `ic` or `packed_ast` modules to understand the logical format.
|
||||
|
||||
from std/typetraits import supportsCopyMem
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
|
||||
import std / tables
|
||||
|
||||
## Overview
|
||||
## ========
|
||||
## `RodFile` represents a Rod File (versioned binary format), and the
|
||||
## associated data for common interactions such as IO and error tracking
|
||||
## (`RodFileError`). The file format broken up into sections (`RodSection`)
|
||||
## and preceded by a header (see: `cookie`). The precise layout, section
|
||||
## ordering and data following the section are determined by the user. See
|
||||
## `ic.loadRodFile`.
|
||||
##
|
||||
## A basic but "wrong" example of the lifecycle:
|
||||
## ---------------------------------------------
|
||||
## 1. `create` or `open` - create a new one or open an existing
|
||||
## 2. `storeHeader` - header info
|
||||
## 3. `storePrim` or `storeSeq` - save your stuff
|
||||
## 4. `close` - and we're done
|
||||
##
|
||||
## Now read the bits below to understand what's missing.
|
||||
##
|
||||
## ### Issues with the Example
|
||||
## Missing Sections:
|
||||
## This is a low level API, so headers and sections need to be stored and
|
||||
## loaded by the user, see `storeHeader` & `loadHeader` and `storeSection` &
|
||||
## `loadSection`, respectively.
|
||||
##
|
||||
## No Error Handling:
|
||||
## The API is centered around IO and prone to error, each operation checks or
|
||||
## sets the `RodFile.err` field. A user of this API needs to handle these
|
||||
## appropriately.
|
||||
##
|
||||
## API Notes
|
||||
## =========
|
||||
##
|
||||
## Valid inputs for Rod files
|
||||
## --------------------------
|
||||
## ASTs, hopes, dreams, and anything as long as it and any children it may have
|
||||
## support `copyMem`. This means anything that is not a pointer and that does not contain a pointer. At a glance these are:
|
||||
## * string
|
||||
## * objects & tuples (fields are recursed)
|
||||
## * sequences AKA `seq[T]`
|
||||
##
|
||||
## Note on error handling style
|
||||
## ----------------------------
|
||||
## A flag based approach is used where operations no-op in case of a
|
||||
## preexisting error and set the flag if they encounter one.
|
||||
##
|
||||
## Misc
|
||||
## ----
|
||||
## * 'Prim' is short for 'primitive', as in a non-sequence type
|
||||
|
||||
type
|
||||
RodSection* = enum
|
||||
versionSection
|
||||
configSection
|
||||
stringsSection
|
||||
checkSumsSection
|
||||
depsSection
|
||||
numbersSection
|
||||
exportsSection
|
||||
hiddenSection
|
||||
reexportsSection
|
||||
compilerProcsSection
|
||||
trmacrosSection
|
||||
convertersSection
|
||||
methodsSection
|
||||
pureEnumsSection
|
||||
toReplaySection
|
||||
topLevelSection
|
||||
bodiesSection
|
||||
symsSection
|
||||
typesSection
|
||||
typeInstCacheSection
|
||||
procInstCacheSection
|
||||
attachedOpsSection
|
||||
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,
|
||||
includeFileChanged
|
||||
|
||||
RodFile* = object
|
||||
f*: File
|
||||
currentSection*: RodSection # for error checking
|
||||
err*: RodFileError # little experiment to see if this works
|
||||
# better than exceptions.
|
||||
|
||||
const
|
||||
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.} =
|
||||
f.err = err
|
||||
#raise newException(IOError, "IO error")
|
||||
|
||||
proc storePrim*(f: var RodFile; s: string) =
|
||||
## Stores a string.
|
||||
## The len is prefixed to allow for later retreival.
|
||||
if f.err != ok: return
|
||||
if s.len >= high(int32):
|
||||
setError f, tooBig
|
||||
return
|
||||
var lenPrefix = int32(s.len)
|
||||
if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
|
||||
setError f, ioFailure
|
||||
else:
|
||||
if s.len != 0:
|
||||
if writeBuffer(f.f, unsafeAddr(s[0]), s.len) != s.len:
|
||||
setError f, ioFailure
|
||||
|
||||
proc storePrim*[T](f: var RodFile; x: T) =
|
||||
## Stores a non-sequence/string `T`.
|
||||
## If `T` doesn't support `copyMem` and is an object or tuple then the fields
|
||||
## are written -- the user from context will need to know which `T` to load.
|
||||
if f.err != ok: return
|
||||
when supportsCopyMem(T):
|
||||
if writeBuffer(f.f, unsafeAddr(x), sizeof(x)) != sizeof(x):
|
||||
setError f, ioFailure
|
||||
elif T is tuple:
|
||||
for y in fields(x):
|
||||
storePrim(f, y)
|
||||
elif T is object:
|
||||
for y in fields(x):
|
||||
when y is seq:
|
||||
storeSeq(f, y)
|
||||
else:
|
||||
storePrim(f, y)
|
||||
else:
|
||||
{.error: "unsupported type for 'storePrim'".}
|
||||
|
||||
proc storeSeq*[T](f: var RodFile; s: seq[T]) =
|
||||
## Stores a sequence of `T`s, with the len as a prefix for later retrieval.
|
||||
if f.err != ok: return
|
||||
if s.len >= high(int32):
|
||||
setError f, tooBig
|
||||
return
|
||||
var lenPrefix = int32(s.len)
|
||||
if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
|
||||
setError f, ioFailure
|
||||
else:
|
||||
for i in 0..<s.len:
|
||||
storePrim(f, s[i])
|
||||
|
||||
proc storeOrderedTable*[K, T](f: var RodFile; s: OrderedTable[K, T]) =
|
||||
if f.err != ok: return
|
||||
if s.len >= high(int32):
|
||||
setError f, tooBig
|
||||
return
|
||||
var lenPrefix = int32(s.len)
|
||||
if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
|
||||
setError f, ioFailure
|
||||
else:
|
||||
for _, v in s:
|
||||
storePrim(f, v)
|
||||
|
||||
proc loadPrim*(f: var RodFile; s: var string) =
|
||||
## Read a string, the length was stored as a prefix
|
||||
if f.err != ok: return
|
||||
var lenPrefix = int32(0)
|
||||
if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
|
||||
setError f, ioFailure
|
||||
else:
|
||||
s = newString(lenPrefix)
|
||||
if lenPrefix > 0:
|
||||
if readBuffer(f.f, unsafeAddr(s[0]), s.len) != s.len:
|
||||
setError f, ioFailure
|
||||
|
||||
proc loadPrim*[T](f: var RodFile; x: var T) =
|
||||
## Load a non-sequence/string `T`.
|
||||
if f.err != ok: return
|
||||
when supportsCopyMem(T):
|
||||
if readBuffer(f.f, unsafeAddr(x), sizeof(x)) != sizeof(x):
|
||||
setError f, ioFailure
|
||||
elif T is tuple:
|
||||
for y in fields(x):
|
||||
loadPrim(f, y)
|
||||
elif T is object:
|
||||
for y in fields(x):
|
||||
when y is seq:
|
||||
loadSeq(f, y)
|
||||
else:
|
||||
loadPrim(f, y)
|
||||
else:
|
||||
{.error: "unsupported type for 'loadPrim'".}
|
||||
|
||||
proc loadSeq*[T](f: var RodFile; s: var seq[T]) =
|
||||
## `T` must be compatible with `copyMem`, see `loadPrim`
|
||||
if f.err != ok: return
|
||||
var lenPrefix = int32(0)
|
||||
if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
|
||||
setError f, ioFailure
|
||||
else:
|
||||
s = newSeq[T](lenPrefix)
|
||||
for i in 0..<lenPrefix:
|
||||
loadPrim(f, s[i])
|
||||
|
||||
proc loadOrderedTable*[K, T](f: var RodFile; s: var OrderedTable[K, T]) =
|
||||
## `T` must be compatible with `copyMem`, see `loadPrim`
|
||||
if f.err != ok: return
|
||||
var lenPrefix = int32(0)
|
||||
if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
|
||||
setError f, ioFailure
|
||||
else:
|
||||
s = initOrderedTable[K, T](lenPrefix)
|
||||
for i in 0..<lenPrefix:
|
||||
var x = default T
|
||||
loadPrim(f, x)
|
||||
s[x.id] = x
|
||||
|
||||
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; cookie = defaultCookie) =
|
||||
## Loads the header which is described by `cookie`.
|
||||
if f.err != ok: return
|
||||
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:
|
||||
setError f, wrongHeader
|
||||
|
||||
proc storeSection*(f: var RodFile; s: RodSection) =
|
||||
## update `currentSection` and writes the bytes value of s.
|
||||
if f.err != ok: return
|
||||
assert f.currentSection < s
|
||||
f.currentSection = s
|
||||
storePrim(f, s)
|
||||
|
||||
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 = 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
|
||||
|
||||
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
|
||||
@@ -10,10 +10,10 @@
|
||||
## This module implements the symbol importing mechanism.
|
||||
|
||||
import
|
||||
ast, msgs, options, idents, lookups,
|
||||
ast, astalgo, msgs, options, idents, lookups,
|
||||
semdata, modulepaths, sigmatch, lineinfos,
|
||||
modulegraphs, wordrecg
|
||||
from std/strutils import `%`, startsWith, replace
|
||||
from std/strutils import `%`, startsWith
|
||||
from std/sequtils import addUnique
|
||||
import std/[sets, tables, intsets]
|
||||
|
||||
@@ -108,8 +108,8 @@ proc rawImportSymbol(c: PContext, s, origin: PSym; importSet: var IntSet) =
|
||||
else:
|
||||
importPureEnumField(c, e)
|
||||
else:
|
||||
if s.kind == skConverter: addConverter(c, s)
|
||||
if hasPattern(s): addPattern(c, s)
|
||||
if s.kind == skConverter: addConverter(c, LazySym(sym: s))
|
||||
if hasPattern(s): addPattern(c, LazySym(sym: s))
|
||||
if s.owner != origin:
|
||||
c.exportIndirections.incl((origin.id, s.id))
|
||||
|
||||
@@ -190,19 +190,22 @@ proc addImport(c: PContext; im: sink ImportedModule) =
|
||||
template addUnnamedIt(c: PContext, fromMod: PSym; filter: untyped) {.dirty.} =
|
||||
for it in mitems c.graph.ifaces[fromMod.position].converters:
|
||||
if filter:
|
||||
if sfExported in it.flags:
|
||||
loadPackedSym(c.graph, it)
|
||||
if sfExported in it.sym.flags:
|
||||
addConverter(c, it)
|
||||
for it in mitems c.graph.ifaces[fromMod.position].patterns:
|
||||
if filter:
|
||||
if sfExported in it.flags:
|
||||
loadPackedSym(c.graph, it)
|
||||
if sfExported in it.sym.flags:
|
||||
addPattern(c, it)
|
||||
for it in mitems c.graph.ifaces[fromMod.position].pureEnums:
|
||||
if filter:
|
||||
importPureEnumFields(c, it, it.typ)
|
||||
loadPackedSym(c.graph, it)
|
||||
importPureEnumFields(c, it.sym, it.sym.typ)
|
||||
|
||||
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
|
||||
c.addImport ImportedModule(m: fromMod, mode: importExcept, exceptSet: exceptSet)
|
||||
addUnnamedIt(c, fromMod, it.name.id notin exceptSet)
|
||||
addUnnamedIt(c, fromMod, it.sym.name.id notin exceptSet)
|
||||
|
||||
proc importAllSymbols*(c: PContext, fromMod: PSym) =
|
||||
c.addImport ImportedModule(m: fromMod, mode: importAll)
|
||||
@@ -242,8 +245,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden, track
|
||||
# avoids modifying `realModule`, see D20201209T194412 for `import {.all.}`
|
||||
result = createModuleAliasImpl(realModule.name)
|
||||
if importHidden:
|
||||
ensureMutable result
|
||||
result.optionsImpl.incl optImportHidden
|
||||
result.options.incl optImportHidden
|
||||
let moduleIdent = if n.kind in {nkInfix, nkImportAs}: n[^1] else: n
|
||||
result.info = moduleIdent.info
|
||||
if trackUnusedImport:
|
||||
@@ -289,8 +291,9 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
|
||||
c.recursiveDep = err
|
||||
|
||||
let trackUnusedImport = warnUnusedImportX in c.config.notes
|
||||
var realModule: PSym
|
||||
discard pushOptionEntry(c)
|
||||
let realModule = c.graph.importModuleCallback(c.graph, c.module, f)
|
||||
realModule = c.graph.importModuleCallback(c.graph, c.module, f)
|
||||
result = importModuleAs(c, n, realModule, transf.importHidden, trackUnusedImport)
|
||||
popOptionEntry(c)
|
||||
|
||||
@@ -304,9 +307,9 @@ 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 moduleNameNorm = getModuleName(c.config, n).replace("\\", "/")
|
||||
if belongsToStdlib(c.graph, result) and not startsWith(moduleNameNorm, stdPrefix) and
|
||||
not startsWith(moduleNameNorm, "system/") and not startsWith(moduleNameNorm, "packages/"):
|
||||
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)
|
||||
|
||||
proc suggestMod(n: PNode; s: PSym) =
|
||||
|
||||
@@ -24,7 +24,7 @@ import std/[strtabs, tables, strutils, intsets]
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
from trees import exprStructuralEquivalent, getRoot, whichPragma, getPotentialWrites
|
||||
from trees import exprStructuralEquivalent, getRoot, whichPragma
|
||||
|
||||
type
|
||||
Con = object
|
||||
@@ -69,14 +69,12 @@ proc hasDestructor(c: Con; t: PType): bool {.inline.} =
|
||||
result = ast.hasDestructor(t)
|
||||
when toDebug.len > 0:
|
||||
# for more effective debugging
|
||||
if not result and c.graph.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc}:
|
||||
if not result and c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
assert(not containsGarbageCollectedRef(t))
|
||||
|
||||
proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo; needsInit: bool): PNode =
|
||||
proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
|
||||
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.idgen, c.owner, info)
|
||||
sym.typ = typ
|
||||
if not needsInit:
|
||||
sym.incl sfNoInit
|
||||
s.vars.add(sym)
|
||||
result = newSymNode(sym)
|
||||
|
||||
@@ -167,7 +165,7 @@ proc isLastReadImpl(n: PNode; c: var Con; scope: var Scope): bool =
|
||||
|
||||
template hasDestructorOrAsgn(c: var Con, typ: PType): bool =
|
||||
# bug #23354; an object type could have a non-trivial assignements when it is passed to a sink parameter
|
||||
hasDestructor(c, typ) or (c.graph.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc} and
|
||||
hasDestructor(c, typ) or (c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
|
||||
typ.kind == tyObject and not isTrivial(getAttachedOp(c.graph, typ, attachedAsgn)))
|
||||
|
||||
proc isLastRead(n: PNode; c: var Con; s: var Scope): bool =
|
||||
@@ -304,7 +302,7 @@ proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFla
|
||||
if deepAliases(dest, ri):
|
||||
# consider: x = x + y, it is wrong to destroy the destination first!
|
||||
# tmp to support self assignments
|
||||
let tmp = c.getTemp(s, dest.typ, dest.info, needsInit = false)
|
||||
let tmp = c.getTemp(s, dest.typ, dest.info)
|
||||
result = newTree(nkStmtList, newTree(nkFastAsgn, tmp, dest), newTree(nkFastAsgn, dest, ri),
|
||||
c.genDestroy(tmp))
|
||||
else:
|
||||
@@ -331,21 +329,21 @@ proc isCriticalLink(dest: PNode): bool {.inline.} =
|
||||
result = dest.kind != nkSym
|
||||
|
||||
proc finishCopy(c: var Con; result, dest: PNode; flags: set[MoveOrCopyFlag]; isFromSink: bool) =
|
||||
if c.graph.config.selectedGC in {gcOrc, gcYrc} and IsExplicitSink notin flags:
|
||||
if c.graph.config.selectedGC == gcOrc and IsExplicitSink notin flags:
|
||||
# add cyclic flag, but not to sink calls, which IsExplicitSink generates
|
||||
let t = dest.typ.skipTypes(tyUserTypeClasses + {tyGenericInst, tyAlias, tySink, tyDistinct})
|
||||
if cyclicType(c.graph, t):
|
||||
result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest))
|
||||
|
||||
proc genMarkCyclic(c: var Con; result, dest: PNode) =
|
||||
if c.graph.config.selectedGC in {gcOrc, gcYrc}:
|
||||
if c.graph.config.selectedGC == gcOrc:
|
||||
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
|
||||
if cyclicType(c.graph, t):
|
||||
if t.kind == tyRef:
|
||||
result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest)
|
||||
else:
|
||||
let xenv = genBuiltin(c.graph, c.idgen, mAccessEnv, "accessEnv", dest)
|
||||
xenv.typ = getSysType(c.graph, dest.info, tyPointer)
|
||||
xenv.typ() = getSysType(c.graph, dest.info, tyPointer)
|
||||
result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, xenv)
|
||||
|
||||
proc genCopyNoCheck(c: var Con; dest, ri: PNode; a: TTypeAttachedOp): PNode =
|
||||
@@ -373,7 +371,7 @@ proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode =
|
||||
# but fields within active case branch might need destruction
|
||||
|
||||
# tmp to support self assignments
|
||||
let tmp = c.getTemp(s, n[1].typ, n.info, needsInit = false)
|
||||
let tmp = c.getTemp(s, n[1].typ, n.info)
|
||||
|
||||
result = newTree(nkStmtList)
|
||||
result.add newTree(nkFastAsgn, tmp, p(n[1], c, s, consumed))
|
||||
@@ -421,7 +419,7 @@ proc genWasMoved(c: var Con, n: PNode): PNode =
|
||||
proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
|
||||
result = newNodeI(nkCall, info)
|
||||
result.add(newSymNode(createMagic(c.graph, c.idgen, "default", mDefault)))
|
||||
result.typ = t
|
||||
result.typ() = t
|
||||
|
||||
proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
# generate: (let tmp = v; reset(v); tmp)
|
||||
@@ -459,50 +457,49 @@ proc isCapturedVar(n: PNode): bool =
|
||||
else: result = false
|
||||
|
||||
proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
let nTyp = n.typ.skipTypes(tyUserTypeClasses)
|
||||
if not hasDestructorOrAsgn(c, nTyp):
|
||||
# Non-managed (plain-old-data) type: no ownership transfer is needed.
|
||||
# Return the expression directly — no temp required.
|
||||
if c.graph.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc}:
|
||||
let tmp = c.getTemp(s, nTyp, n.info)
|
||||
if hasDestructorOrAsgn(c, nTyp):
|
||||
let typ = nTyp.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
let op = getAttachedOp(c.graph, typ, attachedDup)
|
||||
if op != nil and tfHasOwned notin typ.flags:
|
||||
if sfError in op.flags:
|
||||
c.checkForErrorPragma(nTyp, n, "=dup")
|
||||
else:
|
||||
let copyOp = getAttachedOp(c.graph, typ, attachedAsgn)
|
||||
if copyOp != nil and sfError in copyOp.flags and
|
||||
sfOverridden notin op.flags:
|
||||
c.checkForErrorPragma(nTyp, n, "=dup", inferredFromCopy = true)
|
||||
|
||||
let src = p(n, c, s, normal)
|
||||
var newCall = newTreeIT(nkCall, src.info, src.typ,
|
||||
newSymNode(op),
|
||||
src)
|
||||
c.finishCopy(newCall, n, {}, isFromSink = true)
|
||||
result.add newTreeI(nkFastAsgn,
|
||||
src.info, tmp,
|
||||
newCall
|
||||
)
|
||||
else:
|
||||
result.add c.genWasMoved(tmp)
|
||||
var m = c.genCopy(tmp, n, {})
|
||||
m.add p(n, c, s, normal)
|
||||
c.finishCopy(m, n, {}, isFromSink = true)
|
||||
result.add m
|
||||
if isLValue(n) and not isCapturedVar(n) and nTyp.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
|
||||
message(c.graph.config, n.info, hintPerformance,
|
||||
("passing '$1' to a sink parameter introduces an implicit copy; " &
|
||||
"if possible, rearrange your program's control flow to prevent it") % $n)
|
||||
if c.inEnsureMove > 0:
|
||||
localError(c.graph.config, n.info, errFailedMove,
|
||||
("cannot move '$1', passing '$1' to a sink parameter introduces an implicit copy") % $n)
|
||||
else:
|
||||
if c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
assert(not containsManagedMemory(nTyp))
|
||||
if nTyp.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
|
||||
localError(c.graph.config, n.info, "cannot create an implicit openArray copy to be passed to a sink parameter")
|
||||
return p(n, c, s, normal)
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
let tmp = c.getTemp(s, nTyp, n.info, needsInit = false)
|
||||
let typ = nTyp.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
let op = getAttachedOp(c.graph, typ, attachedDup)
|
||||
if op != nil and tfHasOwned notin typ.flags:
|
||||
if sfError in op.flags:
|
||||
c.checkForErrorPragma(nTyp, n, "=dup")
|
||||
else:
|
||||
let copyOp = getAttachedOp(c.graph, typ, attachedAsgn)
|
||||
if copyOp != nil and sfError in copyOp.flags and
|
||||
sfOverridden notin op.flags:
|
||||
c.checkForErrorPragma(nTyp, n, "=dup", inferredFromCopy = true)
|
||||
|
||||
let src = p(n, c, s, normal)
|
||||
var newCall = newTreeIT(nkCall, src.info, src.typ,
|
||||
newSymNode(op),
|
||||
src)
|
||||
c.finishCopy(newCall, n, {}, isFromSink = true)
|
||||
result.add newTreeI(nkFastAsgn,
|
||||
src.info, tmp,
|
||||
newCall
|
||||
)
|
||||
else:
|
||||
result.add c.genWasMoved(tmp)
|
||||
var m = c.genCopy(tmp, n, {})
|
||||
m.add p(n, c, s, normal)
|
||||
c.finishCopy(m, n, {}, isFromSink = true)
|
||||
result.add m
|
||||
if isLValue(n) and not isCapturedVar(n) and nTyp.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
|
||||
message(c.graph.config, n.info, hintPerformance,
|
||||
("passing '$1' to a sink parameter introduces an implicit copy; " &
|
||||
"if possible, rearrange your program's control flow to prevent it") % $n)
|
||||
if c.inEnsureMove > 0:
|
||||
localError(c.graph.config, n.info, errFailedMove,
|
||||
("cannot move '$1', passing '$1' to a sink parameter introduces an implicit copy") % $n)
|
||||
result.add newTree(nkAsgn, tmp, p(n, c, s, normal))
|
||||
# Since we know somebody will take over the produced copy, there is
|
||||
# no need to destroy it.
|
||||
result.add tmp
|
||||
@@ -533,7 +530,7 @@ proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode =
|
||||
# produce temp creation for (fn, env). But we need to move 'env'?
|
||||
# This was already done in the sink parameter handling logic.
|
||||
result = newNodeIT(nkStmtListExpr, arg.info, arg.typ)
|
||||
let tmp = c.getTemp(s, arg.typ, arg.info, true)
|
||||
let tmp = c.getTemp(s, arg.typ, arg.info)
|
||||
result.add c.genSink(s, tmp, arg, {IsDecl})
|
||||
result.add tmp
|
||||
s.final.add c.genDestroy(tmp)
|
||||
@@ -612,7 +609,7 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt
|
||||
# There is a possibility to do this check: s.wasMoved.len > 0 or s.final.len > 0
|
||||
# later and use it to eliminate the temporary when theres no need for it, but its
|
||||
# tricky because you would have to intercept moveOrCopy at a certain point
|
||||
let tmp = c.getTemp(s.parent[], ret.typ, ret.info, needsInit = true)
|
||||
let tmp = c.getTemp(s.parent[], ret.typ, ret.info)
|
||||
tmp.sym.flags = tmpFlags
|
||||
let cpy = if hasDestructor(c, ret.typ) and
|
||||
ret.typ.kind notin {tyOpenArray, tyVarargs}:
|
||||
@@ -773,7 +770,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
|
||||
result = copyNode(n)
|
||||
result.add call
|
||||
else:
|
||||
let tmp = c.getTemp(s, n[0].typ, n.info, needsInit = true)
|
||||
let tmp = c.getTemp(s, n[0].typ, n.info)
|
||||
var m = c.genCopyNoCheck(tmp, n[0], attachedAsgn)
|
||||
m.add p(n[0], c, s, normal)
|
||||
c.finishCopy(m, n[0], {}, isFromSink = false)
|
||||
@@ -828,9 +825,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
n[1].typ.skipTypes(abstractInst-{tyOwned}).kind == tyOwned:
|
||||
# allow conversions from owned to unowned via this little hack:
|
||||
let nTyp = n[1].typ
|
||||
n[1].typ = n.typ
|
||||
n[1].typ() = n.typ
|
||||
result[1] = p(n[1], c, s, sinkArg)
|
||||
result[1].typ = nTyp
|
||||
result[1].typ() = nTyp
|
||||
else:
|
||||
result[1] = p(n[1], c, s, sinkArg)
|
||||
elif n.kind in {nkObjDownConv, nkObjUpConv}:
|
||||
@@ -929,7 +926,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
|
||||
if n[0].kind == nkSym and n[0].sym.magic in {mNew, mNewFinalize}:
|
||||
result[0] = copyTree(n[0])
|
||||
if c.graph.config.selectedGC in {gcHooks, gcArc, gcAtomicArc, gcOrc, gcYrc}:
|
||||
if c.graph.config.selectedGC in {gcHooks, gcArc, gcAtomicArc, gcOrc}:
|
||||
let destroyOld = c.genDestroy(result[1])
|
||||
result = newTree(nkStmtList, destroyOld, result)
|
||||
else:
|
||||
@@ -967,7 +964,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
s.locals.add v.sym
|
||||
pVarTopLevel(v, c, s, result)
|
||||
if ri.kind != nkEmpty:
|
||||
let isGlobalPragma = v.kind == nkSym and
|
||||
let isGlobalPragma = v.kind == nkSym and
|
||||
{sfPure, sfGlobal} <= v.sym.flags and
|
||||
isInProc
|
||||
|
||||
@@ -1004,13 +1001,6 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s, flags)
|
||||
elif isDiscriminantField(n[0]):
|
||||
result = c.genDiscriminantAsgn(s, n)
|
||||
elif n[1].kind in {nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt, nkPragmaBlock}:
|
||||
# Distribute the assignment into each branch to avoid
|
||||
# creating pointless temporaries for expression-based control flow.
|
||||
let dest = p(n[0], c, s, mode)
|
||||
template process(child, s): untyped =
|
||||
newTree(n.kind, dest, p(child, c, s, consumed))
|
||||
handleNestedTempl(n[1], process, willProduceStmt = true)
|
||||
else:
|
||||
result = copyNode(n)
|
||||
result.add p(n[0], c, s, mode)
|
||||
@@ -1046,9 +1036,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
n[1].typ.skipTypes(abstractInst-{tyOwned}).kind == tyOwned:
|
||||
# allow conversions from owned to unowned via this little hack:
|
||||
let nTyp = n[1].typ
|
||||
n[1].typ = n.typ
|
||||
n[1].typ() = n.typ
|
||||
result[1] = p(n[1], c, s, mode)
|
||||
result[1].typ = nTyp
|
||||
result[1].typ() = nTyp
|
||||
else:
|
||||
result[1] = p(n[1], c, s, mode)
|
||||
|
||||
@@ -1164,8 +1154,8 @@ proc ownsData(c: var Con; s: var Scope; orig: PNode; flags: set[MoveOrCopyFlag])
|
||||
break
|
||||
if n.kind in nkCallKinds and n.typ != nil and hasDestructor(c, n.typ):
|
||||
result = newNodeIT(nkStmtListExpr, orig.info, orig.typ)
|
||||
let tmp = c.getTemp(s, n.typ, n.info, needsInit = true)
|
||||
tmp.sym.flagsImpl.incl sfSingleUsedTemp
|
||||
let tmp = c.getTemp(s, n.typ, n.info)
|
||||
tmp.sym.flags.incl sfSingleUsedTemp
|
||||
result.add newTree(nkFastAsgn, tmp, copyTree(n))
|
||||
s.final.add c.genDestroy(tmp)
|
||||
n[] = tmp[]
|
||||
@@ -1302,55 +1292,6 @@ when false:
|
||||
for i in 0..<n.safeLen:
|
||||
injectDefaultCalls(n[i], c)
|
||||
|
||||
proc replaceSinkParam(n: PNode, mapping: Table[int, PSym]): PNode =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
if n.sym.id in mapping:
|
||||
result = newSymNode(mapping[n.sym.id])
|
||||
else:
|
||||
result = n
|
||||
of nkVarSection, nkLetSection:
|
||||
result = copyNode(n)
|
||||
newSons(result, n.len)
|
||||
for i in 0..<n.len:
|
||||
result[i] = copyNode(n[i])
|
||||
for j in 0..<n[i].len-1:
|
||||
result[i].add n[i][j]
|
||||
result[i].add replaceSinkParam(n[i][^1], mapping)
|
||||
of {nkNone..nkNilLit}-{nkSym}, nkTypeSection, nkProcDef, nkConverterDef,
|
||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
|
||||
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
|
||||
result = n
|
||||
else:
|
||||
result = copyNode(n)
|
||||
for i in 0..<n.len:
|
||||
result.add replaceSinkParam(n[i], mapping)
|
||||
|
||||
proc addSinkCopy(c: var Con; s: var Scope; sinkParams: seq[PSym]; n: PNode): PNode =
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
var mapping = initTable[int, PSym]()
|
||||
|
||||
var mutated = newSeq[PNode]()
|
||||
getPotentialWrites(n, false, mutated)
|
||||
var mutatedSet = initIntSet()
|
||||
for m in mutated:
|
||||
mutatedSet.incl m.sym.id
|
||||
for param in sinkParams:
|
||||
if param.id in mutatedSet:
|
||||
let newSym = newSym(skTemp, getIdent(c.graph.cache, "sinkCopy"), c.idgen, param.owner, n.info)
|
||||
newSym.flagsImpl.incl sfFromGeneric
|
||||
newSym.typ = param.typ.elementType
|
||||
mapping[param.id] = newSym
|
||||
let v = newNodeI(nkVarSection, n.info)
|
||||
v.addVar(newSymNode(newSym), newSymNode(param))
|
||||
result.add v
|
||||
if mapping.len > 0:
|
||||
result.add replaceSinkParam(n, mapping)
|
||||
else:
|
||||
result = n
|
||||
|
||||
proc injectDestructorCalls*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n: PNode): PNode =
|
||||
when toDebug.len > 0:
|
||||
shouldDebug = toDebug == owner.name.s or toDebug == "always"
|
||||
@@ -1364,24 +1305,15 @@ proc injectDestructorCalls*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n:
|
||||
var scope = Scope(body: n)
|
||||
let body = p(n, c, scope, normal)
|
||||
|
||||
var sinkParams = newSeq[PSym]()
|
||||
|
||||
if owner.kind in {skProc, skFunc, skMethod, skIterator, skConverter}:
|
||||
let params = owner.typ.n
|
||||
for i in 1..<params.len:
|
||||
let t = params[i].sym.typ
|
||||
if isSinkTypeForParam(t):
|
||||
let baseType = t.skipTypes({tySink})
|
||||
if baseType.kind in {tyString, tySequence, tyArray, tyTuple, tyObject}:
|
||||
sinkParams.add params[i].sym
|
||||
if hasDestructor(c, baseType):
|
||||
scope.final.add c.genDestroy(params[i])
|
||||
if isSinkTypeForParam(t) and hasDestructor(c, t.skipTypes({tySink})):
|
||||
scope.final.add c.genDestroy(params[i])
|
||||
#if optNimV2 in c.graph.config.globalOptions:
|
||||
# injectDefaultCalls(n, c)
|
||||
result = optimize processScope(c, scope, body)
|
||||
if sinkParams.len > 0:
|
||||
result = addSinkCopy(c, scope, sinkParams, result)
|
||||
|
||||
dbg:
|
||||
echo ">---------transformed-to--------->"
|
||||
echo renderTree(result, {renderIds})
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
|
||||
proc copySymdef(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerator; owner: PSym): PNode =
|
||||
case n.kind
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||
result = n
|
||||
of nkSym:
|
||||
let oldSym = n.sym
|
||||
let newSym = copySym(oldSym, idgen)
|
||||
setOwner(newSym, owner)
|
||||
locals[oldSym.id] = newSym
|
||||
result = newSymNode(newSym, oldSym.info)
|
||||
else:
|
||||
result = shallowCopy(n)
|
||||
for i in 0..<n.len:
|
||||
result[i] = copySymdef(n[i], locals, idgen, owner)
|
||||
|
||||
proc copyInlineProcBody(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerator; owner: PSym): PNode =
|
||||
case n.kind
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||
result = n
|
||||
of nkSym:
|
||||
let sym = locals.getOrDefault(n.sym.id)
|
||||
if sym != nil:
|
||||
result = newSymNode(sym, n.info)
|
||||
else:
|
||||
result = n
|
||||
of nkLetSection, nkVarSection:
|
||||
result = shallowCopy(n)
|
||||
for i in 0..<n.len:
|
||||
let it = n[i]
|
||||
if it.kind == nkCommentStmt:
|
||||
result[i] = it
|
||||
elif it.kind in {nkIdentDefs, nkConstDef}:
|
||||
result[i] = shallowCopy(it)
|
||||
for j in 0..<it.len-2:
|
||||
result[i][j] = copySymdef(it[j], locals, idgen, owner)
|
||||
for j in it.len-2..<it.len:
|
||||
result[i][j] = copyInlineProcBody(it[j], locals, idgen, owner)
|
||||
else:
|
||||
assert it.kind == nkVarTuple
|
||||
result[i] = shallowCopy(it)
|
||||
for j in 0..<it.len-2:
|
||||
assert it[j].kind == nkSym
|
||||
let oldSym = it[j].sym
|
||||
let newSym = copySym(oldSym, idgen)
|
||||
setOwner(newSym, owner)
|
||||
locals[oldSym.id] = newSym
|
||||
result[i][j] = newSymNode(newSym, oldSym.info)
|
||||
for j in it.len-2..<it.len:
|
||||
result[i][j] = copyInlineProcBody(it[j], locals, idgen, owner)
|
||||
|
||||
of nkForStmt, nkParForStmt:
|
||||
result = shallowCopy(n)
|
||||
for i in 0..<n.len-2:
|
||||
assert n[i].kind == nkSym
|
||||
let oldSym = n[i].sym
|
||||
let newSym = copySym(oldSym, idgen)
|
||||
setOwner(newSym, owner)
|
||||
locals[oldSym.id] = newSym
|
||||
result[i] = newSymNode(newSym, oldSym.info)
|
||||
result[n.len-2] = copyInlineProcBody(n[n.len-2], locals, idgen, owner)
|
||||
result[n.len-1] = copyInlineProcBody(n[n.len-1], locals, idgen, owner)
|
||||
of routineDefs, nkTypeSection, nkTypeOfExpr, nkMixinStmt, nkBindStmt, nkConstSection:
|
||||
result = n
|
||||
else:
|
||||
result = shallowCopy(n)
|
||||
for i in 0..<n.len:
|
||||
result[i] = copyInlineProcBody(n[i], locals, idgen, owner)
|
||||
|
||||
proc copyParams(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerator; owner: PSym): PNode =
|
||||
result = shallowCopy(n)
|
||||
result[0] = n[0] # return type
|
||||
for i in 1..<n.len:
|
||||
let it = n[i]
|
||||
assert it.kind == nkIdentDefs
|
||||
result[i] = shallowCopy(it)
|
||||
for j in 0..<it.len-2:
|
||||
assert it[j].kind == nkSym
|
||||
let oldSym = it[j].sym
|
||||
let newSym = copySym(oldSym, idgen)
|
||||
setOwner(newSym, owner)
|
||||
locals[oldSym.id] = newSym
|
||||
result[i][j] = newSymNode(newSym, oldSym.info)
|
||||
owner.typ.addParam newSym
|
||||
for j in it.len-2..<it.len:
|
||||
result[i][j] = copyInlineProcBody(it[j], locals, idgen, owner)
|
||||
|
||||
proc copyInlineProc(prc: PSym; idgen: IdGenerator): PSym =
|
||||
result = copySym(prc, idgen)
|
||||
var locals = initTable[int, PSym]()
|
||||
|
||||
var a = shallowCopy(prc.ast)
|
||||
if resultPos < prc.ast.len and prc.ast[resultPos].kind == nkSym:
|
||||
let oldRes = prc.ast[resultPos].sym
|
||||
let newRes = copySym(oldRes, idgen)
|
||||
setOwner(newRes, result)
|
||||
locals[oldRes.id] = newRes
|
||||
a[resultPos] = newSymNode(newRes, oldRes.info)
|
||||
|
||||
result.typ = copyType(prc.typ, idgen, result)
|
||||
result.typ.n = newNodeI(prc.typ.n.kind, prc.typ.n.info)
|
||||
if prc.typ.n.len > 0:
|
||||
result.typ.n.add copyNode(prc.typ.n[0])
|
||||
for i in 1..<prc.typ.n.len:
|
||||
let it = prc.typ.n[i]
|
||||
assert it.kind == nkSym
|
||||
let oldSym = it.sym
|
||||
let newSym = copySym(oldSym, idgen)
|
||||
setOwner(newSym, result)
|
||||
locals[oldSym.id] = newSym
|
||||
result.typ.addParam newSym
|
||||
|
||||
for i in 0..<prc.ast.len:
|
||||
if i == paramsPos:
|
||||
a[i] = copyTree(prc.ast[i])
|
||||
elif i == resultPos and prc.ast[i].kind == nkSym:
|
||||
discard "handled above"
|
||||
else:
|
||||
a[i] = copyInlineProcBody(prc.ast[i], locals, idgen, result)
|
||||
result.ast = a
|
||||
|
||||
#echo "Produced: ", renderTree(result.ast, {renderIds})
|
||||
@@ -80,7 +80,6 @@ Files: "lib"
|
||||
Files: "examples"
|
||||
Files: "dist/nimble"
|
||||
Files: "dist/checksums"
|
||||
Files: "dist/nimony"
|
||||
|
||||
Files: "tests"
|
||||
|
||||
|
||||
@@ -460,9 +460,7 @@ proc addInt128*(result: var string; value: Int128) =
|
||||
var i = initialSize
|
||||
var j = high(result)
|
||||
while i < j:
|
||||
let tmp = result[i]
|
||||
result[i] = result[j]
|
||||
result[j] = tmp
|
||||
swap(result[i], result[j])
|
||||
i += 1
|
||||
j -= 1
|
||||
|
||||
|
||||
@@ -277,8 +277,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
|
||||
else:
|
||||
result.add("_")
|
||||
result.add(rope(s.id))
|
||||
ensureMutable s
|
||||
s.locImpl.snippet = result
|
||||
s.loc.snippet = result
|
||||
|
||||
proc escapeJSString(s: string): string =
|
||||
result = newStringOfCap(s.len + s.len shr 2)
|
||||
@@ -1006,8 +1005,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||
# If some branch requires a local alias introduce it here. This is needed
|
||||
# since JS cannot do ``catch x as y``.
|
||||
if excAlias != nil:
|
||||
ensureMutable excAlias.sym
|
||||
excAlias.sym.locImpl.snippet = mangleName(p.module, excAlias.sym)
|
||||
excAlias.sym.loc.snippet = mangleName(p.module, excAlias.sym)
|
||||
lineF(p, "var $1 = lastJSError;$n", excAlias.sym.loc.snippet)
|
||||
gen(p, n[i][^1], a)
|
||||
moveInto(p, a, r)
|
||||
@@ -1140,8 +1138,7 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
|
||||
# named block?
|
||||
if (n[0].kind != nkSym): internalError(p.config, n.info, "genBlock")
|
||||
var sym = n[0].sym
|
||||
ensureMutable sym
|
||||
sym.locImpl.k = locOther
|
||||
sym.loc.k = locOther
|
||||
sym.position = idx+1
|
||||
let labl = p.unique
|
||||
lineF(p, "Label$1: {$n", [labl.rope])
|
||||
@@ -1240,8 +1237,7 @@ proc generateHeader(p: PProc, prc: PSym): Rope =
|
||||
# to keep it simple
|
||||
let env = prc.ast[paramsPos].lastSon
|
||||
assert env.kind == nkSym, "env is missing"
|
||||
ensureMutable env.sym
|
||||
env.sym.locImpl.snippet = "this"
|
||||
env.sym.loc.snippet = "this"
|
||||
|
||||
for i in 1..<typ.n.len:
|
||||
assert(typ.n[i].kind == nkSym)
|
||||
@@ -1384,9 +1380,7 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
else:
|
||||
if b[1].kind != nkSym: internalError(p.config, b[1].info, "genFieldAddr")
|
||||
var f = b[1].sym
|
||||
if f.loc.snippet == "":
|
||||
ensureMutable f
|
||||
f.locImpl.snippet = mangleName(p.module, f)
|
||||
if f.loc.snippet == "": f.loc.snippet = mangleName(p.module, f)
|
||||
r.res = makeJSString($f.loc.snippet)
|
||||
internalAssert p.config, a.typ != etyBaseIndex
|
||||
r.address = a.res
|
||||
@@ -1414,9 +1408,7 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
|
||||
else:
|
||||
if n[1].kind != nkSym: internalError(p.config, n[1].info, "genFieldAccess")
|
||||
var f = n[1].sym
|
||||
if f.loc.snippet == "":
|
||||
ensureMutable f
|
||||
f.locImpl.snippet = mangleName(p.module, f)
|
||||
if f.loc.snippet == "": f.loc.snippet = mangleName(p.module, f)
|
||||
r.res = "$1.$2" % [r.res, f.loc.snippet]
|
||||
mkTemp(1)
|
||||
r.kind = resExpr
|
||||
@@ -1437,15 +1429,11 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
|
||||
# Field symbol
|
||||
var field = accessExpr[1].sym
|
||||
internalAssert p.config, field.kind == skField
|
||||
if field.loc.snippet == "":
|
||||
ensureMutable field
|
||||
field.locImpl.snippet = mangleName(p.module, field)
|
||||
if field.loc.snippet == "": field.loc.snippet = mangleName(p.module, field)
|
||||
# Discriminant symbol
|
||||
let disc = checkExpr[2].sym
|
||||
internalAssert p.config, disc.kind == skField
|
||||
if disc.loc.snippet == "":
|
||||
ensureMutable disc
|
||||
disc.locImpl.snippet = mangleName(p.module, disc)
|
||||
if disc.loc.snippet == "": disc.loc.snippet = mangleName(p.module, disc)
|
||||
|
||||
var setx: TCompRes = default(TCompRes)
|
||||
gen(p, checkExpr[1], setx)
|
||||
@@ -1544,7 +1532,7 @@ proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) =
|
||||
r.res = s.loc.snippet
|
||||
r.address = ""
|
||||
r.typ = etyNone
|
||||
of skVar, skLet, skResult, skTemp, skForVar:
|
||||
of skVar, skLet, skResult:
|
||||
r.kind = resExpr
|
||||
let jsType = mapType(p):
|
||||
if typ.isNil:
|
||||
@@ -1857,9 +1845,7 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
|
||||
proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||
# don't call '$' here for efficiency:
|
||||
let f = n[0].sym
|
||||
if f.loc.snippet == "":
|
||||
ensureMutable f
|
||||
f.locImpl.snippet = mangleName(p.module, f)
|
||||
if f.loc.snippet == "": f.loc.snippet = mangleName(p.module, f)
|
||||
if sfInfixCall in f.flags:
|
||||
let pat = $n[0].sym.loc.snippet
|
||||
internalAssert p.config, pat.len > 0
|
||||
@@ -2018,12 +2004,8 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
if indirect: result = "[$1]" % [result]
|
||||
of tyTuple:
|
||||
result = rope("{")
|
||||
var first = true
|
||||
for i in 0..<t.len:
|
||||
# Do not produce code for void types
|
||||
if isEmptyType(t[i]): continue
|
||||
if not first: result.add(", ")
|
||||
first = false
|
||||
if i > 0: result.add(", ")
|
||||
result.addf("Field$1: $2", [i.rope,
|
||||
createVar(p, t[i], false)])
|
||||
result.add("}")
|
||||
@@ -2599,9 +2581,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
let val = it[1]
|
||||
gen(p, val, a)
|
||||
var f = it[0].sym
|
||||
if f.loc.snippet == "":
|
||||
ensureMutable f
|
||||
f.locImpl.snippet = mangleName(p.module, f)
|
||||
if f.loc.snippet == "": f.loc.snippet = mangleName(p.module, f)
|
||||
fieldIDs.incl(lookupFieldAgain(n.typ.skipTypes({tyDistinct}), f).id)
|
||||
|
||||
let typ = val.typ.skipTypes(abstractInst)
|
||||
|
||||
@@ -150,7 +150,7 @@ template isIterator*(owner: PSym): bool =
|
||||
|
||||
proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType =
|
||||
result = createObj(g, idgen, owner, info, final=false)
|
||||
result.incl tfFinal
|
||||
result.flags.incl tfFinal
|
||||
if owner.isIterator:
|
||||
rawAddField(result, createStateField(g, owner, idgen))
|
||||
|
||||
@@ -161,7 +161,7 @@ proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym
|
||||
# XXX a bit hacky:
|
||||
result = newSym(skResult, getIdent(g.cache, ":result"), idgen, iter, iter.info, {})
|
||||
result.typ = iter.typ.returnType
|
||||
incl(result.flagsImpl, sfUsed)
|
||||
incl(result.flags, sfUsed)
|
||||
iter.ast.add newSymNode(result)
|
||||
|
||||
proc addHiddenParam(routine: PSym, param: PSym) =
|
||||
@@ -216,10 +216,6 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
|
||||
result[0] = le
|
||||
result[1] = ri
|
||||
|
||||
proc markInjectDestructors(s: PSym) {.inline.} =
|
||||
backendEnsureMutable s
|
||||
s.flagsImpl.incl sfInjectDestructors
|
||||
|
||||
proc makeClosure*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; env: PNode; info: TLineInfo): PNode =
|
||||
result = newNodeIT(nkClosure, info, prc.typ)
|
||||
result.add(newSymNode(prc))
|
||||
@@ -232,7 +228,7 @@ proc makeClosure*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; env: PNode; inf
|
||||
#if isClosureIterator(result.typ):
|
||||
createTypeBoundOps(g, nil, result.typ, info, idgen)
|
||||
if tfHasAsgn in result.typ.flags or optSeqDestructors in g.config.globalOptions:
|
||||
markInjectDestructors(prc)
|
||||
prc.flags.incl sfInjectDestructors
|
||||
|
||||
template liftingHarmful(conf: ConfigRef; owner: PSym): bool =
|
||||
## lambda lifting can be harmful for JS-like code generators.
|
||||
@@ -244,7 +240,7 @@ proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; idgen
|
||||
createTypeBoundOps(g, nil, refType.elementType, info, idgen)
|
||||
createTypeBoundOps(g, nil, refType, info, idgen)
|
||||
if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions:
|
||||
markInjectDestructors(owner)
|
||||
owner.flags.incl sfInjectDestructors
|
||||
|
||||
proc genCreateEnv(env: PNode): PNode =
|
||||
var c = newNodeIT(nkObjConstr, env.info, env.typ)
|
||||
@@ -294,7 +290,7 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
|
||||
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, tfCapturesEnv)
|
||||
incl(owner.typ.flags, tfCapturesEnv)
|
||||
if not isEnv:
|
||||
owner.typ.callConv = ccClosure
|
||||
|
||||
@@ -340,7 +336,7 @@ proc asOwnedRef(c: var DetectionPass; t: PType): PType =
|
||||
if optOwnedRefs in c.graph.config.globalOptions:
|
||||
assert t.kind == tyRef
|
||||
result = newType(tyOwned, c.idgen, t.owner)
|
||||
result.incl tfHasOwned
|
||||
result.flags.incl tfHasOwned
|
||||
result.rawAddSon t
|
||||
else:
|
||||
result = t
|
||||
@@ -412,29 +408,17 @@ Consider:
|
||||
proc isTypeOf(n: PNode): bool =
|
||||
n.kind == nkSym and n.sym.magic in {mTypeOf, mType}
|
||||
|
||||
proc isEnvTypeForRoutine(envTyp: PType; routine: PSym): bool =
|
||||
## True if `envTyp` is (maybe wrapped) env object type owned by `routine`, as
|
||||
## created by `getEnvTypeForOwner` / `createEnvObj`.
|
||||
let obj = envTyp.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
result = obj.kind == tyObject and obj.owner.id == routine.id
|
||||
|
||||
proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
|
||||
var cp = getEnvParam(fn)
|
||||
let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner
|
||||
let t = c.getEnvTypeForOwner(owner, info)
|
||||
if cp == nil:
|
||||
cp = newSym(skParam, getIdent(c.graph.cache, paramName), c.idgen, fn, fn.info)
|
||||
incl(cp.flagsImpl, sfFromGeneric)
|
||||
incl(cp.flags, sfFromGeneric)
|
||||
cp.typ = t
|
||||
addHiddenParam(fn, cp)
|
||||
elif cp.typ != t and fn.kind != skIterator:
|
||||
# Nested `liftLambdas` uses a fresh `DetectionPass`, so `getEnvTypeForOwner`
|
||||
# can allocate another PType for the same logical env; the hidden param from
|
||||
# the inner pass is authoritative (bug #21242).
|
||||
if isEnvTypeForRoutine(cp.typ, owner) and isEnvTypeForRoutine(t, owner):
|
||||
c.ownerToType[owner.id] = cp.typ
|
||||
else:
|
||||
localError(c.graph.config, fn.info, "internal error: inconsistent environment type")
|
||||
localError(c.graph.config, fn.info, "internal error: inconsistent environment type")
|
||||
#echo "adding closure to ", fn.name.s
|
||||
|
||||
proc iterEnvHasUpField(g: ModuleGraph, iter: PSym): bool =
|
||||
@@ -626,7 +610,7 @@ proc rawClosureCreation(owner: PSym;
|
||||
let unowned = c.unownedEnvVars[owner.id]
|
||||
assert unowned != nil
|
||||
let env2 = copyTree(env)
|
||||
env2.typ = unowned.typ
|
||||
env2.typ() = unowned.typ
|
||||
result.add newAsgnStmt(unowned, env2, env.info)
|
||||
createTypeBoundOpsLL(d.graph, unowned.typ, env.info, d.idgen, owner)
|
||||
|
||||
@@ -640,7 +624,7 @@ proc rawClosureCreation(owner: PSym;
|
||||
if owner.kind != skMacro:
|
||||
createTypeBoundOps(d.graph, nil, fieldAccess.typ, env.info, d.idgen)
|
||||
if tfHasAsgn in fieldAccess.typ.flags or optSeqDestructors in d.graph.config.globalOptions:
|
||||
markInjectDestructors(owner)
|
||||
owner.flags.incl sfInjectDestructors
|
||||
|
||||
let upField = lookupInRecord(env.typ.skipTypes({tyOwned, tyRef, tyPtr}).n, getIdent(d.graph.cache, upName))
|
||||
if upField != nil:
|
||||
@@ -682,7 +666,7 @@ proc closureCreationForIter(owner: PSym, iter: PNode;
|
||||
result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ)
|
||||
let iterOwner = iter.sym.skipGenericOwner
|
||||
var v = newSym(skVar, getIdent(d.graph.cache, envName), d.idgen, iterOwner, iter.info)
|
||||
incl(v.flagsImpl, sfShadowed)
|
||||
incl(v.flags, sfShadowed)
|
||||
v.typ = asOwnedRef(d, getHiddenParam(d.graph, iter.sym).typ)
|
||||
var vnode: PNode
|
||||
if iterOwner.isIterator:
|
||||
@@ -803,7 +787,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
|
||||
let oldInContainer = c.inContainer
|
||||
c.inContainer = 0
|
||||
let m = newSymNode(n[namePos].sym)
|
||||
m.typ = n.typ
|
||||
m.typ() = n.typ
|
||||
result = liftCapturedVars(m, owner, d, c)
|
||||
c.inContainer = oldInContainer
|
||||
of nkHiddenStdConv:
|
||||
|
||||
@@ -46,11 +46,12 @@ proc setToPreviousLayer*(pt: var LayeredIdTable) {.inline.} =
|
||||
when useRef:
|
||||
pt = pt.nextLayer
|
||||
else:
|
||||
# Must read nextLayer into a temp before destroying pt:
|
||||
# `pt = pt.nextLayer[]` would call eqcopy(&pt, &(*pt.nextLayer)) which
|
||||
# decrements pt.nextLayer's rc (freeing it) before reading pt.nextLayer.nextLayer.
|
||||
let tmp = pt.nextLayer[]
|
||||
pt = tmp
|
||||
when defined(gcDestructors):
|
||||
pt = pt.nextLayer[]
|
||||
else:
|
||||
# workaround refc
|
||||
let tmp = pt.nextLayer[]
|
||||
pt = tmp
|
||||
|
||||
iterator pairs*(pt: LayeredIdTable): (ItemId, PType) =
|
||||
var tm = pt
|
||||
|
||||
@@ -1349,7 +1349,7 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
|
||||
lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier")
|
||||
of '-':
|
||||
if L.buf[L.bufpos+1] in {'0'..'9'} and
|
||||
(L.bufpos == 0 or L.buf[L.bufpos-1] in UnaryMinusWhitelist):
|
||||
(L.bufpos-1 == 0 or L.buf[L.bufpos-1] in UnaryMinusWhitelist):
|
||||
# x)-23 # binary minus
|
||||
# ,-23 # unary minus
|
||||
# \n-78 # unary minus? Yes.
|
||||
|
||||
@@ -49,7 +49,7 @@ proc at(a, i: PNode, elemType: PType): PNode =
|
||||
result = newNodeI(nkBracketExpr, a.info, 2)
|
||||
result[0] = a
|
||||
result[1] = i
|
||||
result.typ = elemType
|
||||
result.typ() = elemType
|
||||
|
||||
proc destructorOverridden(g: ModuleGraph; t: PType): bool =
|
||||
let op = getAttachedOp(g, t, attachedDestructor)
|
||||
@@ -68,7 +68,7 @@ proc dotField(x: PNode, f: PSym): PNode =
|
||||
else:
|
||||
result[0] = x
|
||||
result[1] = newSymNode(f, x.info)
|
||||
result.typ = f.typ
|
||||
result.typ() = f.typ
|
||||
|
||||
proc newAsgnStmt(le, ri: PNode): PNode =
|
||||
result = newNodeI(nkAsgn, le.info, 2)
|
||||
@@ -88,7 +88,7 @@ proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.add newAsgnStmt(x, y)
|
||||
elif c.kind == attachedDestructor and c.addMemReset:
|
||||
let call = genBuiltin(c, mDefault, "default", x)
|
||||
call.typ = t
|
||||
call.typ() = t
|
||||
body.add newAsgnStmt(x, call)
|
||||
elif c.kind == attachedWasMoved:
|
||||
body.add genBuiltin(c, mWasMoved, "wasMoved", x)
|
||||
@@ -105,7 +105,7 @@ proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
|
||||
result = newNodeI(nkWhileStmt, c.info, 2)
|
||||
let cmp = genBuiltin(c, mLtI, "<", i)
|
||||
cmp.add genLen(c.g, dest)
|
||||
cmp.typ = getSysType(c.g, c.info, tyBool)
|
||||
cmp.typ() = getSysType(c.g, c.info, tyBool)
|
||||
result[0] = cmp
|
||||
result[1] = newNodeI(nkStmtList, c.info)
|
||||
|
||||
@@ -127,10 +127,10 @@ proc genContainerOf(c: var TLiftCtx; objType: PType, field, x: PSym): PNode =
|
||||
dotExpr.add newSymNode(field)
|
||||
|
||||
let offsetOf = genBuiltin(c, mOffsetOf, "offsetof", dotExpr)
|
||||
offsetOf.typ = intType
|
||||
offsetOf.typ() = intType
|
||||
|
||||
let minusExpr = genBuiltin(c, mSubI, "-", castExpr1)
|
||||
minusExpr.typ = intType
|
||||
minusExpr.typ() = intType
|
||||
minusExpr.add offsetOf
|
||||
|
||||
let objPtr = makePtrType(objType.owner, objType, c.idgen)
|
||||
@@ -163,7 +163,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool,
|
||||
if c.filterDiscriminator != nil: return
|
||||
let f = n.sym
|
||||
let b = if c.kind == attachedTrace: y else: y.dotField(f)
|
||||
if (sfCursor in f.flags and c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc, gcHooks}) or
|
||||
if (sfCursor in f.flags and c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
|
||||
enforceDefaultOp:
|
||||
defaultOp(c, f.typ, body, x.dotField(f), b)
|
||||
else:
|
||||
@@ -280,11 +280,11 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
|
||||
# because the wasMoved(dest) call would zero out src, if dest aliases src.
|
||||
var cond = newTree(nkCall, newSymNode(c.g.getSysMagic(c.info, "==", mEqRef)),
|
||||
newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x), newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y))
|
||||
cond.typ = getSysType(c.g, x.info, tyBool)
|
||||
cond.typ() = getSysType(c.g, x.info, tyBool)
|
||||
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
|
||||
temp.typ = x.typ
|
||||
incl(temp, sfFromGeneric)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
var v = newNodeI(nkVarSection, c.info)
|
||||
let blob = newSymNode(temp)
|
||||
v.addVar(blob, x)
|
||||
@@ -312,7 +312,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
|
||||
|
||||
proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
|
||||
result = newIntLit(g, info, ord value)
|
||||
result.typ = getSysType(g, info, tyBool)
|
||||
result.typ() = getSysType(g, info, tyBool)
|
||||
|
||||
proc getCycleParam(c: TLiftCtx): PNode =
|
||||
assert c.kind in {attachedAsgn, attachedDup}
|
||||
@@ -397,8 +397,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
if op != nil and op != c.fn and
|
||||
(sfOverridden in op.flags or destructorOverridden):
|
||||
if sfError in op.flags:
|
||||
ensureMutable c.fn
|
||||
incl c.fn.flagsImpl, sfError
|
||||
incl c.fn.flags, sfError
|
||||
#else:
|
||||
# markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op)
|
||||
@@ -424,8 +423,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
if op == nil:
|
||||
op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen)
|
||||
if sfError in op.flags:
|
||||
ensureMutable c.fn
|
||||
incl c.fn.flagsImpl, sfError
|
||||
incl c.fn.flags, sfError
|
||||
#else:
|
||||
# markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op)
|
||||
@@ -541,7 +539,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
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)
|
||||
temp.typ = getSysType(c.g, body.info, tyInt)
|
||||
incl(temp.flagsImpl, sfFromGeneric)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
|
||||
var v = newNodeI(nkVarSection, c.info)
|
||||
result = newSymNode(temp)
|
||||
@@ -551,29 +549,13 @@ proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
|
||||
proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode =
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
|
||||
temp.typ = value.typ
|
||||
incl(temp.flagsImpl, sfFromGeneric)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
|
||||
var v = newNodeI(nkVarSection, c.info)
|
||||
result = newSymNode(temp)
|
||||
v.addVar(result, value)
|
||||
body.add v
|
||||
|
||||
proc considerInferDupFromCopy(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
## For `=dup`, if no explicit hook exists, try to infer from `=copy` hook
|
||||
## to maintain backward compatibility. Returns true if inference was applied.
|
||||
if c.kind == attachedDup:
|
||||
var op2 = getAttachedOp(c.g, t, attachedAsgn)
|
||||
if op2 != nil and sfOverridden in op2.flags:
|
||||
#markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op2)
|
||||
body.add genBuiltin(c, mWasMoved, "wasMoved", x)
|
||||
body.add newHookCall(c, op2, x, y)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
|
||||
let incCall = genBuiltin(c, mInc, "inc", i)
|
||||
incCall.add lowerings.newIntLit(c.g, c.info, 1)
|
||||
@@ -583,21 +565,19 @@ proc newSeqCall(c: var TLiftCtx; x, y: PNode): PNode =
|
||||
# don't call genAddr(c, x) here:
|
||||
result = genBuiltin(c, mNewSeq, "newSeq", x)
|
||||
let lenCall = genBuiltin(c, mLengthSeq, "len", y)
|
||||
lenCall.typ = getSysType(c.g, x.info, tyInt)
|
||||
lenCall.typ() = getSysType(c.g, x.info, tyInt)
|
||||
result.add lenCall
|
||||
|
||||
proc setLenStrCall(c: var TLiftCtx; x, y: PNode): PNode =
|
||||
let lenCall = genBuiltin(c, mLengthStr, "len", y)
|
||||
lenCall.typ = getSysType(c.g, x.info, tyInt)
|
||||
lenCall.typ() = getSysType(c.g, x.info, tyInt)
|
||||
result = genBuiltin(c, mSetLengthStr, "setLen", x) # genAddr(g, x))
|
||||
result.add lenCall
|
||||
|
||||
proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode; noinit = false): PNode =
|
||||
proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode =
|
||||
let lenCall = genBuiltin(c, mLengthSeq, "len", y)
|
||||
lenCall.typ = getSysType(c.g, x.info, tyInt)
|
||||
let name = if noinit: "setLenUninit" else: "setLen"
|
||||
let magic = if noinit: mSetLengthSeqUninit else: mSetLengthSeq
|
||||
var op = getSysMagic(c.g, x.info, name, magic)
|
||||
lenCall.typ() = getSysType(c.g, x.info, tyInt)
|
||||
var op = getSysMagic(c.g, x.info, "setLen", mSetLengthSeq)
|
||||
op = instantiateGeneric(c, op, t, t)
|
||||
result = newTree(nkCall, newSymNode(op, x.info), x, lenCall)
|
||||
|
||||
@@ -619,38 +599,14 @@ proc checkSelfAssignment(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
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)
|
||||
cond.typ() = getSysType(c.g, c.info, tyBool)
|
||||
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
|
||||
|
||||
proc genBulkCopySeq(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
## Generates a call to nimCopySeqPayload for bulk memcpy of seq data.
|
||||
let elemType = t.elementType
|
||||
let sym = magicsys.getCompilerProc(c.g, "nimCopySeqPayload")
|
||||
if sym == nil:
|
||||
localError(c.g.config, c.info, "system module needs: nimCopySeqPayload")
|
||||
return
|
||||
var sizeOf = genBuiltin(c, mSizeOf, "sizeof", newNodeIT(nkType, c.info, elemType))
|
||||
sizeOf.typ = getSysType(c.g, c.info, tyInt)
|
||||
var alignOf = genBuiltin(c, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType))
|
||||
alignOf.typ = getSysType(c.g, c.info, tyInt)
|
||||
let call = newNodeI(nkCall, c.info)
|
||||
call.add newSymNode(sym)
|
||||
call.add newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x)
|
||||
call.add newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y)
|
||||
call.add sizeOf
|
||||
call.add alignOf
|
||||
call.typ = sym.typ.returnType
|
||||
body.add call
|
||||
|
||||
proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case c.kind
|
||||
of attachedDup:
|
||||
let bulkCopy = supportsCopyMem(t.elementType)
|
||||
body.add setLenSeqCall(c, t, x, y, noinit = bulkCopy)
|
||||
if bulkCopy:
|
||||
genBulkCopySeq(c, t, body, x, y)
|
||||
else:
|
||||
forallElements(c, t, body, x, y)
|
||||
body.add setLenSeqCall(c, t, x, y)
|
||||
forallElements(c, t, body, x, y)
|
||||
of attachedAsgn, attachedDeepCopy:
|
||||
# we generate:
|
||||
# if x.p == y.p:
|
||||
@@ -659,14 +615,9 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
# var i = 0
|
||||
# while i < y.len: dest[i] = y[i]; inc(i)
|
||||
# This is usually more efficient than a destroy/create pair.
|
||||
# For trivially copyable types, use bulk copyMem instead of element loop.
|
||||
checkSelfAssignment(c, t, body, x, y)
|
||||
let bulkCopy = supportsCopyMem(t.elementType)
|
||||
body.add setLenSeqCall(c, t, x, y, noinit = bulkCopy)
|
||||
if bulkCopy:
|
||||
genBulkCopySeq(c, t, body, x, y)
|
||||
else:
|
||||
forallElements(c, t, body, x, y)
|
||||
body.add setLenSeqCall(c, t, x, y)
|
||||
forallElements(c, t, body, x, y)
|
||||
of attachedSink:
|
||||
let moveCall = genBuiltin(c, mMove, "move", x)
|
||||
moveCall.add y
|
||||
@@ -732,18 +683,11 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of attachedAsgn, attachedDeepCopy, attachedDup:
|
||||
body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c, x), y)
|
||||
of attachedSink:
|
||||
if c.g.config.usesSso():
|
||||
# SmallString: destroy old dst, then bit-copy src (no rc increment — this is a move).
|
||||
# No .p aliasing check needed; rc-based destroy handles COW sharing correctly.
|
||||
doAssert t.destructor != nil
|
||||
body.add destructorCall(c, t.destructor, x)
|
||||
body.add newAsgnStmt(x, y)
|
||||
else:
|
||||
let moveCall = genBuiltin(c, mMove, "move", x)
|
||||
moveCall.add y
|
||||
doAssert t.destructor != nil
|
||||
moveCall.add destructorCall(c, t.destructor, x)
|
||||
body.add moveCall
|
||||
let moveCall = genBuiltin(c, mMove, "move", x)
|
||||
moveCall.add y
|
||||
doAssert t.destructor != nil
|
||||
moveCall.add destructorCall(c, t.destructor, x)
|
||||
body.add moveCall
|
||||
of attachedDestructor:
|
||||
body.add genBuiltin(c, mDestroy, "destroy", x)
|
||||
of attachedTrace:
|
||||
@@ -775,43 +719,14 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
dest[] = source
|
||||
decRef tmp
|
||||
|
||||
For YRC the write barrier is more complicated still and must be:
|
||||
|
||||
let tmp = dest
|
||||
# assignment must come first so that the collector sees the most-recent graph:
|
||||
atomic: dest[] = source
|
||||
# Then teach the cycle collector about the changes edge (these use locks, see yrc.nim):
|
||||
incRef source
|
||||
decRef tmp
|
||||
|
||||
This is implemented as a single runtime call (nimAsgnYrc / nimSinkYrc).
|
||||
]#
|
||||
var actions = newNodeI(nkStmtList, c.info)
|
||||
let elemType = t.elementType
|
||||
|
||||
createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen)
|
||||
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(c.g, elemType)
|
||||
|
||||
# YRC uses dedicated runtime procs for the entire write barrier:
|
||||
if c.g.config.selectedGC == gcYrc:
|
||||
let desc =
|
||||
if isFinal(elemType):
|
||||
let ti = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
|
||||
ti.typ = getSysType(c.g, c.info, tyPointer)
|
||||
ti
|
||||
else:
|
||||
newNodeIT(nkNilLit, c.info, getSysType(c.g, c.info, tyPointer))
|
||||
case c.kind
|
||||
of attachedAsgn, attachedDup:
|
||||
body.add callCodegenProc(c.g, "nimAsgnYrc", c.info, genAddr(c, x), y, desc)
|
||||
return
|
||||
of attachedSink:
|
||||
body.add callCodegenProc(c.g, "nimSinkYrc", c.info, genAddr(c, x), y, desc)
|
||||
return
|
||||
else: discard # fall through for destructor, trace, wasMoved
|
||||
|
||||
let isCyclic = c.g.config.selectedGC in {gcOrc, gcYrc} and types.canFormAcycle(c.g, elemType)
|
||||
|
||||
let isInheritableAcyclicRef = c.g.config.selectedGC in {gcOrc, gcYrc} and
|
||||
let isInheritableAcyclicRef = c.g.config.selectedGC == gcOrc and
|
||||
(not isPureObject(elemType)) and
|
||||
tfAcyclic in skipTypes(elemType, abstractInst+{tyOwned}-{tyTypeDesc}).flags
|
||||
# dynamic Acyclic refs need to use dyn decRef
|
||||
@@ -825,7 +740,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
if isFinal(elemType):
|
||||
addDestructorCall(c, elemType, actions, genDeref(tmp, nkDerefExpr))
|
||||
var alignOf = genBuiltin(c, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType))
|
||||
alignOf.typ = getSysType(c.g, c.info, tyInt)
|
||||
alignOf.typ() = getSysType(c.g, c.info, tyInt)
|
||||
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, tmp, alignOf)
|
||||
else:
|
||||
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(tmp, nkDerefExpr))
|
||||
@@ -835,7 +750,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
if isCyclic:
|
||||
if isFinal(elemType):
|
||||
let typInfo = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
|
||||
typInfo.typ = getSysType(c.g, c.info, tyPointer)
|
||||
typInfo.typ() = getSysType(c.g, c.info, tyPointer)
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo)
|
||||
else:
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp)
|
||||
@@ -843,7 +758,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLastDyn", c.info, x)
|
||||
else:
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x)
|
||||
cond.typ = getSysType(c.g, x.info, tyBool)
|
||||
cond.typ() = getSysType(c.g, x.info, tyBool)
|
||||
|
||||
case c.kind
|
||||
of attachedSink:
|
||||
@@ -870,7 +785,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
if isCyclic:
|
||||
if isFinal(elemType):
|
||||
let typInfo = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
|
||||
typInfo.typ = getSysType(c.g, c.info, tyPointer)
|
||||
typInfo.typ() = getSysType(c.g, c.info, tyPointer)
|
||||
body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x, c.idgen), typInfo, y)
|
||||
else:
|
||||
# If the ref is polymorphic we have to account for this
|
||||
@@ -891,28 +806,9 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
## Closures are really like refs except they always use a virtual destructor
|
||||
## and we need to do the refcounting only on the ref field which we call 'xenv':
|
||||
let xenv = genBuiltin(c, mAccessEnv, "accessEnv", x)
|
||||
xenv.typ = getSysType(c.g, c.info, tyPointer)
|
||||
xenv.typ() = getSysType(c.g, c.info, tyPointer)
|
||||
|
||||
# Closures are (fnPtr, env) pairs. nimAsgnYrc/nimSinkYrc handle the env pointer
|
||||
# (atomic store + buffered inc/dec). We also need newAsgnStmt to copy the fnPtr.
|
||||
if c.g.config.selectedGC == gcYrc:
|
||||
let nilDesc = newNodeIT(nkNilLit, c.info, getSysType(c.g, c.info, tyPointer))
|
||||
let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
|
||||
yenv.typ = getSysType(c.g, c.info, tyPointer)
|
||||
case c.kind
|
||||
of attachedAsgn, attachedDup:
|
||||
# nimAsgnYrc: save old env, atomic store new env, inc new env, dec old env
|
||||
body.add callCodegenProc(c.g, "nimAsgnYrc", c.info, genAddr(c, xenv), yenv, nilDesc)
|
||||
# Raw struct copy to also update the function pointer (env write is redundant but benign)
|
||||
body.add newAsgnStmt(x, y)
|
||||
return
|
||||
of attachedSink:
|
||||
body.add callCodegenProc(c.g, "nimSinkYrc", c.info, genAddr(c, xenv), yenv, nilDesc)
|
||||
body.add newAsgnStmt(x, y)
|
||||
return
|
||||
else: discard # fall through for destructor, trace, wasMoved
|
||||
|
||||
let isCyclic = c.g.config.selectedGC in {gcOrc, gcYrc}
|
||||
let isCyclic = c.g.config.selectedGC == gcOrc
|
||||
let tmp =
|
||||
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
|
||||
declareTempOf(c, body, xenv)
|
||||
@@ -926,7 +822,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
if isCyclic: "nimDecRefIsLastCyclicDyn"
|
||||
else: "nimDecRefIsLast"
|
||||
let cond = callCodegenProc(c.g, decRefProc, c.info, tmp)
|
||||
cond.typ = getSysType(c.g, x.info, tyBool)
|
||||
cond.typ() = getSysType(c.g, x.info, tyBool)
|
||||
|
||||
case c.kind
|
||||
of attachedSink:
|
||||
@@ -938,18 +834,19 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedAsgn:
|
||||
let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
|
||||
yenv.typ = getSysType(c.g, c.info, tyPointer)
|
||||
yenv.typ() = getSysType(c.g, c.info, tyPointer)
|
||||
if isCyclic:
|
||||
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c)))
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, cond, actions)
|
||||
else:
|
||||
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv))
|
||||
|
||||
body.add genIf(c, cond, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDup:
|
||||
let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
|
||||
yenv.typ = getSysType(c.g, c.info, tyPointer)
|
||||
yenv.typ() = getSysType(c.g, c.info, tyPointer)
|
||||
if isCyclic:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c)))
|
||||
@@ -1001,7 +898,7 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
if isFinal(elemType):
|
||||
addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr))
|
||||
var alignOf = genBuiltin(c, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType))
|
||||
alignOf.typ = getSysType(c.g, c.info, tyInt)
|
||||
alignOf.typ() = getSysType(c.g, c.info, tyInt)
|
||||
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x, alignOf)
|
||||
else:
|
||||
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr))
|
||||
@@ -1024,14 +921,14 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
# a big problem is that we don't know the environment's type here, so we
|
||||
# have to go through some indirection; we delegate this to the codegen:
|
||||
let call = newNodeI(nkCall, c.info, 2)
|
||||
call.typ = t
|
||||
call.typ() = t
|
||||
call[0] = newSymNode(createMagic(c.g, c.idgen, "deepCopy", mDeepCopy))
|
||||
call[1] = y
|
||||
body.add newAsgnStmt(x, call)
|
||||
elif (optOwnedRefs in c.g.config.globalOptions and
|
||||
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc}:
|
||||
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
|
||||
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
|
||||
xx.typ = getSysType(c.g, c.info, tyPointer)
|
||||
xx.typ() = getSysType(c.g, c.info, tyPointer)
|
||||
case c.kind
|
||||
of attachedSink:
|
||||
# we 'nil' y out afterwards so we *need* to take over its reference
|
||||
@@ -1040,13 +937,13 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedAsgn:
|
||||
let yy = genBuiltin(c, mAccessEnv, "accessEnv", y)
|
||||
yy.typ = getSysType(c.g, c.info, tyPointer)
|
||||
yy.typ() = getSysType(c.g, c.info, tyPointer)
|
||||
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
|
||||
body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDup:
|
||||
let yy = genBuiltin(c, mAccessEnv, "accessEnv", y)
|
||||
yy.typ = getSysType(c.g, c.info, tyPointer)
|
||||
yy.typ() = getSysType(c.g, c.info, tyPointer)
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
|
||||
of attachedDestructor:
|
||||
@@ -1061,7 +958,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
|
||||
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
|
||||
xx.typ = getSysType(c.g, c.info, tyPointer)
|
||||
xx.typ() = getSysType(c.g, c.info, tyPointer)
|
||||
var actions = newNodeI(nkStmtList, c.info)
|
||||
#discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(xx))
|
||||
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, xx)
|
||||
@@ -1084,7 +981,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
tyPtr, tyUncheckedArray, tyVar, tyLent:
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyRef:
|
||||
if c.g.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc}:
|
||||
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
atomicRefOp(c, t, body, x, y)
|
||||
elif (optOwnedRefs in c.g.config.globalOptions and
|
||||
optRefCheck in c.g.config.options):
|
||||
@@ -1093,7 +990,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyProc:
|
||||
if t.callConv == ccClosure:
|
||||
if c.g.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc}:
|
||||
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
atomicClosureOp(c, t, body, x, y)
|
||||
else:
|
||||
closureOp(c, t, body, x, y)
|
||||
@@ -1154,12 +1051,19 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
elif tfUnion in t.flags: # bug #25236
|
||||
defaultOp(c, t, body, x, y)
|
||||
else:
|
||||
if not considerInferDupFromCopy(c, t, body, x, y):
|
||||
if c.kind == attachedDup:
|
||||
var op2 = getAttachedOp(c.g, t, attachedAsgn)
|
||||
if op2 != nil and sfOverridden in op2.flags:
|
||||
#markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op2)
|
||||
body.add newHookCall(c, t.assignment, x, y)
|
||||
else:
|
||||
fillBodyObjT(c, t, body, x, y)
|
||||
else:
|
||||
fillBodyObjT(c, t, body, x, y)
|
||||
of tyDistinct:
|
||||
if not considerUserDefinedOp(c, t, body, x, y):
|
||||
if not considerInferDupFromCopy(c, t, body, x, y):
|
||||
fillBody(c, t.elementType, body, x, y)
|
||||
fillBody(c, t.elementType, body, x, y)
|
||||
of tyTuple:
|
||||
fillBodyTup(c, t, body, x, y)
|
||||
of tyVarargs, tyOpenArray:
|
||||
@@ -1206,7 +1110,7 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
|
||||
|
||||
result.typ.addParam src
|
||||
|
||||
if g.config.selectedGC in {gcOrc, gcYrc} and
|
||||
if g.config.selectedGC == gcOrc and
|
||||
cyclicType(g, typ.skipTypes(abstractInst)):
|
||||
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
|
||||
idgen, result, info)
|
||||
@@ -1220,7 +1124,8 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
|
||||
n[bodyPos] = newNodeI(nkStmtList, info)
|
||||
n[resultPos] = newSymNode(res)
|
||||
result.ast = n
|
||||
incl result.flagsImpl, {sfFromGeneric, sfGeneratedOp}
|
||||
incl result.flags, sfFromGeneric
|
||||
incl result.flags, sfGeneratedOp
|
||||
|
||||
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
|
||||
info: TLineInfo; idgen: IdGenerator; isDiscriminant = false): PSym =
|
||||
@@ -1233,7 +1138,7 @@ 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 g.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc} and
|
||||
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:
|
||||
@@ -1249,7 +1154,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
|
||||
if kind notin {attachedDestructor, attachedWasMoved}:
|
||||
result.typ.addParam src
|
||||
|
||||
if kind == attachedAsgn and g.config.selectedGC in {gcOrc, gcYrc} and
|
||||
if kind == attachedAsgn and g.config.selectedGC == gcOrc and
|
||||
cyclicType(g, typ.skipTypes(abstractInst)):
|
||||
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
|
||||
idgen, result, info)
|
||||
@@ -1262,33 +1167,23 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
|
||||
n[paramsPos] = result.typ.n
|
||||
n[bodyPos] = newNodeI(nkStmtList, info)
|
||||
result.ast = n
|
||||
incl result.flagsImpl, sfFromGeneric
|
||||
incl result.flagsImpl, sfGeneratedOp
|
||||
incl result.flags, sfFromGeneric
|
||||
incl result.flags, sfGeneratedOp
|
||||
if kind == attachedWasMoved:
|
||||
incl result.flagsImpl, sfNoSideEffect
|
||||
incl result.typ, tfNoSideEffect
|
||||
incl result.flags, sfNoSideEffect
|
||||
incl result.typ.flags, tfNoSideEffect
|
||||
|
||||
proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let xx = genBuiltin(c, mAccessTypeField, "accessTypeField", x)
|
||||
let yy = genBuiltin(c, mAccessTypeField, "accessTypeField", y)
|
||||
xx.typ = getSysType(c.g, c.info, tyPointer)
|
||||
yy.typ = xx.typ
|
||||
xx.typ() = getSysType(c.g, c.info, tyPointer)
|
||||
yy.typ() = xx.typ
|
||||
body.add newAsgnStmt(xx, yy)
|
||||
|
||||
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
info: TLineInfo; idgen: IdGenerator): PSym =
|
||||
if typ.kind == tyDistinct:
|
||||
# For =dup, if the distinct type has a user-defined =copy, don't delegate
|
||||
# to the base type. Instead fall through to the normal produceSym logic
|
||||
# so that fillBody -> considerInferDupFromCopy can synthesize =dup from =copy.
|
||||
if kind == attachedDup:
|
||||
let copyOp = getAttachedOp(g, typ, attachedAsgn)
|
||||
if copyOp != nil and sfOverridden in copyOp.flags:
|
||||
discard "fall through to normal produceSym logic"
|
||||
else:
|
||||
return produceSymDistinctType(g, c, typ, kind, info, idgen)
|
||||
else:
|
||||
return produceSymDistinctType(g, c, typ, kind, info, idgen)
|
||||
return produceSymDistinctType(g, c, typ, kind, info, idgen)
|
||||
|
||||
result = getAttachedOp(g, typ, kind)
|
||||
if result == nil:
|
||||
@@ -1309,30 +1204,21 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
|
||||
if kind == attachedSink and destructorOverridden(g, typ):
|
||||
## compiler can use a combination of `=destroy` and memCopy for sink op
|
||||
ensureMutable dest
|
||||
dest.flagsImpl.incl sfCursor
|
||||
dest.flags.incl sfCursor
|
||||
let op = getAttachedOp(g, typ, attachedDestructor)
|
||||
result.ast[bodyPos].add newOpCall(a, op, if op.typ.firstParamType.kind == tyVar: d[0] else: d)
|
||||
result.ast[bodyPos].add newAsgnStmt(d, src)
|
||||
else:
|
||||
var tk: TTypeKind
|
||||
var skipped: PType = nil
|
||||
if g.config.selectedGC in {gcArc, gcOrc, gcYrc, gcHooks, gcAtomicArc}:
|
||||
if g.config.selectedGC in {gcArc, gcOrc, gcHooks, gcAtomicArc}:
|
||||
skipped = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink})
|
||||
tk = skipped.kind
|
||||
else:
|
||||
tk = tyNone # no special casing for strings and seqs
|
||||
case tk
|
||||
of tySequence:
|
||||
let needsYrcLock = g.config.selectedGC == gcYrc and
|
||||
kind in {attachedDestructor, attachedSink, attachedAsgn, attachedDeepCopy, attachedDup} and
|
||||
types.canFormAcycle(g, skipped.elementType)
|
||||
# YRC: topology-changing seq ops must hold the mutator (read) lock
|
||||
if needsYrcLock:
|
||||
result.ast[bodyPos].add callCodegenProc(g, "acquireMutatorLock", info)
|
||||
fillSeqOp(a, typ, result.ast[bodyPos], d, src)
|
||||
if needsYrcLock:
|
||||
result.ast[bodyPos].add callCodegenProc(g, "releaseMutatorLock", info)
|
||||
of tyString:
|
||||
fillStrOp(a, typ, result.ast[bodyPos], d, src)
|
||||
else:
|
||||
@@ -1342,15 +1228,13 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
|
||||
|
||||
if not a.canRaise:
|
||||
ensureMutable result
|
||||
incl result.flagsImpl, sfNeverRaises
|
||||
incl result.flags, sfNeverRaises
|
||||
result.ast[pragmasPos] = newNodeI(nkPragma, info)
|
||||
result.ast[pragmasPos].add newTree(nkExprColonExpr,
|
||||
newIdentNode(g.cache.getIdent("raises"), info), newNodeI(nkBracket, info))
|
||||
|
||||
if kind == attachedDestructor:
|
||||
ensureMutable result
|
||||
incl result.optionsImpl, optQuirky
|
||||
incl result.options, optQuirky
|
||||
completePartialOp(g, idgen.module, typ, kind, result)
|
||||
|
||||
|
||||
@@ -1375,9 +1259,7 @@ proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym,
|
||||
result.ast[bodyPos].add v
|
||||
let placeHolder = newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
|
||||
fillBody(a, typ, result.ast[bodyPos], d, placeHolder)
|
||||
if not a.canRaise:
|
||||
ensureMutable result
|
||||
incl result.flagsImpl, sfNeverRaises
|
||||
if not a.canRaise: incl result.flags, sfNeverRaises
|
||||
|
||||
|
||||
template liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
|
||||
@@ -1421,13 +1303,11 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
|
||||
## to ensure we lift assignment, destructors and moves properly.
|
||||
## The later 'injectdestructors' pass depends on it.
|
||||
if orig == nil or {tfCheckedForDestructor, tfHasMeta} * orig.flags != {}: return
|
||||
# IC: review this solution again later
|
||||
incl orig.flagsImpl, tfCheckedForDestructor
|
||||
incl orig.flags, tfCheckedForDestructor
|
||||
# for user defined generic destructors:
|
||||
let origRoot = genericRoot(orig)
|
||||
if origRoot != nil:
|
||||
# IC: review this solution again later
|
||||
incl origRoot.flagsImpl, tfGenericHasDestructor
|
||||
incl origRoot.flags, tfGenericHasDestructor
|
||||
|
||||
let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
if isEmptyContainer(skipped) or skipped.kind == tyStatic: return
|
||||
@@ -1447,13 +1327,13 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
|
||||
|
||||
# we do not generate '=trace' procs if we
|
||||
# have the cycle detection disabled, saves code size.
|
||||
let lastAttached = if g.config.selectedGC in {gcOrc, gcYrc}: attachedTrace
|
||||
let lastAttached = if g.config.selectedGC == gcOrc: attachedTrace
|
||||
else: attachedSink
|
||||
|
||||
# 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 = default(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]:
|
||||
@@ -1472,6 +1352,5 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
|
||||
if not isTrivial(getAttachedOp(g, orig, attachedDestructor)):
|
||||
#or not isTrivial(orig.assignment) or
|
||||
# not isTrivial(orig.sink):
|
||||
# IC: review this solution again later
|
||||
orig.flagsImpl.incl tfHasAsgn
|
||||
orig.flags.incl tfHasAsgn
|
||||
# ^ XXX Breaks IC!
|
||||
|
||||
@@ -32,12 +32,12 @@ proc interestingVar(s: PSym): bool {.inline.} =
|
||||
proc lookupOrAdd(c: var Ctx; s: PSym; info: TLineInfo): PNode =
|
||||
let field = addUniqueField(c.objType, s, c.cache, c.idgen)
|
||||
var deref = newNodeI(nkHiddenDeref, info)
|
||||
deref.typ = c.objType
|
||||
deref.typ() = c.objType
|
||||
deref.add(newSymNode(c.partialParam, info))
|
||||
result = newNodeI(nkDotExpr, info)
|
||||
result.add(deref)
|
||||
result.add(newSymNode(field))
|
||||
result.typ = field.typ
|
||||
result.typ() = field.typ
|
||||
|
||||
proc liftLocals(n: PNode; i: int; c: var Ctx) =
|
||||
let it = n[i]
|
||||
|
||||
@@ -99,7 +99,6 @@ type
|
||||
warnUser = "User",
|
||||
warnGlobalVarConstructorTemporary = "GlobalVarConstructorTemporary",
|
||||
warnImplicitRangeConversion = "ImplicitRangeConversion",
|
||||
warnSystemRangeConversion = "SystemRangeConversion",
|
||||
# hints
|
||||
hintSuccess = "Success", hintSuccessX = "SuccessX",
|
||||
hintCC = "CC",
|
||||
@@ -209,7 +208,6 @@ const
|
||||
warnUser: "$1",
|
||||
warnGlobalVarConstructorTemporary: "global variable '$1' initialization requires a temporary variable",
|
||||
warnImplicitRangeConversion: "implicit range conversion $1",
|
||||
warnSystemRangeConversion: "implicit range conversion $1",
|
||||
hintSuccess: "operation successful: $#",
|
||||
# keep in sync with `testament.isSuccess`
|
||||
hintSuccessX: "$build\n$loc lines; ${sec}s; $mem; proj: $project; out: $output",
|
||||
@@ -264,9 +262,9 @@ type
|
||||
|
||||
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
|
||||
result = default(array[0..3, TNoteKinds])
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept, warnStdPrefix, warnSystemRangeConversion}
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept, warnStdPrefix, warnImplicitRangeConversion}
|
||||
result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
|
||||
result[1] = result[2] - {warnImplicitRangeConversion, warnProveField, warnProveIndex,
|
||||
result[1] = result[2] - {warnProveField, warnProveIndex,
|
||||
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
|
||||
hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin, hintPerformance}
|
||||
result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf,
|
||||
@@ -279,10 +277,6 @@ const
|
||||
errFloatToString* = "cannot convert '$1' to '$2'"
|
||||
|
||||
type
|
||||
FileInfoKind* = enum
|
||||
fikSource, ## A real source file path
|
||||
fikNifModule ## A NIF module suffix (not a real path)
|
||||
|
||||
TFileInfo* = object
|
||||
fullPath*: AbsoluteFile # This is a canonical full filesystem path
|
||||
projPath*: RelativeFile # This is relative to the project's root
|
||||
@@ -301,7 +295,6 @@ type
|
||||
# for 'nimsuggest'
|
||||
hash*: string # the checksum of the file
|
||||
dirty*: bool # for 'nimpretty' like tooling
|
||||
kind*: FileInfoKind # distinguishes real files from NIF suffixes
|
||||
when defined(nimpretty):
|
||||
fullContent*: string
|
||||
FileIndex* = distinct int32
|
||||
|
||||
@@ -163,7 +163,7 @@ proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
inc(s.lineOffset)
|
||||
result = min(bufLen, s.s.len - s.rd)
|
||||
if result > 0:
|
||||
copyMem(buf, readRawData(s.s, s.rd), result)
|
||||
copyMem(buf, addr(s.s[s.rd]), result)
|
||||
inc(s.rd, result)
|
||||
|
||||
proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
@@ -173,7 +173,7 @@ proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
of llsString:
|
||||
result = min(bufLen, s.s.len - s.rd)
|
||||
if result > 0:
|
||||
copyMem(buf, readRawData(s.s, s.rd), result)
|
||||
copyMem(buf, addr(s.s[0 + s.rd]), result)
|
||||
inc(s.rd, result)
|
||||
of llsFile:
|
||||
result = readBuffer(s.f, buf, bufLen)
|
||||
|
||||
@@ -311,7 +311,7 @@ proc errorSym*(c: PContext, ident: PIdent, info: TLineInfo): PSym =
|
||||
## creates an error symbol to avoid cascading errors (for IDE support)
|
||||
result = newSym(skError, ident, c.idgen, getCurrOwner(c), info, {})
|
||||
result.typ = errorType(c)
|
||||
incl(result.flagsImpl, sfDiscardable)
|
||||
incl(result.flags, sfDiscardable)
|
||||
# pretend it's from the top level scope to prevent cascading errors:
|
||||
if c.config.cmd != cmdInteractive and c.compilesContextId == 0:
|
||||
c.moduleScope.addSym(result)
|
||||
@@ -412,6 +412,8 @@ proc addDecl*(c: PContext, sym: PSym) {.inline.} =
|
||||
proc addPrelimDecl*(c: PContext, sym: PSym) =
|
||||
discard c.currentScope.addUniqueSym(sym)
|
||||
|
||||
from ic / ic import addHidden
|
||||
|
||||
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
|
||||
## adds symbol to the module for either private or public access.
|
||||
if sfExported in sym.flags:
|
||||
@@ -420,6 +422,8 @@ proc addInterfaceDeclAux(c: PContext, sym: PSym) =
|
||||
else: internalError(c.config, sym.info, "addInterfaceDeclAux")
|
||||
elif sym.kind in ExportableSymKinds and c.module != nil and isTopLevelInsideDeclaration(c, sym):
|
||||
strTableAdd(semtabAll(c.graph, c.module), sym)
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
addHidden(c.encoder, c.packedRepr, sym)
|
||||
|
||||
proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||
## adds a symbol on the scope and the interface if appropriate
|
||||
|
||||
@@ -82,7 +82,7 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: P
|
||||
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen,
|
||||
owner, value.info, g.config.options)
|
||||
temp.typ = skipTypes(value.typ, abstractInst)
|
||||
incl(temp.flagsImpl, sfFromGeneric)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
tempAsNode = newSymNode(temp)
|
||||
|
||||
var v = newNodeI(nkVarSection, value.info)
|
||||
@@ -103,7 +103,7 @@ proc evalOnce*(g: ModuleGraph; value: PNode; idgen: IdGenerator; owner: PSym): P
|
||||
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen,
|
||||
owner, value.info, g.config.options)
|
||||
temp.typ = skipTypes(value.typ, abstractInst)
|
||||
incl(temp.flagsImpl, sfFromGeneric)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
|
||||
var v = newNodeI(nkLetSection, value.info)
|
||||
let tempAsNode = newSymNode(temp)
|
||||
@@ -127,8 +127,8 @@ proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNod
|
||||
# note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
|
||||
var temp = newSym(skVar, getIdent(g.cache, genPrefix), idgen, owner, n.info, owner.options)
|
||||
temp.typ = n[1].typ
|
||||
incl(temp.flagsImpl, sfFromGeneric)
|
||||
incl(temp.flagsImpl, sfGenSym)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
incl(temp.flags, sfGenSym)
|
||||
|
||||
var v = newNodeI(nkVarSection, n.info)
|
||||
let tempAsNode = newSymNode(temp)
|
||||
@@ -147,13 +147,13 @@ proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo
|
||||
result = newType(tyObject, idgen, owner)
|
||||
if final:
|
||||
rawAddSon(result, nil)
|
||||
incl result, tfFinal
|
||||
incl result.flags, tfFinal
|
||||
else:
|
||||
rawAddSon(result, getCompilerProc(g, "RootObj").typ)
|
||||
result.n = newNodeI(nkRecList, info)
|
||||
let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s),
|
||||
idgen, owner, info, owner.options)
|
||||
incl s.flagsImpl, sfAnon
|
||||
incl s.flags, sfAnon
|
||||
s.typ = result
|
||||
result.sym = s
|
||||
|
||||
@@ -174,12 +174,12 @@ proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode =
|
||||
# returns a[].field as a node
|
||||
assert field.kind == skField
|
||||
var deref = newNodeI(nkHiddenDeref, info)
|
||||
deref.typ = a.typ.skipTypes(abstractInst)[0]
|
||||
deref.typ() = a.typ.skipTypes(abstractInst)[0]
|
||||
deref.add a
|
||||
result = newNodeI(nkDotExpr, info)
|
||||
result.add deref
|
||||
result.add newSymNode(field)
|
||||
result.typ = field.typ
|
||||
result.typ() = field.typ
|
||||
|
||||
proc rawDirectAccess*(obj, field: PSym): PNode =
|
||||
# returns a.field as a node
|
||||
@@ -187,7 +187,7 @@ proc rawDirectAccess*(obj, field: PSym): PNode =
|
||||
result = newNodeI(nkDotExpr, field.info)
|
||||
result.add newSymNode(obj)
|
||||
result.add newSymNode(field)
|
||||
result.typ = field.typ
|
||||
result.typ() = field.typ
|
||||
|
||||
proc lookupInRecord(n: PNode, id: ItemId): PSym =
|
||||
result = nil
|
||||
@@ -250,12 +250,12 @@ proc newDotExpr*(obj, b: PSym): PNode =
|
||||
assert field != nil, b.name.s
|
||||
result.add newSymNode(obj)
|
||||
result.add newSymNode(field)
|
||||
result.typ = field.typ
|
||||
result.typ() = field.typ
|
||||
|
||||
proc indirectAccess*(a: PNode, b: ItemId, info: TLineInfo): PNode =
|
||||
# returns a[].b as a node
|
||||
var deref = newNodeI(nkHiddenDeref, info)
|
||||
deref.typ = a.typ.skipTypes(abstractInst).elementType
|
||||
deref.typ() = a.typ.skipTypes(abstractInst).elementType
|
||||
var t = deref.typ.skipTypes(abstractInst)
|
||||
var field: PSym
|
||||
while true:
|
||||
@@ -273,12 +273,12 @@ proc indirectAccess*(a: PNode, b: ItemId, info: TLineInfo): PNode =
|
||||
result = newNodeI(nkDotExpr, info)
|
||||
result.add deref
|
||||
result.add newSymNode(field)
|
||||
result.typ = field.typ
|
||||
result.typ() = field.typ
|
||||
|
||||
proc indirectAccess*(a: PNode, b: string, info: TLineInfo; cache: IdentCache): PNode =
|
||||
# returns a[].b as a node
|
||||
var deref = newNodeI(nkHiddenDeref, info)
|
||||
deref.typ = a.typ.skipTypes(abstractInst).elementType
|
||||
deref.typ() = a.typ.skipTypes(abstractInst).elementType
|
||||
var t = deref.typ.skipTypes(abstractInst)
|
||||
var field: PSym
|
||||
let bb = getIdent(cache, b)
|
||||
@@ -297,7 +297,7 @@ proc indirectAccess*(a: PNode, b: string, info: TLineInfo; cache: IdentCache): P
|
||||
result = newNodeI(nkDotExpr, info)
|
||||
result.add deref
|
||||
result.add newSymNode(field)
|
||||
result.typ = field.typ
|
||||
result.typ() = field.typ
|
||||
|
||||
proc getFieldFromObj*(t: PType; v: PSym): PSym =
|
||||
assert v.kind != skField
|
||||
@@ -320,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, idgen, n.typ.owner)
|
||||
result.typ() = newType(typeKind, idgen, n.typ.owner)
|
||||
result.typ.rawAddSon(n.typ)
|
||||
|
||||
proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
|
||||
@@ -344,18 +344,18 @@ proc callCodegenProc*(g: ModuleGraph; name: string;
|
||||
if optionalArgs != nil:
|
||||
for i in 1..<optionalArgs.len-2:
|
||||
result.add optionalArgs[i]
|
||||
result.typ = sym.typ.returnType
|
||||
result.typ() = sym.typ.returnType
|
||||
|
||||
proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
|
||||
result = nkIntLit.newIntNode(value)
|
||||
result.typ = getSysType(g, info, tyInt)
|
||||
result.typ() = getSysType(g, info, tyInt)
|
||||
|
||||
proc genHigh*(g: ModuleGraph; n: PNode): PNode =
|
||||
if skipTypes(n.typ, abstractVar).kind == tyArray:
|
||||
result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar))))
|
||||
else:
|
||||
result = newNodeI(nkCall, n.info, 2)
|
||||
result.typ = getSysType(g, n.info, tyInt)
|
||||
result.typ() = getSysType(g, n.info, tyInt)
|
||||
result[0] = newSymNode(getSysMagic(g, n.info, "high", mHigh))
|
||||
result[1] = n
|
||||
|
||||
@@ -364,7 +364,7 @@ proc genLen*(g: ModuleGraph; n: PNode): PNode =
|
||||
result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar)) + 1))
|
||||
else:
|
||||
result = newNodeI(nkCall, n.info, 2)
|
||||
result.typ = getSysType(g, n.info, tyInt)
|
||||
result.typ() = getSysType(g, n.info, tyInt)
|
||||
result[0] = newSymNode(getSysMagic(g, n.info, "len", mLengthSeq))
|
||||
result[1] = n
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
# Built-in types and compilerprocs are registered here.
|
||||
|
||||
import
|
||||
ast, msgs, platform, idents,
|
||||
modulegraphs, lineinfos, types
|
||||
ast, astalgo, msgs, platform, idents,
|
||||
modulegraphs, lineinfos
|
||||
|
||||
export createMagic
|
||||
|
||||
@@ -134,7 +134,7 @@ proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym =
|
||||
proc resetNimScriptSymbols*(g: ModuleGraph) = g.exposed = initStrTable()
|
||||
|
||||
proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
|
||||
case t.skipTypes(abstractRange).kind
|
||||
case t.kind
|
||||
of tyInt, tyInt8, tyInt16, tyInt32, tyInt64,
|
||||
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64:
|
||||
result = getSysMagic(g, info, "==", mEqI)
|
||||
@@ -166,4 +166,4 @@ proc makeAddr*(n: PNode; idgen: IdGenerator): PNode =
|
||||
result = n
|
||||
else:
|
||||
result = newTree(nkHiddenAddr, n)
|
||||
result.typ = makePtrType(n.typ.skipTypes({tySink}), idgen)
|
||||
result.typ() = makePtrType(n.typ.skipTypes({tySink}), idgen)
|
||||
|
||||
@@ -26,14 +26,12 @@ import
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
|
||||
import ic / [cbackend, integrity, navigator, ic]
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
|
||||
import pipelines
|
||||
|
||||
when not defined(nimKochBootstrap):
|
||||
import nifbackend
|
||||
import deps
|
||||
|
||||
when not defined(leanCompiler):
|
||||
import docgen
|
||||
|
||||
@@ -97,6 +95,14 @@ proc commandCheck(graph: ModuleGraph) =
|
||||
setPipeLinePass(graph, SemPass)
|
||||
compilePipelineProject(graph)
|
||||
|
||||
if conf.symbolFiles != disabledSf:
|
||||
case conf.ideCmd
|
||||
of ideDef: navDefinition(graph)
|
||||
of ideUse: navUsages(graph)
|
||||
of ideDus: navDefusages(graph)
|
||||
else: discard
|
||||
writeRodFiles(graph)
|
||||
|
||||
when not defined(leanCompiler):
|
||||
proc commandDoc2(graph: ModuleGraph; ext: string) =
|
||||
handleDocOutputOptions graph.config
|
||||
@@ -111,38 +117,6 @@ when not defined(leanCompiler):
|
||||
else: raiseAssert $ext
|
||||
compilePipelineProject(graph)
|
||||
|
||||
proc commandCompileToNif(graph: ModuleGraph) =
|
||||
let conf = graph.config
|
||||
extccomp.initVars(conf)
|
||||
if conf.symbolFiles == disabledSf:
|
||||
if {optRun, optForceFullMake} * conf.globalOptions == {optRun} or isDefined(conf, "nimBetterRun"):
|
||||
if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile):
|
||||
# nothing changed
|
||||
graph.config.notes = graph.config.mainPackageNotes
|
||||
return
|
||||
|
||||
if not extccomp.ccHasSaneOverflow(conf):
|
||||
conf.symbols.defineSymbol("nimEmulateOverflowChecks")
|
||||
|
||||
setPipeLinePass(graph, NifgenPass)
|
||||
compilePipelineProject(graph)
|
||||
|
||||
proc commandNifC(graph: ModuleGraph) =
|
||||
## Generate C code from precompiled NIF files.
|
||||
## This is the new IC approach: compile modules to NIF first with `nim m`,
|
||||
## then generate C code from the entry.nif file with whole-program DCE.
|
||||
when not defined(nimKochBootstrap):
|
||||
let conf = graph.config
|
||||
extccomp.initVars(conf)
|
||||
|
||||
if not extccomp.ccHasSaneOverflow(conf):
|
||||
conf.symbols.defineSymbol("nimEmulateOverflowChecks")
|
||||
|
||||
# Use the NIF backend to generate C code
|
||||
nifbackend.generateCode(graph, conf.projectMainIdx)
|
||||
else:
|
||||
rawMessage(graph.config, errGenerated, "NIF backend not available during bootstrap build")
|
||||
|
||||
proc commandCompileToC(graph: ModuleGraph) =
|
||||
let conf = graph.config
|
||||
extccomp.initVars(conf)
|
||||
@@ -163,7 +137,15 @@ proc commandCompileToC(graph: ModuleGraph) =
|
||||
compilePipelineProject(graph)
|
||||
if graph.config.errorCounter > 0:
|
||||
return # issue #9933
|
||||
cgenWriteModules(graph.backend, conf)
|
||||
if conf.symbolFiles == disabledSf:
|
||||
cgenWriteModules(graph.backend, conf)
|
||||
else:
|
||||
if isDefined(conf, "nimIcIntegrityChecks"):
|
||||
checkIntegrity(graph)
|
||||
generateCode(graph)
|
||||
# graph.backend can be nil under IC when nothing changed at all:
|
||||
if graph.backend != nil:
|
||||
cgenWriteModules(graph.backend, conf)
|
||||
if conf.cmd != cmdTcc and graph.backend != nil:
|
||||
extccomp.callCCompiler(conf)
|
||||
# for now we do not support writing out a .json file with the build instructions when HCR is on
|
||||
@@ -202,7 +184,7 @@ proc commandInteractive(graph: ModuleGraph) =
|
||||
discard graph.compilePipelineModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
|
||||
else:
|
||||
var m = graph.makeStdinModule()
|
||||
incl(m, sfMainModule)
|
||||
incl(m.flags, sfMainModule)
|
||||
var idgen = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0)
|
||||
let s = llStreamOpenStdIn(onPrompt = proc() = flushDot(graph.config))
|
||||
discard processPipelineModule(graph, m, idgen, s)
|
||||
@@ -223,6 +205,10 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
|
||||
else:
|
||||
rawMessage(config, errGenerated, "cannot open file: " & f.string)
|
||||
|
||||
proc commandView(graph: ModuleGraph) =
|
||||
let f = toAbsolute(mainCommandArg(graph.config), AbsoluteDir getCurrentDir()).addFileExt(RodExt)
|
||||
rodViewer(f, graph.config, graph.cache)
|
||||
|
||||
const
|
||||
PrintRopeCacheStats = false
|
||||
|
||||
@@ -271,7 +257,7 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
if conf.exc == excNone: conf.exc = excSetjmp
|
||||
of backendCpp:
|
||||
if conf.exc == excNone: conf.exc = excCpp
|
||||
of backendObjc, backendNif: discard
|
||||
of backendObjc: discard
|
||||
of backendJs:
|
||||
if conf.hcrOn:
|
||||
# XXX: At the moment, system.nim cannot be compiled in JS mode
|
||||
@@ -289,7 +275,6 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
of backendCpp: commandCompileToC(graph)
|
||||
of backendObjc: commandCompileToC(graph)
|
||||
of backendJs: commandCompileToJS(graph)
|
||||
of backendNif: commandCompileToNif(graph)
|
||||
of backendInvalid: raiseAssert "unreachable"
|
||||
|
||||
template docLikeCmd(body) =
|
||||
@@ -320,6 +305,8 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
case conf.cmd
|
||||
of cmdBackends:
|
||||
compileToBackend()
|
||||
when BenchIC:
|
||||
echoTimes graph.packed
|
||||
of cmdTcc:
|
||||
when hasTinyCBackend:
|
||||
extccomp.setCC(conf, "tcc", unknownLineInfo)
|
||||
@@ -416,27 +403,16 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
of cmdCheck:
|
||||
commandCheck(graph)
|
||||
of cmdM:
|
||||
# cmdM uses NIF files, not ROD files
|
||||
graph.config.symbolFiles = disabledSf
|
||||
setUseIc(true)
|
||||
graph.config.symbolFiles = v2Sf
|
||||
setUseIc(graph.config.symbolFiles != disabledSf)
|
||||
commandCheck(graph)
|
||||
of cmdNifC:
|
||||
setUseIc(true)
|
||||
# Generate C code from NIF files
|
||||
wantMainModule(conf)
|
||||
setOutFile(conf)
|
||||
commandNifC(graph)
|
||||
of cmdIc:
|
||||
# Generate .build.nif for nifmake
|
||||
setUseIc(true)
|
||||
wantMainModule(conf)
|
||||
when not defined(nimKochBootstrap):
|
||||
commandIc(conf)
|
||||
else:
|
||||
rawMessage(conf, errGenerated, "nim deps not available in bootstrap build")
|
||||
of cmdParse:
|
||||
wantMainModule(conf)
|
||||
discard parseFile(conf.projectMainIdx, cache, conf)
|
||||
of cmdRod:
|
||||
wantMainModule(conf)
|
||||
commandView(graph)
|
||||
#msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!")
|
||||
of cmdInteractive: commandInteractive(graph)
|
||||
of cmdNimscript:
|
||||
if conf.projectIsCmd or conf.projectIsStdin: discard
|
||||
|
||||
@@ -14,12 +14,8 @@
|
||||
import std/[intsets, tables, hashes, strtabs, os, strutils, parseutils]
|
||||
import ../dist/checksums/src/checksums/md5
|
||||
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages, suggestsymdb
|
||||
import ic / [packed_ast, ic]
|
||||
|
||||
when not defined(nimKochBootstrap):
|
||||
import ast2nif
|
||||
import "../dist/nimony/src/lib" / [nifstreams, bitabs]
|
||||
|
||||
import typekeys
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -27,12 +23,16 @@ when defined(nimPreviewSlimSystem):
|
||||
type
|
||||
SigHash* = distinct MD5Digest
|
||||
|
||||
LazySym* = object
|
||||
id*: FullId
|
||||
sym*: PSym
|
||||
|
||||
Iface* = object ## data we don't want to store directly in the
|
||||
## ast.PSym type for s.kind == skModule
|
||||
module*: PSym ## module this "Iface" belongs to
|
||||
converters*: seq[PSym]
|
||||
patterns*: seq[PSym]
|
||||
pureEnums*: seq[PSym]
|
||||
converters*: seq[LazySym]
|
||||
patterns*: seq[LazySym]
|
||||
pureEnums*: seq[LazySym]
|
||||
interf: TStrTable
|
||||
interfHidden: TStrTable
|
||||
uniqueName*: Rope
|
||||
@@ -41,12 +41,25 @@ type
|
||||
opNot*, opContains*, opLe*, opLt*, opAnd*, opOr*, opIsNil*, opEq*: PSym
|
||||
opAdd*, opSub*, opMul*, opDiv*, opLen*: PSym
|
||||
|
||||
FullId* = object
|
||||
module*: int
|
||||
packed*: PackedItemId
|
||||
|
||||
LazyType* = object
|
||||
id*: FullId
|
||||
typ*: PType
|
||||
|
||||
LazyInstantiation* = object
|
||||
module*: int
|
||||
sym*: FullId
|
||||
concreteTypes*: seq[FullId]
|
||||
inst*: PInstantiation
|
||||
|
||||
PipelinePass* = enum
|
||||
NonePass
|
||||
SemPass
|
||||
JSgenPass
|
||||
CgenPass
|
||||
NifgenPass
|
||||
EvalPass
|
||||
InterpreterPass
|
||||
GenDependPass
|
||||
@@ -56,19 +69,19 @@ type
|
||||
|
||||
ModuleGraph* {.acyclic.} = ref object
|
||||
ifaces*: seq[Iface] ## indexed by int32 fileIdx
|
||||
packed*: PackedModuleGraph
|
||||
encoders*: seq[PackedEncoder]
|
||||
|
||||
typeInstCache*: Table[ItemId, seq[PType]] # A symbol's ItemId.
|
||||
procInstCache*: Table[ItemId, seq[PInstantiation]] # A symbol's ItemId.
|
||||
attachedOps*: array[TTypeAttachedOp, Table[ItemId, PSym]] # Type ID, destructors, etc.
|
||||
loadedOps: array[TTypeAttachedOp, Table[string, PSym]] # This can later by unified with `attachedOps` once it's stable
|
||||
opsLog*: seq[LogEntry]
|
||||
methodsPerGenericType*: Table[ItemId, seq[(int, PSym)]] # Type ID, attached methods
|
||||
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.
|
||||
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, PSym]
|
||||
loadedEnumToStringProcs: Table[string, PSym]
|
||||
enumToStringProcs*: Table[ItemId, LazySym]
|
||||
emittedTypeInfo*: Table[string, FileIndex]
|
||||
|
||||
startupPackedConfig*: PackedConfig
|
||||
packageSyms*: TStrTable
|
||||
deps*: IntSet # the dependency graph or potentially its transitive closure.
|
||||
importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies
|
||||
@@ -94,8 +107,8 @@ type
|
||||
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[PSym]]
|
||||
dispatchers*: seq[PSym]
|
||||
methodsPerType*: Table[ItemId, seq[LazySym]]
|
||||
dispatchers*: seq[LazySym]
|
||||
|
||||
systemModule*: PSym
|
||||
sysTypes*: array[TTypeKind, PType]
|
||||
@@ -124,8 +137,6 @@ type
|
||||
cachedFiles*: StringTableRef
|
||||
|
||||
procGlobals*: seq[PNode]
|
||||
nifReplayActions*: Table[int32, seq[PNode]] # module position -> replay actions for NIF
|
||||
cachedMods: IntSet
|
||||
|
||||
TPassContext* = object of RootObj # the pass's context
|
||||
idgen*: IdGenerator
|
||||
@@ -148,12 +159,8 @@ proc resetForBackend*(g: ModuleGraph) =
|
||||
a.clear()
|
||||
g.methodsPerGenericType.clear()
|
||||
g.enumToStringProcs.clear()
|
||||
g.loadedEnumToStringProcs.clear()
|
||||
g.dispatchers.setLen(0)
|
||||
g.methodsPerType.clear()
|
||||
for a in mitems(g.loadedOps):
|
||||
a.clear()
|
||||
g.opsLog.setLen(0)
|
||||
|
||||
const
|
||||
cb64 = [
|
||||
@@ -209,43 +216,85 @@ proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) =
|
||||
strTableAdd(semtabAll(g, m), s)
|
||||
|
||||
proc isCachedModule(g: ModuleGraph; module: int): bool {.inline.} =
|
||||
result = module in g.cachedMods
|
||||
result = module < g.packed.len and g.packed[module].status == loaded
|
||||
|
||||
proc isCachedModule*(g: ModuleGraph; m: PSym): bool {.inline.} =
|
||||
isCachedModule(g, m.position)
|
||||
|
||||
proc simulateCachedModule(g: ModuleGraph; moduleSym: PSym; m: PackedModule) =
|
||||
when false:
|
||||
echo "simulating ", moduleSym.name.s, " ", moduleSym.position
|
||||
simulateLoadedModule(g.packed, g.config, g.cache, moduleSym, m)
|
||||
|
||||
proc initEncoder*(g: ModuleGraph; module: PSym) =
|
||||
let id = module.position
|
||||
if id >= g.encoders.len:
|
||||
setLen g.encoders, id+1
|
||||
ic.initEncoder(g.encoders[id],
|
||||
g.packed[id].fromDisk, module, g.config, g.startupPackedConfig)
|
||||
|
||||
type
|
||||
ModuleIter* = object
|
||||
fromRod: bool
|
||||
modIndex: int
|
||||
ti: TIdentIter
|
||||
rodIt: RodIter
|
||||
importHidden: bool
|
||||
|
||||
proc initModuleIter*(mi: var ModuleIter; g: ModuleGraph; m: PSym; name: PIdent): PSym =
|
||||
assert m.kind == skModule
|
||||
mi.modIndex = m.position
|
||||
mi.fromRod = isCachedModule(g, mi.modIndex)
|
||||
mi.importHidden = optImportHidden in m.options
|
||||
result = initIdentIter(mi.ti, g.ifaces[mi.modIndex].interfSelect(mi.importHidden), name)
|
||||
if mi.fromRod:
|
||||
result = initRodIter(mi.rodIt, g.config, g.cache, g.packed, FileIndex mi.modIndex, name, mi.importHidden)
|
||||
else:
|
||||
result = initIdentIter(mi.ti, g.ifaces[mi.modIndex].interfSelect(mi.importHidden), name)
|
||||
|
||||
proc nextModuleIter*(mi: var ModuleIter; g: ModuleGraph): PSym =
|
||||
result = nextIdentIter(mi.ti, g.ifaces[mi.modIndex].interfSelect(mi.importHidden))
|
||||
if mi.fromRod:
|
||||
result = nextRodIter(mi.rodIt, g.packed)
|
||||
else:
|
||||
result = nextIdentIter(mi.ti, g.ifaces[mi.modIndex].interfSelect(mi.importHidden))
|
||||
|
||||
iterator allSyms*(g: ModuleGraph; m: PSym): PSym =
|
||||
let importHidden = optImportHidden in m.options
|
||||
for s in g.ifaces[m.position].interfSelect(importHidden).data:
|
||||
if s != nil:
|
||||
yield s
|
||||
if isCachedModule(g, m):
|
||||
var rodIt: RodIter = default(RodIter)
|
||||
var r = initRodIterAllSyms(rodIt, g.config, g.cache, g.packed, FileIndex m.position, importHidden)
|
||||
while r != nil:
|
||||
yield r
|
||||
r = nextRodIter(rodIt, g.packed)
|
||||
else:
|
||||
for s in g.ifaces[m.position].interfSelect(importHidden).data:
|
||||
if s != nil:
|
||||
yield s
|
||||
|
||||
proc someSym*(g: ModuleGraph; m: PSym; name: PIdent): PSym =
|
||||
let importHidden = optImportHidden in m.options
|
||||
result = strTableGet(g.ifaces[m.position].interfSelect(importHidden), name)
|
||||
if isCachedModule(g, m):
|
||||
result = interfaceSymbol(g.config, g.cache, g.packed, FileIndex(m.position), name, importHidden)
|
||||
else:
|
||||
result = strTableGet(g.ifaces[m.position].interfSelect(importHidden), name)
|
||||
|
||||
proc someSymAmb*(g: ModuleGraph; m: PSym; name: PIdent; amb: var bool): PSym =
|
||||
let importHidden = optImportHidden in m.options
|
||||
var ti: TIdentIter = default(TIdentIter)
|
||||
result = initIdentIter(ti, g.ifaces[m.position].interfSelect(importHidden), name)
|
||||
if result != nil and nextIdentIter(ti, g.ifaces[m.position].interfSelect(importHidden)) != nil:
|
||||
# another symbol exists with same name
|
||||
amb = true
|
||||
if isCachedModule(g, m):
|
||||
result = nil
|
||||
for s in interfaceSymbols(g.config, g.cache, g.packed, FileIndex(m.position), name, importHidden):
|
||||
if result == nil:
|
||||
# set result to the first symbol
|
||||
result = s
|
||||
else:
|
||||
# another symbol found
|
||||
amb = true
|
||||
break
|
||||
else:
|
||||
var ti: TIdentIter = default(TIdentIter)
|
||||
result = initIdentIter(ti, g.ifaces[m.position].interfSelect(importHidden), name)
|
||||
if result != nil and nextIdentIter(ti, g.ifaces[m.position].interfSelect(importHidden)) != nil:
|
||||
# another symbol exists with same name
|
||||
amb = true
|
||||
|
||||
proc systemModuleSym*(g: ModuleGraph; name: PIdent): PSym =
|
||||
result = someSym(g, g.systemModule, name)
|
||||
@@ -257,113 +306,109 @@ iterator systemModuleSyms*(g: ModuleGraph; name: PIdent): PSym =
|
||||
yield r
|
||||
r = nextModuleIter(mi, g)
|
||||
|
||||
proc resolveType(g: ModuleGraph; t: var LazyType): PType =
|
||||
result = t.typ
|
||||
if result == nil and isCachedModule(g, t.id.module):
|
||||
result = loadTypeFromId(g.config, g.cache, g.packed, t.id.module, t.id.packed)
|
||||
t.typ = result
|
||||
assert result != nil
|
||||
|
||||
proc resolveSym(g: ModuleGraph; t: var LazySym): PSym =
|
||||
result = t.sym
|
||||
if result == nil and isCachedModule(g, t.id.module):
|
||||
result = loadSymFromId(g.config, g.cache, g.packed, t.id.module, t.id.packed)
|
||||
t.sym = result
|
||||
assert result != nil
|
||||
|
||||
proc resolveInst(g: ModuleGraph; t: var LazyInstantiation): PInstantiation =
|
||||
result = t.inst
|
||||
if result == nil and isCachedModule(g, t.module):
|
||||
result = PInstantiation(sym: loadSymFromId(g.config, g.cache, g.packed, t.sym.module, t.sym.packed))
|
||||
result.concreteTypes = newSeq[PType](t.concreteTypes.len)
|
||||
for i in 0..high(result.concreteTypes):
|
||||
result.concreteTypes[i] = loadTypeFromId(g.config, g.cache, g.packed,
|
||||
t.concreteTypes[i].module, t.concreteTypes[i].packed)
|
||||
t.inst = result
|
||||
assert result != nil
|
||||
|
||||
proc resolveAttachedOp*(g: ModuleGraph; t: var LazySym): PSym =
|
||||
result = t.sym
|
||||
if result == nil:
|
||||
result = loadSymFromId(g.config, g.cache, g.packed, t.id.module, t.id.packed)
|
||||
t.sym = result
|
||||
assert result != nil
|
||||
|
||||
iterator typeInstCacheItems*(g: ModuleGraph; s: PSym): PType =
|
||||
if g.typeInstCache.contains(s.itemId):
|
||||
let x = addr(g.typeInstCache[s.itemId])
|
||||
for t in mitems(x[]):
|
||||
yield t
|
||||
yield resolveType(g, t)
|
||||
|
||||
iterator procInstCacheItems*(g: ModuleGraph; s: PSym): PInstantiation =
|
||||
if g.procInstCache.contains(s.itemId):
|
||||
let x = addr(g.procInstCache[s.itemId])
|
||||
for t in mitems(x[]):
|
||||
yield t
|
||||
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.
|
||||
if g.attachedOps[op].contains(t.itemId):
|
||||
result = g.attachedOps[op][t.itemId]
|
||||
elif g.config.cmd in {cmdNifC, cmdM}:
|
||||
# Fall back to key-based lookup for NIF-loaded hooks
|
||||
let key = typeKey(t, g.config, loadTypeCallback, loadSymCallback)
|
||||
result = g.loadedOps[op].getOrDefault(key)
|
||||
#echo "fallback ", key, " ", op, " ", result
|
||||
result = resolveAttachedOp(g, g.attachedOps[op][t.itemId])
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc setAttachedOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
|
||||
## we also need to record this to the packed module.
|
||||
if not g.attachedOps[op].contains(t.itemId):
|
||||
let key = typeKey(t, g.config, loadTypeCallback, loadSymCallback)
|
||||
# Use key-based deduplication for opsLog because different type objects
|
||||
# (e.g. canon vs orig) can have different itemIds but same structural key
|
||||
if key notin g.loadedOps[op]:
|
||||
# Hooks should be written to the module where the type is defined,
|
||||
# not the module that triggered the registration
|
||||
let ownerModule = if t.sym != nil: t.sym.itemId.module.int else: module
|
||||
g.opsLog.add LogEntry(kind: HookEntry, op: op, module: ownerModule, key: key, sym: value)
|
||||
g.loadedOps[op][key] = value
|
||||
g.attachedOps[op][t.itemId] = value
|
||||
|
||||
proc setAttachedOp*(g: ModuleGraph; module: int; typeId: ItemId; op: TTypeAttachedOp; value: PSym) =
|
||||
## Overload that takes ItemId directly, useful for registering hooks from NIF index.
|
||||
g.attachedOps[op][typeId] = value
|
||||
g.attachedOps[op][t.itemId] = LazySym(sym: value)
|
||||
|
||||
proc setAttachedOpPartial*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
|
||||
## we also need to record this to the packed module.
|
||||
g.attachedOps[op][t.itemId] = value
|
||||
g.attachedOps[op][t.itemId] = LazySym(sym: value)
|
||||
|
||||
proc completePartialOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) {.inline.} =
|
||||
discard
|
||||
proc completePartialOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
|
||||
if g.config.symbolFiles != disabledSf:
|
||||
assert module < g.encoders.len
|
||||
assert isActive(g.encoders[module])
|
||||
toPackedGeneratedProcDef(value, g.encoders[module], g.packed[module].fromDisk)
|
||||
#storeAttachedProcDef(t, op, value, g.encoders[module], g.packed[module].fromDisk)
|
||||
|
||||
iterator getDispatchers*(g: ModuleGraph): PSym =
|
||||
for i in g.dispatchers.mitems:
|
||||
yield i
|
||||
yield resolveSym(g, i)
|
||||
|
||||
proc addDispatchers*(g: ModuleGraph, value: PSym) =
|
||||
# TODO: add it for packed modules
|
||||
g.dispatchers.add value
|
||||
g.dispatchers.add LazySym(sym: value)
|
||||
|
||||
iterator resolveLazySymSeq(g: ModuleGraph, list: var seq[PSym]): PSym =
|
||||
iterator resolveLazySymSeq(g: ModuleGraph, list: var seq[LazySym]): PSym =
|
||||
for it in list.mitems:
|
||||
yield it
|
||||
yield resolveSym(g, it)
|
||||
|
||||
proc setMethodsPerType*(g: ModuleGraph; id: ItemId, methods: seq[PSym]) =
|
||||
proc setMethodsPerType*(g: ModuleGraph; id: ItemId, methods: seq[LazySym]) =
|
||||
# TODO: add it for packed modules
|
||||
g.methodsPerType[id] = methods
|
||||
|
||||
proc addNifReplayAction*(g: ModuleGraph; module: int32; n: PNode) =
|
||||
## Stores a replay action for NIF-based incremental compilation.
|
||||
g.nifReplayActions.mgetOrPut(module, @[]).add n
|
||||
|
||||
iterator getMethodsPerType*(g: ModuleGraph; t: PType): PSym =
|
||||
if g.methodsPerType.contains(t.itemId):
|
||||
for it in mitems g.methodsPerType[t.itemId]:
|
||||
yield it
|
||||
yield resolveSym(g, it)
|
||||
|
||||
proc getToStringProc*(g: ModuleGraph; t: PType): PSym =
|
||||
result = g.enumToStringProcs.getOrDefault(t.itemId)
|
||||
if result == nil and g.config.cmd in {cmdNifC, cmdM}:
|
||||
let key = typeKey(t, g.config, loadTypeCallback, loadSymCallback)
|
||||
result = g.loadedEnumToStringProcs.getOrDefault(key)
|
||||
result = resolveSym(g, g.enumToStringProcs[t.itemId])
|
||||
assert result != nil
|
||||
|
||||
proc setToStringProc*(g: ModuleGraph; t: PType; value: PSym) =
|
||||
g.enumToStringProcs[t.itemId] = value
|
||||
let key = typeKey(t, g.config, loadTypeCallback, loadSymCallback)
|
||||
let ownerModule = if t.sym != nil: t.sym.itemId.module.int else: value.itemId.module.int
|
||||
g.opsLog.add LogEntry(kind: EnumToStrEntry, module: ownerModule, key: key, sym: value)
|
||||
g.enumToStringProcs[t.itemId] = LazySym(sym: value)
|
||||
|
||||
iterator methodsForGeneric*(g: ModuleGraph; t: PType): (int, PSym) =
|
||||
if g.methodsPerGenericType.contains(t.itemId):
|
||||
for it in mitems g.methodsPerGenericType[t.itemId]:
|
||||
yield (it[0], it[1])
|
||||
yield (it[0], resolveSym(g, it[1]))
|
||||
|
||||
proc addMethodToGeneric*(g: ModuleGraph; module: int; t: PType; col: int; m: PSym) =
|
||||
g.methodsPerGenericType.mgetOrPut(t.itemId, @[]).add (col, m)
|
||||
let key = typeKey(t, g.config, loadTypeCallback, loadSymCallback)
|
||||
let ownerModule = if t.sym != nil: t.sym.itemId.module.int else: module
|
||||
g.opsLog.add LogEntry(kind: MethodEntry, module: ownerModule, key: key, sym: m)
|
||||
|
||||
proc logGenericInstance*(g: ModuleGraph; inst: PSym) =
|
||||
## Log a generic instance so it gets written to the NIF file.
|
||||
## This is needed when generic instances are created during compile-time
|
||||
## evaluation and may be referenced from other modules compiled in the same run.
|
||||
if g.config.cmd in {cmdNifC, cmdM}:
|
||||
let ownerModule = inst.itemId.module.int
|
||||
g.opsLog.add LogEntry(kind: GenericInstEntry, module: ownerModule, sym: inst)
|
||||
g.methodsPerGenericType.mgetOrPut(t.itemId, @[]).add (col, LazySym(sym: m))
|
||||
|
||||
proc hasDisabledAsgn*(g: ModuleGraph; t: PType): bool =
|
||||
let op = getAttachedOp(g, t, attachedAsgn)
|
||||
@@ -377,31 +422,21 @@ proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) =
|
||||
|
||||
proc loadCompilerProc*(g: ModuleGraph; name: string): PSym =
|
||||
result = nil
|
||||
if g.config.symbolFiles == disabledSf and optWithinConfigSystem notin g.config.globalOptions:
|
||||
# For NIF-based compilation, search in loaded NIF modules
|
||||
when not defined(nimKochBootstrap):
|
||||
# Try to resolve from NIF for both cmdNifC and cmdM (which uses NIF files)
|
||||
if g.config.cmd in {cmdNifC, cmdM}:
|
||||
# First try system module (most compilerprocs are there)
|
||||
let systemFileIdx = g.config.m.systemFileIdx
|
||||
if systemFileIdx != InvalidFileIdx and not g.withinSystem:
|
||||
# Only try to load from NIF if the file exists (it may not during initial ic build)
|
||||
result = tryResolveCompilerProc(ast.program, name, systemFileIdx)
|
||||
if result != nil:
|
||||
strTableAdd(g.compilerprocs, result)
|
||||
return result
|
||||
if g.config.symbolFiles == disabledSf: return nil
|
||||
|
||||
# Try threadpool module (some compilerprocs like FlowVar are there)
|
||||
# Find threadpool module by searching loaded modules
|
||||
for moduleIdx in 0..<g.ifaces.len:
|
||||
let module = g.ifaces[moduleIdx].module
|
||||
if module != nil and module.name.s == "threadpool":
|
||||
let threadpoolFileIdx = module.position.FileIndex
|
||||
result = tryResolveCompilerProc(ast.program, name, threadpoolFileIdx)
|
||||
if result != nil:
|
||||
strTableAdd(g.compilerprocs, result)
|
||||
return result
|
||||
return nil
|
||||
# slow, linear search, but the results are cached:
|
||||
for module in 0..<len(g.packed):
|
||||
#if isCachedModule(g, module):
|
||||
let x = searchForCompilerproc(g.packed[module], name)
|
||||
if x >= 0:
|
||||
result = loadSymFromId(g.config, g.cache, g.packed, module, toPackedItemId(x))
|
||||
if result != nil:
|
||||
strTableAdd(g.compilerprocs, result)
|
||||
return result
|
||||
|
||||
proc loadPackedSym*(g: ModuleGraph; s: var LazySym) =
|
||||
if s.sym == nil:
|
||||
s.sym = loadSymFromId(g.config, g.cache, g.packed, s.id.module, s.id.packed)
|
||||
|
||||
proc `$`*(u: SigHash): string =
|
||||
toBase64a(cast[cstring](unsafeAddr u), sizeof(u))
|
||||
@@ -489,13 +524,15 @@ proc registerModule*(g: ModuleGraph; m: PSym) =
|
||||
if m.position >= g.ifaces.len:
|
||||
setLen(g.ifaces, m.position + 1)
|
||||
|
||||
if g.ifaces[m.position].module == nil:
|
||||
g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[],
|
||||
uniqueName: rope(uniqueModuleName(g.config, m)))
|
||||
initStrTables(g, m)
|
||||
if m.position >= g.packed.len:
|
||||
setLen(g.packed.pm, m.position + 1)
|
||||
|
||||
g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[],
|
||||
uniqueName: rope(uniqueModuleName(g.config, m)))
|
||||
initStrTables(g, m)
|
||||
|
||||
proc registerModuleById*(g: ModuleGraph; m: FileIndex) =
|
||||
registerModule(g, g.ifaces[int m].module)
|
||||
registerModule(g, g.packed[int m].module)
|
||||
|
||||
proc initOperators*(g: ModuleGraph): Operators =
|
||||
# These are safe for IC.
|
||||
@@ -542,14 +579,12 @@ proc initModuleGraphFields(result: ModuleGraph) =
|
||||
result.operators = initOperators(result)
|
||||
result.emittedTypeInfo = initTable[string, FileIndex]()
|
||||
result.cachedFiles = newStringTable()
|
||||
result.cachedMods = initIntSet()
|
||||
|
||||
proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
|
||||
result = ModuleGraph()
|
||||
result.config = config
|
||||
result.cache = cache
|
||||
initModuleGraphFields(result)
|
||||
ast.setupProgram(config, cache)
|
||||
|
||||
proc resetAllModules*(g: ModuleGraph) =
|
||||
g.packageSyms = initStrTable()
|
||||
@@ -565,13 +600,49 @@ proc resetAllModules*(g: ModuleGraph) =
|
||||
initModuleGraphFields(g)
|
||||
|
||||
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
if fileIdx.int32 >= 0 and fileIdx.int32 < g.ifaces.len:
|
||||
result = g.ifaces[fileIdx.int32].module
|
||||
else:
|
||||
result = nil
|
||||
result = nil
|
||||
if fileIdx.int32 >= 0:
|
||||
if isCachedModule(g, fileIdx.int32):
|
||||
result = g.packed[fileIdx.int32].module
|
||||
elif fileIdx.int32 < g.ifaces.len:
|
||||
result = g.ifaces[fileIdx.int32].module
|
||||
|
||||
proc moduleOpenForCodegen*(g: ModuleGraph; m: FileIndex): bool {.inline.} =
|
||||
result = true
|
||||
if g.config.symbolFiles == disabledSf:
|
||||
result = true
|
||||
else:
|
||||
result = g.packed[m.int32].status notin {undefined, stored, loaded}
|
||||
|
||||
proc rememberEmittedTypeInfo*(g: ModuleGraph; m: FileIndex; ti: string) =
|
||||
#assert(not isCachedModule(g, m.int32))
|
||||
if g.config.symbolFiles != disabledSf:
|
||||
#assert g.encoders[m.int32].isActive
|
||||
assert g.packed[m.int32].status != stored
|
||||
g.packed[m.int32].fromDisk.emittedTypeInfo.add ti
|
||||
#echo "added typeinfo ", m.int32, " ", ti, " suspicious ", not g.encoders[m.int32].isActive
|
||||
|
||||
proc rememberFlag*(g: ModuleGraph; m: PSym; flag: ModuleBackendFlag) =
|
||||
if g.config.symbolFiles != disabledSf:
|
||||
#assert g.encoders[m.int32].isActive
|
||||
assert g.packed[m.position].status != stored
|
||||
g.packed[m.position].fromDisk.backendFlags.incl flag
|
||||
|
||||
proc closeRodFile*(g: ModuleGraph; m: PSym) =
|
||||
if g.config.symbolFiles in {readOnlySf, v2Sf}:
|
||||
# For stress testing we seek to reload the symbols from memory. This
|
||||
# way much of the logic is tested but the test is reproducible as it does
|
||||
# not depend on the hard disk contents!
|
||||
let mint = m.position
|
||||
saveRodFile(toRodFile(g.config, AbsoluteFile toFullPath(g.config, FileIndex(mint))),
|
||||
g.encoders[mint], g.packed[mint].fromDisk)
|
||||
g.packed[mint].status = stored
|
||||
|
||||
elif g.config.symbolFiles == stressTest:
|
||||
# debug code, but maybe a good idea for production? Could reduce the compiler's
|
||||
# memory consumption considerably at the cost of more loads from disk.
|
||||
let mint = m.position
|
||||
simulateCachedModule(g, m, g.packed[mint].fromDisk)
|
||||
g.packed[mint].status = loaded
|
||||
|
||||
proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
|
||||
|
||||
@@ -609,13 +680,13 @@ proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
||||
if m != nil:
|
||||
g.suggestSymbols.del(fileIdx)
|
||||
g.suggestErrors.del(fileIdx)
|
||||
incl m.flagsImpl, sfDirty
|
||||
incl m.flags, sfDirty
|
||||
|
||||
proc unmarkAllDirty*(g: ModuleGraph) =
|
||||
for i in 0i32..<g.ifaces.len.int32:
|
||||
let m = g.ifaces[i].module
|
||||
if m != nil:
|
||||
m.flagsImpl.excl sfDirty
|
||||
m.flags.excl sfDirty
|
||||
|
||||
proc isDirty*(g: ModuleGraph; m: PSym): bool =
|
||||
result = g.suggestMode and sfDirty in m.flags
|
||||
@@ -655,59 +726,23 @@ proc needsCompilation*(g: ModuleGraph, fileIdx: FileIndex): bool =
|
||||
|
||||
proc getBody*(g: ModuleGraph; s: PSym): PNode {.inline.} =
|
||||
result = s.ast[bodyPos]
|
||||
if result == nil and g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}:
|
||||
result = loadProcBody(g.config, g.cache, g.packed, s)
|
||||
s.ast[bodyPos] = result
|
||||
assert result != nil
|
||||
|
||||
when not defined(nimKochBootstrap):
|
||||
proc moduleFromNifFile*(g: ModuleGraph; fileIdx: FileIndex;
|
||||
flags: set[LoadFlag] = {}): PrecompiledModule =
|
||||
## Returns 'nil' if the module needs to be recompiled.
|
||||
## Loads module from NIF file when optCompress is enabled.
|
||||
## When loadFullAst is true, loads the complete module AST for code generation.
|
||||
if not fileExists(toNifFilename(g.config, fileIdx)):
|
||||
return PrecompiledModule(module: nil)
|
||||
|
||||
# Create module symbol
|
||||
let filename = AbsoluteFile toFullPath(g.config, fileIdx)
|
||||
|
||||
let m = PSym(
|
||||
kindImpl: skModule,
|
||||
itemId: ItemId(module: int32(fileIdx), item: 0'i32),
|
||||
name: getIdent(g.cache, splitFile(filename).name),
|
||||
infoImpl: newLineInfo(fileIdx, 1, 1),
|
||||
positionImpl: int(fileIdx))
|
||||
setOwner(m, getPackage(g.config, g.cache, fileIdx))
|
||||
# Register module in graph
|
||||
registerModule(g, m)
|
||||
|
||||
result = loadNifModule(ast.program, fileIdx,
|
||||
g.ifaces[fileIdx.int].interf,
|
||||
g.ifaces[fileIdx.int].interfHidden, flags)
|
||||
result.module = m
|
||||
|
||||
# Mark module as cached
|
||||
g.cachedMods.incl fileIdx.int
|
||||
|
||||
# Register hooks from NIF index with the module graph
|
||||
for x in result.logOps:
|
||||
case x.kind
|
||||
of HookEntry:
|
||||
g.loadedOps[x.op][x.key] = x.sym
|
||||
of ConverterEntry:
|
||||
g.ifaces[fileIdx.int].converters.add x.sym
|
||||
of MethodEntry:
|
||||
discard "todo"
|
||||
of EnumToStrEntry:
|
||||
g.loadedEnumToStringProcs[x.key] = x.sym
|
||||
of GenericInstEntry:
|
||||
raiseAssert "GenericInstEntry should not be in the NIF index"
|
||||
# Register methods per type from NIF index
|
||||
discard "todo"
|
||||
proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex;
|
||||
cachedModules: var seq[FileIndex]): PSym =
|
||||
## Returns 'nil' if the module needs to be recompiled.
|
||||
if g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}:
|
||||
result = moduleFromRodFile(g.packed, g.config, g.cache, fileIdx, cachedModules)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc configComplete*(g: ModuleGraph) =
|
||||
#rememberStartupConfig(g.startupPackedConfig, g.config)
|
||||
discard
|
||||
rememberStartupConfig(g.startupPackedConfig, g.config)
|
||||
|
||||
proc onProcessing*(graph: ModuleGraph, fileIdx: FileIndex, moduleStatus: string, fromModule: PSym) =
|
||||
proc onProcessing*(graph: ModuleGraph, fileIdx: FileIndex, moduleStatus: string, fromModule: PSym, ) =
|
||||
let conf = graph.config
|
||||
let isNimscript = conf.isDefined("nimscript")
|
||||
if (not isNimscript) or hintProcessing in conf.cmdlineNotes:
|
||||
@@ -728,7 +763,7 @@ proc getPackage*(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
result = pkgSym
|
||||
graph.packageSyms.strTableAdd(pkgSym)
|
||||
|
||||
proc belongsToStdlib*(graph: ModuleGraph, sym: PSym): bool =
|
||||
func belongsToStdlib*(graph: ModuleGraph, sym: PSym): bool =
|
||||
## Check if symbol belongs to the 'stdlib' package.
|
||||
sym.getPackageSymbol.getPackageId == graph.systemModule.getPackageId
|
||||
|
||||
|
||||
@@ -109,11 +109,9 @@ proc mangleModuleName*(conf: ConfigRef; path: AbsoluteFile): string =
|
||||
of FromSearchPath: "@p"
|
||||
of FromNimblePath: "@n"
|
||||
|
||||
# Note: We encode ".." specially as "@d" to avoid issues with changeFileExt
|
||||
# which would misinterpret ".." as "name.ext" and strip the second part.
|
||||
prefix & best.multiReplace(
|
||||
{"..": "@d", $os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"})
|
||||
{$os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"})
|
||||
|
||||
proc demangleModuleName*(path: string): string =
|
||||
## Demangle a relative module path.
|
||||
result = path.multiReplace({"@@": "@", "@d": "..", "@h": "#", "@s": "/", "@m": "", "@p": "", "@n": "", "@c": ":"})
|
||||
result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@p": "", "@n": "", "@c": ":"})
|
||||
|
||||
@@ -32,9 +32,9 @@ proc newModule*(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
|
||||
# We cannot call ``newSym`` here, because we have to circumvent the ID
|
||||
# mechanism, which we do in order to assign each module a persistent ID.
|
||||
result = PSym(kindImpl: skModule, itemId: ItemId(module: int32(fileIdx), item: 0'i32),
|
||||
result = PSym(kind: skModule, itemId: ItemId(module: int32(fileIdx), item: 0'i32),
|
||||
name: getModuleIdent(graph, filename),
|
||||
infoImpl: newLineInfo(fileIdx, 1, 1))
|
||||
info: newLineInfo(fileIdx, 1, 1))
|
||||
if not isNimIdentifier(result.name.s):
|
||||
rawMessage(graph.config, errGenerated, "invalid module name: '" & result.name.s &
|
||||
"'; a module name must be a valid Nim identifier.")
|
||||
|
||||
@@ -30,6 +30,7 @@ proc toLowerAscii(a: var string) {.inline.} =
|
||||
|
||||
proc flushDot*(conf: ConfigRef) =
|
||||
## safe to call multiple times
|
||||
# xxx one edge case not yet handled is when `printf` is called at CT with `compiletimeFFI`.
|
||||
let stdOrr = if optStdout in conf.globalOptions: stdout else: stderr
|
||||
let stdOrrKind = toStdOrrKind(stdOrr)
|
||||
if stdOrrKind in conf.lastMsgWasDot:
|
||||
@@ -51,7 +52,7 @@ proc makeCString*(s: string): Rope =
|
||||
result = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
|
||||
result.add("\"")
|
||||
for i in 0..<s.len:
|
||||
# line wrapping of string literals in cgen'd code was a bad idea, e.g. causes: bug #16265
|
||||
# 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:
|
||||
@@ -59,12 +60,12 @@ proc makeCString*(s: string): Rope =
|
||||
toCChar(s[i], result)
|
||||
result.add('\"')
|
||||
|
||||
proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile; kind = fikSource): TFileInfo =
|
||||
proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo =
|
||||
result = TFileInfo(fullPath: fullPath, projPath: projPath,
|
||||
shortName: fullPath.extractFilename,
|
||||
quotedFullName: fullPath.string.makeCString,
|
||||
lines: @[],
|
||||
kind: kind)
|
||||
lines: @[]
|
||||
)
|
||||
result.quotedName = result.shortName.makeCString
|
||||
when defined(nimpretty):
|
||||
if not result.fullPath.isEmpty:
|
||||
@@ -132,23 +133,6 @@ proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex =
|
||||
var dummy: bool = false
|
||||
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy)
|
||||
|
||||
proc registerNifSuffix*(conf: ConfigRef; suffix: string; isKnownFile: var bool): FileIndex =
|
||||
result = conf.m.filenameToIndexTbl.getOrDefault(suffix, InvalidFileIdx)
|
||||
if result == InvalidFileIdx:
|
||||
isKnownFile = false
|
||||
result = conf.m.fileInfos.len.FileIndex
|
||||
conf.m.fileInfos.add(newFileInfo(AbsoluteFile suffix, RelativeFile suffix, fikNifModule))
|
||||
conf.m.filenameToIndexTbl[suffix] = result
|
||||
else:
|
||||
isKnownFile = true
|
||||
|
||||
proc fileInfoKind*(conf: ConfigRef; fileIdx: FileIndex): FileInfoKind =
|
||||
## Returns the kind of a FileIndex (source file or NIF module suffix).
|
||||
if fileIdx.int >= 0 and fileIdx.int < conf.m.fileInfos.len:
|
||||
result = conf.m.fileInfos[fileIdx.int].kind
|
||||
else:
|
||||
result = fikSource # Default to source for unknown indices
|
||||
|
||||
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
|
||||
result = TLineInfo(fileIndex: fileInfoIdx)
|
||||
if line < int high(uint16):
|
||||
@@ -240,7 +224,7 @@ proc setDirtyFile*(conf: ConfigRef; fileIdx: FileIndex; filename: AbsoluteFile)
|
||||
|
||||
proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
|
||||
assert fileIdx.int32 >= 0
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc) or defined(gcYrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
conf.m.fileInfos[fileIdx.int32].hash = hash
|
||||
else:
|
||||
shallowCopy(conf.m.fileInfos[fileIdx.int32].hash, hash)
|
||||
@@ -248,7 +232,7 @@ proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
|
||||
|
||||
proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string =
|
||||
assert fileIdx.int32 >= 0
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc) or defined(gcYrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
result = conf.m.fileInfos[fileIdx.int32].hash
|
||||
else:
|
||||
shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash)
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2025 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## NIF-based C/C++ code generator backend.
|
||||
##
|
||||
## This module implements C code generation from precompiled NIF files.
|
||||
## It traverses the module dependency graph starting from the main module
|
||||
## and generates C code for all reachable modules.
|
||||
##
|
||||
## Usage:
|
||||
## 1. Compile modules to NIF: nim m mymodule.nim
|
||||
## 2. Generate C from NIF: nim nifc myproject.nim
|
||||
|
||||
import std/[intsets, tables, sets, os]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
import ast, options, lineinfos, modulegraphs, cgendata, cgen,
|
||||
pathutils, extccomp, msgs, modulepaths, idents, types, ast2nif
|
||||
|
||||
proc loadModuleDependencies(g: ModuleGraph; mainFileIdx: FileIndex): seq[PrecompiledModule] =
|
||||
## Traverse the module dependency graph using a stack.
|
||||
## Returns all modules that need code generation, in dependency order.
|
||||
let mainModule = moduleFromNifFile(g, mainFileIdx, {LoadFullAst})
|
||||
|
||||
var stack: seq[ModuleSuffix] = @[]
|
||||
result = @[]
|
||||
|
||||
if mainModule.module != nil:
|
||||
incl mainModule.module.flagsImpl, sfMainModule
|
||||
for dep in mainModule.deps:
|
||||
stack.add dep
|
||||
|
||||
var visited = initHashSet[string]()
|
||||
|
||||
while stack.len > 0:
|
||||
let suffix = stack.pop()
|
||||
|
||||
if not visited.containsOrIncl(suffix.string):
|
||||
var isKnownFile = false
|
||||
let fileIdx = g.config.registerNifSuffix(suffix.string, isKnownFile)
|
||||
let precomp = moduleFromNifFile(g, fileIdx, {LoadFullAst})
|
||||
if precomp.module != nil:
|
||||
result.add precomp
|
||||
for dep in precomp.deps:
|
||||
if not visited.contains(dep.string):
|
||||
stack.add dep
|
||||
else:
|
||||
assert false, "Recompiling module is not implemented."
|
||||
|
||||
if mainModule.module != nil:
|
||||
result.add mainModule
|
||||
|
||||
proc setupNifBackendModule(g: ModuleGraph; module: PSym): BModule =
|
||||
## Set up a BModule for code generation from a NIF module.
|
||||
if g.backend == nil:
|
||||
g.backend = cgendata.newModuleList(g)
|
||||
result = cgen.newModule(BModuleList(g.backend), module, g.config, idGeneratorFromModule(module))
|
||||
|
||||
proc finishModule(g: ModuleGraph; bmod: BModule) =
|
||||
# Finalize the module (this adds it to modulesClosed)
|
||||
# Create an empty stmt list as the init body - genInitCode in writeModule will set it up properly
|
||||
let initStmt = newNode(nkStmtList)
|
||||
finalCodegenActions(g, bmod, initStmt)
|
||||
|
||||
# Generate dispatcher methods
|
||||
for disp in getDispatchers(g):
|
||||
genProcLvl3(bmod, disp)
|
||||
|
||||
proc generateCodeForModule(g: ModuleGraph; precomp: PrecompiledModule) =
|
||||
## Generate C code for a single module.
|
||||
let moduleId = precomp.module.position
|
||||
var bmod = BModuleList(g.backend).mods[moduleId]
|
||||
if bmod == nil:
|
||||
bmod = setupNifBackendModule(g, precomp.module)
|
||||
|
||||
# Generate code for the module's top-level statements
|
||||
if precomp.topLevel != nil:
|
||||
cgen.genTopLevelStmt(bmod, precomp.topLevel)
|
||||
|
||||
proc generateCode*(g: ModuleGraph; mainFileIdx: FileIndex) =
|
||||
## Main entry point for NIF-based C code generation.
|
||||
## Traverses the module dependency graph and generates C code.
|
||||
|
||||
# Reset backend state
|
||||
resetForBackend(g)
|
||||
|
||||
var isKnownFile = false
|
||||
let systemFileIdx = registerNifSuffix(g.config, "sysma2dyk", isKnownFile)
|
||||
g.config.m.systemFileIdx = systemFileIdx
|
||||
#msgs.fileInfoIdx(g.config,
|
||||
# g.config.libpath / RelativeFile"system.nim")
|
||||
|
||||
# Load system module first - it's always needed and contains essential hooks
|
||||
var precompSys = PrecompiledModule(module: nil)
|
||||
precompSys = moduleFromNifFile(g, systemFileIdx, {LoadFullAst, AlwaysLoadInterface})
|
||||
g.systemModule = precompSys.module
|
||||
|
||||
# Load all modules in dependency order using stack traversal
|
||||
# This must happen BEFORE any code generation so that hooks are loaded into loadedOps
|
||||
let modules = loadModuleDependencies(g, mainFileIdx)
|
||||
if modules.len == 0:
|
||||
rawMessage(g.config, errGenerated,
|
||||
"Cannot load NIF file for main module: " & toFullPath(g.config, mainFileIdx))
|
||||
return
|
||||
|
||||
# Set up backend modules for all modules that need code generation
|
||||
for m in modules:
|
||||
discard setupNifBackendModule(g, m.module)
|
||||
|
||||
# Also ensure system module is set up and generated first if it exists
|
||||
if precompSys.module != nil:
|
||||
discard setupNifBackendModule(g, precompSys.module)
|
||||
generateCodeForModule(g, precompSys)
|
||||
|
||||
# Track which modules have been processed to avoid duplicates
|
||||
var processed = initIntSet()
|
||||
if precompSys.module != nil:
|
||||
processed.incl precompSys.module.position
|
||||
|
||||
# Generate code for all modules (skip system since it's already processed)
|
||||
for m in modules:
|
||||
if not processed.containsOrIncl(m.module.position):
|
||||
generateCodeForModule(g, m)
|
||||
|
||||
# during code generation of `main.nim` we can trigger the code generation
|
||||
# of symbols in different modules so we need to finish these modules
|
||||
# here later, after the above loop!
|
||||
# Important: The main module must be finished LAST so that all other modules
|
||||
# have registered their init procs before genMainProc uses them.
|
||||
var mainModule: BModule = nil
|
||||
for m in BModuleList(g.backend).mods:
|
||||
if m != nil:
|
||||
assert m.module != nil
|
||||
if sfMainModule in m.module.flags:
|
||||
mainModule = m
|
||||
else:
|
||||
finishModule g, m
|
||||
if mainModule != nil:
|
||||
finishModule g, mainModule
|
||||
|
||||
# Write C files
|
||||
cgenWriteModules(g.backend, g.config)
|
||||
|
||||
# Run C compiler
|
||||
if g.config.cmd != cmdTcc:
|
||||
extccomp.callCCompiler(g.config)
|
||||
if not g.config.hcrOn:
|
||||
extccomp.writeJsonBuildInstructions(g.config, g.cachedFiles)
|
||||
1690
compiler/nifgen.nim
1690
compiler/nifgen.nim
File diff suppressed because it is too large
Load Diff
@@ -919,7 +919,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
|
||||
newSymNode(op, r.info),
|
||||
l,
|
||||
r)
|
||||
result.typ = newType(tyBool, ctx.idgen, nil)
|
||||
result.typ() = newType(tyBool, ctx.idgen, nil)
|
||||
|
||||
proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
|
||||
var cache = newIdentCache()
|
||||
@@ -929,7 +929,7 @@ proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
|
||||
result = nkPrefix.newTree(
|
||||
newSymNode(op, node.info),
|
||||
node)
|
||||
result.typ = newType(tyBool, ctx.idgen, nil)
|
||||
result.typ() = newType(tyBool, ctx.idgen, nil)
|
||||
|
||||
proc infixEq(ctx: NilCheckerContext, l: PNode, r: PNode): PNode =
|
||||
infix(ctx, l, r, mEqRef)
|
||||
|
||||
@@ -12,8 +12,7 @@ define:nimPreviewNonVarDestructor
|
||||
define:nimPreviewCheckedClose
|
||||
define:nimPreviewAsmSemSymbol
|
||||
define:nimPreviewCStringComparisons
|
||||
#define:nimPreviewDuplicateModuleError
|
||||
# Incompatible with Nimony's compat2.nim for now
|
||||
define:nimPreviewDuplicateModuleError
|
||||
|
||||
threads:off
|
||||
|
||||
@@ -66,7 +65,3 @@ define:useStdoutAsStdmsg
|
||||
@if nimHasVtables:
|
||||
experimental:vtables
|
||||
@end
|
||||
|
||||
@if nimHasImplicitRangeConversion:
|
||||
warning[ImplicitRangeConversion]:off
|
||||
@end
|
||||
|
||||
@@ -118,14 +118,9 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
|
||||
if conf.selectedGC == gcUnselected:
|
||||
if conf.backend in {backendC, backendCpp, backendObjc} or
|
||||
(conf.cmd in cmdDocLike and conf.backend != backendJs) or
|
||||
conf.cmd in {cmdGendepend, cmdNifC, cmdIc, cmdM}:
|
||||
conf.cmd == cmdGendepend:
|
||||
initOrcDefines(conf)
|
||||
|
||||
if conf.selectedStrings == stringSso and
|
||||
conf.selectedGC notin {gcArc, gcOrc, gcYrc, gcAtomicArc}:
|
||||
rawMessage(conf, errGenerated,
|
||||
"--strings:sso requires --mm:arc, --mm:orc, --mm:yrc, or --mm:atomicArc")
|
||||
|
||||
mainCommand(graph)
|
||||
if conf.hasHint(hintGCStats): echo(GC_getStatistics())
|
||||
#echo(GC_getStatistics())
|
||||
|
||||
@@ -128,7 +128,7 @@ proc createInterpreter*(scriptName: string;
|
||||
if conf.libpath.isEmpty: conf.libpath = AbsoluteDir p
|
||||
|
||||
var m = graph.makeModule(scriptName)
|
||||
incl(m, sfMainModule)
|
||||
incl(m.flags, sfMainModule)
|
||||
var idgen = idGeneratorFromModule(m)
|
||||
var vm = newCtx(m, cache, graph, idgen)
|
||||
vm.mode = emRepl
|
||||
@@ -168,7 +168,7 @@ proc runRepl*(r: TLLRepl;
|
||||
if supportNimscript: defineSymbol(conf.symbols, "nimconfig")
|
||||
when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
|
||||
var m = graph.makeStdinModule()
|
||||
incl(m, sfMainModule)
|
||||
incl(m.flags, sfMainModule)
|
||||
var idgen = idGeneratorFromModule(m)
|
||||
|
||||
if supportNimscript: graph.vm = setupVM(m, cache, "stdin", graph, idgen)
|
||||
|
||||
@@ -84,7 +84,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
|
||||
elemType = settype[0]
|
||||
first = firstOrd(conf, elemType).toInt64
|
||||
result = newNodeI(nkCurly, info)
|
||||
result.typ = settype
|
||||
result.typ() = settype
|
||||
result.info = info
|
||||
e = 0
|
||||
while e < s.len * ElemSize:
|
||||
@@ -101,7 +101,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
|
||||
result.add aa
|
||||
else:
|
||||
n = newNodeI(nkRange, info)
|
||||
n.typ = elemType
|
||||
n.typ() = elemType
|
||||
n.add aa
|
||||
let bb = newIntTypeNode(b + first, elemType)
|
||||
bb.info = info
|
||||
|
||||
@@ -113,8 +113,6 @@ type # please make sure we have under 32 options
|
||||
optJsBigInt64 # use bigints for 64-bit integers in JS
|
||||
optDocRaw # for documentation: Don't render markdown for JSON output
|
||||
optItaniumMangle # mangling follows the Itanium spec
|
||||
optCompress # turn on AST compression by converting it to NIF
|
||||
optWithinConfigSystem # we still compile within the configuration system
|
||||
|
||||
TGlobalOptions* = set[TGlobalOption]
|
||||
|
||||
@@ -144,7 +142,6 @@ type
|
||||
backendCpp = "cpp"
|
||||
backendJs = "js"
|
||||
backendObjc = "objc"
|
||||
backendNif = "nif"
|
||||
# backendNimscript = "nimscript" # this could actually work
|
||||
# backendLlvm = "llvm" # probably not well supported; was cmdCompileToLLVM
|
||||
|
||||
@@ -157,6 +154,7 @@ type
|
||||
cmdCheck # semantic checking for whole project
|
||||
cmdM # only compile a single
|
||||
cmdParse # parse a single file (for debugging)
|
||||
cmdRod # .rod to some text representation (for debugging)
|
||||
cmdIdeTools # ide tools (e.g. nimsuggest)
|
||||
cmdNimscript # evaluate nimscript
|
||||
cmdDoc0
|
||||
@@ -176,13 +174,10 @@ type
|
||||
cmdNop
|
||||
cmdJsonscript # compile a .json build file
|
||||
# old unused: cmdInterpret, cmdDef: def feature (find definition for IDEs)
|
||||
cmdCompileToNif
|
||||
cmdNifC # generate C code from NIF files
|
||||
cmdIc # generate .build.nif for nifmake
|
||||
|
||||
const
|
||||
cmdBackends* = {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
|
||||
cmdCompileToJS, cmdCrun, cmdCompileToNif}
|
||||
cmdCompileToJS, cmdCrun}
|
||||
cmdDocLike* = {cmdDoc0, cmdDoc, cmdDoc2tex, cmdJsondoc0, cmdJsondoc,
|
||||
cmdCtags, cmdBuildindex}
|
||||
|
||||
@@ -195,7 +190,6 @@ type
|
||||
gcRegions = "regions"
|
||||
gcArc = "arc"
|
||||
gcOrc = "orc"
|
||||
gcYrc = "yrc" # thread-safe ORC (concurrent cycle collector)
|
||||
gcAtomicArc = "atomicArc"
|
||||
gcMarkAndSweep = "markAndSweep"
|
||||
gcHooks = "hooks"
|
||||
@@ -231,7 +225,7 @@ type
|
||||
strictEffects,
|
||||
unicodeOperators, # deadcode
|
||||
flexibleOptionalParams,
|
||||
strictDefs, # deadcode
|
||||
strictDefs,
|
||||
strictCaseObjects,
|
||||
inferGenericTypes,
|
||||
openSym, # remove nfDisabledOpenSym when this is default
|
||||
@@ -259,9 +253,6 @@ type
|
||||
## Old transformation for closures in JS backend
|
||||
noPanicOnExcept
|
||||
## don't panic on bare except
|
||||
procParamTypeBackendAliases
|
||||
## Keep the old proc type compatibility rules that ignore backend
|
||||
## c type aliases.
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
|
||||
@@ -270,10 +261,6 @@ type
|
||||
ccNone, ccGcc, ccNintendoSwitch, ccLLVM_Gcc, ccCLang, ccBcc, ccVcc,
|
||||
ccTcc, ccEnv, ccIcl, ccIcc, ccClangCl, ccHipcc, ccNvcc
|
||||
|
||||
StringsMode* = enum
|
||||
stringDefault = "default"
|
||||
stringSso = "sso"
|
||||
|
||||
ExceptionSystem* = enum
|
||||
excNone, # no exception system selected yet
|
||||
excSetjmp, # setjmp based exception handling
|
||||
@@ -373,13 +360,11 @@ type
|
||||
implicitCmd*: bool # whether some flag triggered an implicit `command`
|
||||
selectedGC*: TGCMode # the selected GC (+)
|
||||
exc*: ExceptionSystem
|
||||
selectedStrings*: StringsMode
|
||||
hintProcessingDots*: bool # true for dots, false for filenames
|
||||
verbosity*: int # how verbose the compiler is
|
||||
numberOfProcessors*: int # number of processors
|
||||
lastCmdTime*: float # when caas is enabled, we measure each command
|
||||
symbolFiles*: SymbolFilesOption
|
||||
ic*: bool # whether ic is enabled
|
||||
spellSuggestMax*: int # max number of spelling suggestions for typos
|
||||
|
||||
cppDefines*: HashSet[string] # (*)
|
||||
@@ -524,7 +509,7 @@ const
|
||||
optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs`
|
||||
optTrMacros, optStyleCheck, optCursorInference}
|
||||
DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace,
|
||||
optJsBigInt64, optItaniumMangle}
|
||||
optJsBigInt64}
|
||||
|
||||
proc getSrcTimestamp(): DateTime =
|
||||
try:
|
||||
@@ -706,7 +691,6 @@ template quitOrRaise*(conf: ConfigRef, msg = "") =
|
||||
|
||||
proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in cmdDocLike + {cmdIdeTools}
|
||||
proc usesWriteBarrier*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
|
||||
proc usesSso*(conf: ConfigRef): bool {.inline.} = conf.selectedStrings == stringSso
|
||||
|
||||
template compilationCachePresent*(conf: ConfigRef): untyped =
|
||||
false
|
||||
|
||||
@@ -33,7 +33,7 @@ proc getPackage*(conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym =
|
||||
pkgIdent = getIdent(cache, pkgName)
|
||||
newSym(skPackage, pkgIdent, idGeneratorForPackage(int32(fileIdx)), nil, info)
|
||||
|
||||
proc getPackageSymbol*(sym: PSym): PSym =
|
||||
func getPackageSymbol*(sym: PSym): PSym =
|
||||
## Return the owning package symbol.
|
||||
assert sym != nil
|
||||
result = sym
|
||||
@@ -41,18 +41,18 @@ proc getPackageSymbol*(sym: PSym): PSym =
|
||||
result = result.owner
|
||||
assert result != nil, repr(sym.info)
|
||||
|
||||
proc getPackageId*(sym: PSym): int =
|
||||
func getPackageId*(sym: PSym): int =
|
||||
## Return the owning package ID.
|
||||
sym.getPackageSymbol.id
|
||||
|
||||
proc belongsToProjectPackage*(conf: ConfigRef, sym: PSym): bool =
|
||||
func belongsToProjectPackage*(conf: ConfigRef, sym: PSym): bool =
|
||||
## Return whether the symbol belongs to the project's package.
|
||||
##
|
||||
## See Also:
|
||||
## * `modulegraphs.belongsToStdlib`
|
||||
conf.mainPackageId == sym.getPackageId
|
||||
|
||||
proc belongsToProjectPackageMaybeNil*(conf: ConfigRef, sym: PSym): bool =
|
||||
func belongsToProjectPackageMaybeNil*(conf: ConfigRef, sym: PSym): bool =
|
||||
## Return whether the symbol belongs to the project's package.
|
||||
## Returns `false` if `sym` is nil.
|
||||
##
|
||||
|
||||
@@ -148,6 +148,11 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
|
||||
closeParser(p)
|
||||
if s.kind != llsStdIn: break
|
||||
closePasses(graph, a)
|
||||
if graph.config.backend notin {backendC, backendCpp, backendObjc}:
|
||||
# We only write rod files here if no C-like backend is active.
|
||||
# The C-like backends have been patched to support the IC mechanism.
|
||||
# They are responsible for closing the rod files. See `cbackend.nim`.
|
||||
closeRodFile(graph, module)
|
||||
result = true
|
||||
|
||||
proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym =
|
||||
@@ -163,12 +168,24 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fr
|
||||
elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput)
|
||||
discard processModule(graph, result, idGeneratorFromModule(result), s)
|
||||
if result == nil:
|
||||
result = newModule(graph, fileIdx)
|
||||
result.incl flags
|
||||
registerModule(graph, result)
|
||||
processModuleAux("import")
|
||||
var cachedModules: seq[FileIndex] = @[]
|
||||
result = moduleFromRodFile(graph, fileIdx, cachedModules)
|
||||
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
|
||||
if result == nil:
|
||||
result = newModule(graph, fileIdx)
|
||||
result.flags.incl flags
|
||||
registerModule(graph, result)
|
||||
processModuleAux("import")
|
||||
else:
|
||||
if sfSystemModule in flags:
|
||||
graph.systemModule = result
|
||||
partialInitModule(result, graph, fileIdx, filename)
|
||||
for m in cachedModules:
|
||||
registerModuleById(graph, m)
|
||||
replayStateChanges(graph.packed.pm[m.int].module, graph)
|
||||
replayGenericCacheInformation(graph, m.int)
|
||||
elif graph.isDirty(result):
|
||||
result.excl sfDirty
|
||||
result.flags.excl sfDirty
|
||||
# reset module fields:
|
||||
initStrTables(graph, result)
|
||||
result.ast = nil
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import sem, cgen, modulegraphs, ast, llstream, parser, msgs,
|
||||
lineinfos, reorder, options, semdata, cgendata, modules, pathutils,
|
||||
packages, syntaxes, depends, vm, pragmas, idents, lookups, wordrecg,
|
||||
liftdestructors, nifgen
|
||||
|
||||
when not defined(nimKochBootstrap):
|
||||
import vmdef
|
||||
import ast2nif
|
||||
import "../dist/nimony/src/lib" / [nifstreams, bitabs]
|
||||
liftdestructors
|
||||
|
||||
import pipelineutils
|
||||
|
||||
@@ -28,10 +23,6 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext):
|
||||
result = semNode
|
||||
if bModule != nil:
|
||||
genTopLevelStmt(BModule(bModule), result)
|
||||
of NifgenPass:
|
||||
result = semNode
|
||||
if bModule != nil:
|
||||
genTopLevelNif(bModule, result)
|
||||
of JSgenPass:
|
||||
when not defined(leanCompiler):
|
||||
result = processJSCodeGen(bModule, semNode)
|
||||
@@ -40,12 +31,7 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext):
|
||||
of GenDependPass:
|
||||
result = addDotDependency(bModule, semNode)
|
||||
of SemPass:
|
||||
# Return the semantic node for cmdM (NIF generation needs it)
|
||||
# For regular check, we don't need the result
|
||||
if graph.config.cmd == cmdM:
|
||||
result = semNode
|
||||
else:
|
||||
result = graph.emptyNode
|
||||
result = graph.emptyNode
|
||||
of Docgen2Pass, Docgen2TexPass:
|
||||
when not defined(leanCompiler):
|
||||
result = processNode(bModule, semNode)
|
||||
@@ -62,8 +48,7 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext):
|
||||
raiseAssert "use setPipeLinePass to set a proper PipelinePass"
|
||||
|
||||
proc processImplicitImports*(graph: ModuleGraph; implicits: seq[string], nodeKind: TNodeKind,
|
||||
m: PSym, ctx: PContext, bModule: PPassContext, idgen: IdGenerator;
|
||||
topLevelStmts: PNode) =
|
||||
m: PSym, ctx: PContext, bModule: PPassContext, idgen: IdGenerator) =
|
||||
# XXX fixme this should actually be relative to the config file!
|
||||
let relativeTo = toFullPath(graph.config, m.info)
|
||||
for module in items(implicits):
|
||||
@@ -75,13 +60,8 @@ proc processImplicitImports*(graph: ModuleGraph; implicits: seq[string], nodeKin
|
||||
importStmt.add str
|
||||
message(graph.config, importStmt.info, hintProcessingStmt, $idgen[])
|
||||
let semNode = semWithPContext(ctx, importStmt)
|
||||
if semNode == nil:
|
||||
if semNode == nil or processPipeline(graph, semNode, bModule) == nil:
|
||||
break
|
||||
let top = processPipeline(graph, semNode, bModule)
|
||||
if top == nil:
|
||||
break
|
||||
if topLevelStmts != nil:
|
||||
topLevelStmts.add top
|
||||
|
||||
proc prePass*(c: PContext; n: PNode) =
|
||||
for son in n:
|
||||
@@ -103,7 +83,7 @@ proc prePass*(c: PContext; n: PNode) =
|
||||
let feature = parseEnum[Feature](name.strVal)
|
||||
if feature == codeReordering:
|
||||
c.features.incl feature
|
||||
c.module.incl sfReorder
|
||||
c.module.flags.incl sfReorder
|
||||
except ValueError:
|
||||
discard
|
||||
else:
|
||||
@@ -151,8 +131,6 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
nil
|
||||
of SemPass:
|
||||
nil
|
||||
of NifgenPass:
|
||||
setupNifgen(graph, module, idgen)
|
||||
of NonePass:
|
||||
raiseAssert "use setPipeLinePass to set a proper PipelinePass"
|
||||
|
||||
@@ -166,11 +144,6 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
else:
|
||||
s = stream
|
||||
graph.interactive = stream.kind == llsStdIn
|
||||
var topLevelStmts =
|
||||
if optCompress in graph.config.globalOptions or graph.config.cmd == cmdM:
|
||||
newNodeI(nkStmtList, module.info)
|
||||
else:
|
||||
nil
|
||||
while true:
|
||||
syntaxes.openParser(p, fileIdx, s, graph.cache, graph.config)
|
||||
|
||||
@@ -180,8 +153,8 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
# in ROD files. I think we should enable this feature only
|
||||
# for the interactive mode.
|
||||
if module.name.s != "nimscriptapi":
|
||||
processImplicitImports graph, graph.config.implicitImports, nkImportStmt, module, ctx, bModule, idgen, topLevelStmts
|
||||
processImplicitImports graph, graph.config.implicitIncludes, nkIncludeStmt, module, ctx, bModule, idgen, topLevelStmts
|
||||
processImplicitImports graph, graph.config.implicitImports, nkImportStmt, module, ctx, bModule, idgen
|
||||
processImplicitImports graph, graph.config.implicitIncludes, nkIncludeStmt, module, ctx, bModule, idgen
|
||||
|
||||
checkFirstLineIndentation(p)
|
||||
block processCode:
|
||||
@@ -202,9 +175,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
if graph.pipelinePass != EvalPass:
|
||||
message(graph.config, sl.info, hintProcessingStmt, $idgen[])
|
||||
var semNode = semWithPContext(ctx, sl)
|
||||
let top = processPipeline(graph, semNode, bModule)
|
||||
if top != nil and topLevelStmts != nil:
|
||||
topLevelStmts.add top
|
||||
discard processPipeline(graph, semNode, bModule)
|
||||
|
||||
closeParser(p)
|
||||
if s.kind != llsStdIn: break
|
||||
@@ -221,7 +192,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
if retTyp != nil:
|
||||
# TODO: properly semcheck the code of dispatcher?
|
||||
createTypeBoundOps(graph, ctx, retTyp, disp.ast.info, idgen)
|
||||
genProcLvl3(m, disp)
|
||||
genProcAux(m, disp)
|
||||
discard closePContext(graph, ctx, nil)
|
||||
of JSgenPass:
|
||||
when not defined(leanCompiler):
|
||||
@@ -236,31 +207,14 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
of Docgen2JsonPass:
|
||||
when not defined(leanCompiler):
|
||||
discard closeJson(graph, bModule, finalNode)
|
||||
of NifgenPass:
|
||||
closeNif(graph, bModule, finalNode)
|
||||
of NonePass:
|
||||
raiseAssert "use setPipeLinePass to set a proper PipelinePass"
|
||||
|
||||
when not defined(nimKochBootstrap):
|
||||
# For cmdM: only write NIF for the main module, not for imported modules
|
||||
# (imported modules should be loaded from existing NIF files)
|
||||
let shouldWriteNif = (optCompress in graph.config.globalOptions) or
|
||||
(graph.config.cmd == cmdM and sfMainModule in module.flags)
|
||||
if shouldWriteNif and not graph.config.isDefined("nimscript"):
|
||||
topLevelStmts.add finalNode
|
||||
# Collect replay actions from both pragma computations and VM state diff
|
||||
var replayActions: seq[PNode] = @[]
|
||||
# Get pragma-recorded replay actions (compile, link, passC, passL, etc.)
|
||||
if graph.nifReplayActions.hasKey(module.position.int32):
|
||||
replayActions.add graph.nifReplayActions[module.position.int32]
|
||||
# Also get VM state diff (macro cache operations)
|
||||
if graph.vm != nil:
|
||||
for (m, n) in PCtx(graph.vm).vmstateDiff:
|
||||
if m == module:
|
||||
replayActions.add n
|
||||
|
||||
writeNifModule(graph.config, module.position.int32, topLevelStmts, graph.opsLog, replayActions)
|
||||
|
||||
if graph.config.backend notin {backendC, backendCpp, backendObjc}:
|
||||
# We only write rod files here if no C-like backend is active.
|
||||
# The C-like backends have been patched to support the IC mechanism.
|
||||
# They are responsible for closing the rod files. See `cbackend.nim`.
|
||||
closeRodFile(graph, module)
|
||||
result = true
|
||||
|
||||
proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags; fromModule: PSym = nil): PSym =
|
||||
@@ -276,30 +230,8 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF
|
||||
elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput)
|
||||
discard processPipelineModule(graph, result, idGeneratorFromModule(result), s)
|
||||
if result == nil:
|
||||
when not defined(nimKochBootstrap):
|
||||
# For cmdM: load imports from NIF files (but compile the main module from source)
|
||||
# Skip when withinSystem is true (compiling system.nim itself)
|
||||
if graph.config.cmd == cmdM and
|
||||
sfMainModule notin flags and
|
||||
not graph.withinSystem and
|
||||
not graph.config.isDefined("nimscript"):
|
||||
let precomp = moduleFromNifFile(graph, fileIdx)
|
||||
if precomp.module == nil:
|
||||
let nifPath = toNifFilename(graph.config, fileIdx)
|
||||
globalError(graph.config, unknownLineInfo,
|
||||
"nim m requires precompiled NIF for import: " & toFullPath(graph.config, fileIdx) &
|
||||
" (expected: " & nifPath & ")")
|
||||
return nil # Don't fall through to compile from source
|
||||
else:
|
||||
# Module successfully loaded from NIF file - use it and skip processing
|
||||
result = precomp.module
|
||||
if sfSystemModule in flags:
|
||||
graph.systemModule = result
|
||||
partialInitModule(result, graph, fileIdx, AbsoluteFile(toFullPath(graph.config, fileIdx)))
|
||||
# Replay state changes from the loaded NIF module
|
||||
if result.ast != nil:
|
||||
replayStateChanges(result, graph)
|
||||
return result # Return early, don't process from source
|
||||
var cachedModules: seq[FileIndex] = @[]
|
||||
result = moduleFromRodFile(graph, fileIdx, cachedModules)
|
||||
let path = toFullPath(graph.config, fileIdx)
|
||||
let filename = AbsoluteFile path
|
||||
# it could be a stdinfile/cmdfile
|
||||
@@ -307,19 +239,26 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF
|
||||
graph.cachedFiles[path] = $secureHashFile(path)
|
||||
if result == nil:
|
||||
result = newModule(graph, fileIdx)
|
||||
result.incl flags
|
||||
result.flags.incl flags
|
||||
registerModule(graph, result)
|
||||
processModuleAux("import")
|
||||
else:
|
||||
if sfSystemModule in flags:
|
||||
graph.systemModule = result
|
||||
if sfMainModule in flags and graph.config.cmd == cmdM:
|
||||
result.incl flags
|
||||
result.flags.incl flags
|
||||
registerModule(graph, result)
|
||||
processModuleAux("import")
|
||||
partialInitModule(result, graph, fileIdx, filename)
|
||||
for m in cachedModules:
|
||||
registerModuleById(graph, m)
|
||||
if sfMainModule in flags and graph.config.cmd == cmdM:
|
||||
discard
|
||||
else:
|
||||
replayStateChanges(graph.packed.pm[m.int].module, graph)
|
||||
replayGenericCacheInformation(graph, m.int)
|
||||
elif graph.isDirty(result):
|
||||
result.excl sfDirty
|
||||
result.flags.excl sfDirty
|
||||
# reset module fields:
|
||||
initStrTables(graph, result)
|
||||
result.ast = nil
|
||||
@@ -347,12 +286,10 @@ proc connectPipelineCallbacks*(graph: ModuleGraph) =
|
||||
|
||||
proc compilePipelineSystemModule*(graph: ModuleGraph) =
|
||||
if graph.systemModule == nil:
|
||||
graph.withinSystem = true
|
||||
connectPipelineCallbacks(graph)
|
||||
graph.config.m.systemFileIdx = fileInfoIdx(graph.config,
|
||||
graph.config.libpath / RelativeFile"system.nim")
|
||||
discard graph.compilePipelineModule(graph.config.m.systemFileIdx, {sfSystemModule})
|
||||
graph.withinSystem = false
|
||||
|
||||
proc compilePipelineProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) =
|
||||
connectPipelineCallbacks(graph)
|
||||
@@ -369,23 +306,7 @@ proc compilePipelineProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx
|
||||
graph.importStack.add projectFile
|
||||
|
||||
if projectFile == systemFileIdx:
|
||||
graph.withinSystem = true
|
||||
discard graph.compilePipelineModule(projectFile, {sfMainModule, sfSystemModule})
|
||||
graph.withinSystem = false
|
||||
elif graph.config.cmd == cmdM:
|
||||
# For cmdM: load system.nim from NIF first, then compile the main module
|
||||
connectPipelineCallbacks(graph)
|
||||
graph.config.m.systemFileIdx = fileInfoIdx(graph.config,
|
||||
graph.config.libpath / RelativeFile"system.nim")
|
||||
when not defined(nimKochBootstrap):
|
||||
let precomp = moduleFromNifFile(graph, graph.config.m.systemFileIdx)
|
||||
graph.systemModule = precomp.module
|
||||
if graph.systemModule == nil:
|
||||
let nifPath = toNifFilename(graph.config, graph.config.m.systemFileIdx)
|
||||
localError(graph.config, unknownLineInfo,
|
||||
"nim m requires precompiled NIF for system module (expected: " & nifPath & ")")
|
||||
return
|
||||
discard graph.compilePipelineModule(projectFile, {sfMainModule})
|
||||
else:
|
||||
graph.compilePipelineSystemModule()
|
||||
discard graph.compilePipelineModule(projectFile, {sfMainModule})
|
||||
|
||||
@@ -33,7 +33,7 @@ proc iterToProcImpl*(c: PContext, n: PNode): PNode =
|
||||
|
||||
let prc = newSym(skProc, n[3].ident, c.idgen, iter.sym.owner, iter.sym.info)
|
||||
prc.typ = copyType(iter.sym.typ, c.idgen, prc)
|
||||
excl prc.typ, tfCapturesEnv
|
||||
excl prc.typ.flags, tfCapturesEnv
|
||||
prc.typ.n.add newSymNode(getEnvParam(iter.sym))
|
||||
prc.typ.rawAddSon t
|
||||
let orig = iter.sym.ast
|
||||
|
||||
@@ -21,6 +21,8 @@ import std/[os, math, strutils]
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
from ic / ic import addCompilerProc
|
||||
|
||||
const
|
||||
FirstCallConv* = wNimcall
|
||||
LastCallConv* = wNoconv
|
||||
@@ -146,7 +148,7 @@ proc pragmaEnsures(c: PContext, n: PNode) =
|
||||
if o.kind in routineKinds and o.typ != nil and o.typ.returnType != nil:
|
||||
var s = newSym(skResult, getIdent(c.cache, "result"), c.idgen, o, n.info)
|
||||
s.typ = o.typ.returnType
|
||||
incl(s.flagsImpl, sfUsed)
|
||||
incl(s.flags, sfUsed)
|
||||
addDecl(c, s)
|
||||
n[1] = c.semExpr(c, n[1])
|
||||
closeScope(c)
|
||||
@@ -154,12 +156,12 @@ proc pragmaEnsures(c: PContext, n: PNode) =
|
||||
proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) =
|
||||
# special cases to improve performance:
|
||||
if extname == "$1":
|
||||
s.setSnippet(rope(s.name.s))
|
||||
s.loc.snippet = rope(s.name.s)
|
||||
elif '$' notin extname:
|
||||
s.setSnippet(rope(extname))
|
||||
s.loc.snippet = rope(extname)
|
||||
else:
|
||||
try:
|
||||
s.setSnippet(rope(extname % s.name.s))
|
||||
s.loc.snippet = rope(extname % s.name.s)
|
||||
except ValueError:
|
||||
localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
|
||||
when hasFFI:
|
||||
@@ -168,36 +170,36 @@ proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) =
|
||||
|
||||
proc makeExternImport(c: PContext; s: PSym, extname: string, info: TLineInfo) =
|
||||
setExternName(c, s, extname, info)
|
||||
s.incl(sfImportc)
|
||||
s.excl(sfForward)
|
||||
incl(s.flags, sfImportc)
|
||||
excl(s.flags, sfForward)
|
||||
|
||||
proc makeExternExport(c: PContext; s: PSym, extname: string, info: TLineInfo) =
|
||||
setExternName(c, s, extname, info)
|
||||
s.incl(sfExportc)
|
||||
incl(s.flags, sfExportc)
|
||||
|
||||
proc processImportCompilerProc(c: PContext; s: PSym, extname: string, info: TLineInfo) =
|
||||
setExternName(c, s, extname, info)
|
||||
s.incl(sfImportc)
|
||||
s.excl(sfForward)
|
||||
incl(s.locImpl.flags, lfImportCompilerProc)
|
||||
incl(s.flags, sfImportc)
|
||||
excl(s.flags, sfForward)
|
||||
incl(s.loc.flags, lfImportCompilerProc)
|
||||
|
||||
proc processImportCpp(c: PContext; s: PSym, extname: string, info: TLineInfo) =
|
||||
setExternName(c, s, extname, info)
|
||||
s.incl(sfImportc)
|
||||
incl(s.flagsImpl, sfInfixCall)
|
||||
excl(s.flagsImpl, sfForward)
|
||||
incl(s.flags, sfImportc)
|
||||
incl(s.flags, sfInfixCall)
|
||||
excl(s.flags, sfForward)
|
||||
if c.config.backend == backendC:
|
||||
let m = s.getModule()
|
||||
incl(m.flagsImpl, sfCompileToCpp)
|
||||
incl(m.flags, sfCompileToCpp)
|
||||
incl c.config.globalOptions, optMixedMode
|
||||
|
||||
proc processImportObjC(c: PContext; s: PSym, extname: string, info: TLineInfo) =
|
||||
setExternName(c, s, extname, info)
|
||||
s.incl(sfImportc)
|
||||
incl(s.flagsImpl, sfNamedParamCall)
|
||||
excl(s.flagsImpl, sfForward)
|
||||
incl(s.flags, sfImportc)
|
||||
incl(s.flags, sfNamedParamCall)
|
||||
excl(s.flags, sfForward)
|
||||
let m = s.getModule()
|
||||
m.incl(sfCompileToObjc)
|
||||
incl(m.flags, sfCompileToObjc)
|
||||
|
||||
proc newEmptyStrNode(c: PContext; n: PNode, strVal: string = ""): PNode {.noinline.} =
|
||||
result = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString))
|
||||
@@ -237,14 +239,14 @@ proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
|
||||
proc processVirtual(c: PContext, n: PNode, s: PSym, flag: TSymFlag) =
|
||||
s.constraint = newEmptyStrNode(c, n, getOptionalStr(c, n, "$1"))
|
||||
s.constraint.strVal = s.constraint.strVal % s.name.s
|
||||
s.flagsImpl.incl {flag, sfInfixCall, sfExportc, sfMangleCpp}
|
||||
s.flags.incl {flag, sfInfixCall, sfExportc, sfMangleCpp}
|
||||
|
||||
s.typ.callConv = ccMember
|
||||
incl c.config.globalOptions, optMixedMode
|
||||
|
||||
proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
|
||||
sym.constraint = getStrLitNode(c, n)
|
||||
sym.flagsImpl.incl sfCodegenDecl
|
||||
sym.flags.incl sfCodegenDecl
|
||||
|
||||
proc processMagic(c: PContext, n: PNode, s: PSym) =
|
||||
#if sfSystemModule notin c.module.flags:
|
||||
@@ -280,10 +282,10 @@ proc onOff(c: PContext, n: PNode, op: TOptions, resOptions: var TOptions) =
|
||||
|
||||
proc pragmaNoForward*(c: PContext, n: PNode; flag=sfNoForward) =
|
||||
if isTurnedOn(c, n):
|
||||
incl(c.module.flagsImpl, flag)
|
||||
incl(c.module.flags, flag)
|
||||
c.features.incl codeReordering
|
||||
else:
|
||||
excl(c.module.flagsImpl, flag)
|
||||
excl(c.module.flags, flag)
|
||||
# c.features.excl codeReordering
|
||||
|
||||
# deprecated as of 0.18.1
|
||||
@@ -355,9 +357,9 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
|
||||
var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
|
||||
if not lib.isOverridden:
|
||||
addToLib(lib, sym)
|
||||
sym.incl(lfDynamicLib)
|
||||
incl(sym.loc.flags, lfDynamicLib)
|
||||
else:
|
||||
sym.incl(lfExportLib)
|
||||
incl(sym.loc.flags, lfExportLib)
|
||||
# since we'll be loading the dynlib symbols dynamically, we must use
|
||||
# a calling convention that doesn't introduce custom name mangling
|
||||
# cdecl is the default - the user can override this explicitly
|
||||
@@ -433,7 +435,7 @@ proc processExperimental(c: PContext; n: PNode) =
|
||||
if not isTopLevel(c):
|
||||
localError(c.config, n.info,
|
||||
"Code reordering experimental pragma only valid at toplevel")
|
||||
c.module.flagsImpl.incl sfReorder
|
||||
c.module.flags.incl sfReorder
|
||||
except ValueError:
|
||||
localError(c.config, n[1].info, "unknown experimental feature")
|
||||
else:
|
||||
@@ -567,7 +569,7 @@ proc processCompile(c: PContext, n: PNode) =
|
||||
n[i] = c.semConstExpr(c, n[i])
|
||||
case n[i].kind
|
||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc) or defined(gcYrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
result = n[i].strVal
|
||||
else:
|
||||
shallowCopy(result, n[i].strVal)
|
||||
@@ -634,7 +636,7 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
|
||||
var e = searchInScopes(con, getIdent(con.cache, sub), amb)
|
||||
# XXX what to do here if 'amb' is true?
|
||||
if e != nil:
|
||||
incl(e.flagsImpl, sfUsed)
|
||||
incl(e.flags, sfUsed)
|
||||
if isDefined(con.config, "nimPreviewAsmSemSymbol"):
|
||||
result.add con.semExprWithType(con, newSymNode(e), {efTypeAllowed})
|
||||
else:
|
||||
@@ -723,12 +725,12 @@ proc processPragma(c: PContext, n: PNode, i: int) =
|
||||
proc pragmaRaisesOrTags(c: PContext, n: PNode) =
|
||||
proc processExc(c: PContext, x: PNode) =
|
||||
if c.hasUnresolvedArgs(c, x):
|
||||
x.typ = makeTypeFromExpr(c, x)
|
||||
x.typ() = makeTypeFromExpr(c, x)
|
||||
else:
|
||||
var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs)
|
||||
if t.kind notin {tyObject, tyOr}:
|
||||
localError(c.config, x.info, errGenerated, "invalid type for raises/tags list")
|
||||
x.typ = t
|
||||
x.typ() = t
|
||||
|
||||
if n.kind in nkPragmaCallKinds and n.len == 2:
|
||||
let it = n[1]
|
||||
@@ -755,21 +757,23 @@ proc typeBorrow(c: PContext; sym: PSym, n: PNode) =
|
||||
let it = n[1]
|
||||
if it.kind != nkAccQuoted:
|
||||
localError(c.config, n.info, "a type can only borrow `.` for now")
|
||||
incl(sym.typ, tfBorrowDot)
|
||||
incl(sym.typ.flags, tfBorrowDot)
|
||||
|
||||
proc markCompilerProc(c: PContext; s: PSym) =
|
||||
# minor hack ahead: FlowVar is the only generic .compilerproc type which
|
||||
# should not have an external name set:
|
||||
if s.kind != skType or s.name.s != "FlowVar":
|
||||
makeExternExport(c, s, "$1", s.info)
|
||||
incl(s, sfCompilerProc)
|
||||
incl(s.flagsImpl, sfUsed)
|
||||
incl(s.flags, sfCompilerProc)
|
||||
incl(s.flags, sfUsed)
|
||||
registerCompilerProc(c.graph, s)
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
addCompilerProc(c.encoder, c.packedRepr, s)
|
||||
|
||||
proc deprecatedStmt(c: PContext; outerPragma: PNode) =
|
||||
let pragma = outerPragma[1]
|
||||
if pragma.kind in {nkStrLit..nkTripleStrLit}:
|
||||
incl(c.module, sfDeprecated)
|
||||
incl(c.module.flags, sfDeprecated)
|
||||
c.module.constraint = getStrLitNode(c, outerPragma)
|
||||
return
|
||||
if pragma.kind != nkBracket:
|
||||
@@ -838,7 +842,7 @@ proc processEffectsOf(c: PContext, n: PNode; owner: PSym) =
|
||||
let r = c.semExpr(c, n)
|
||||
if r.kind == nkSym and r.sym.kind == skParam:
|
||||
if r.sym.owner == owner:
|
||||
incl r.sym, sfEffectsDelayed
|
||||
incl r.sym.flags, sfEffectsDelayed
|
||||
else:
|
||||
localError(c.config, n.info, errGenerated, "parameter cannot be declared as .effectsOf")
|
||||
else:
|
||||
@@ -903,8 +907,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
if c.config.backend != backendCpp:
|
||||
localError(c.config, it.info, "exportcpp requires `cpp` backend, got: " & $c.config.backend)
|
||||
else:
|
||||
incl(sym, sfMangleCpp)
|
||||
incl(sym.flagsImpl, sfUsed) # avoid wrong hints
|
||||
incl(sym.flags, sfMangleCpp)
|
||||
incl(sym.flags, sfUsed) # avoid wrong hints
|
||||
of wImportc:
|
||||
let name = getOptionalStr(c, it, "$1")
|
||||
cppDefine(c.config, name)
|
||||
@@ -917,24 +921,24 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
processImportCompilerProc(c, sym, name, it.info)
|
||||
of wExtern: setExternName(c, sym, expectStrLit(c, it), it.info)
|
||||
of wDirty:
|
||||
if sym.kind == skTemplate: incl(sym, sfDirty)
|
||||
if sym.kind == skTemplate: incl(sym.flags, sfDirty)
|
||||
else: invalidPragma(c, it)
|
||||
of wRedefine:
|
||||
if sym.kind == skTemplate: incl(sym, sfTemplateRedefinition)
|
||||
if sym.kind == skTemplate: incl(sym.flags, sfTemplateRedefinition)
|
||||
else: invalidPragma(c, it)
|
||||
of wCallsite:
|
||||
if sym.kind == skTemplate: incl(sym, sfCallsite)
|
||||
if sym.kind == skTemplate: incl(sym.flags, sfCallsite)
|
||||
else: invalidPragma(c, it)
|
||||
of wImportCpp:
|
||||
processImportCpp(c, sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
of wCppNonPod:
|
||||
incl(sym, sfCppNonPod)
|
||||
incl(sym.flags, sfCppNonPod)
|
||||
of wImportJs:
|
||||
if c.config.backend != backendJs:
|
||||
localError(c.config, it.info, "`importjs` pragma requires the JavaScript target")
|
||||
let name = getOptionalStr(c, it, "$1")
|
||||
incl(sym, sfImportc)
|
||||
incl(sym.flagsImpl, sfInfixCall)
|
||||
incl(sym.flags, sfImportc)
|
||||
incl(sym.flags, sfInfixCall)
|
||||
if sym.kind in skProcKinds and {'(', '#', '@'} notin name:
|
||||
localError(c.config, n.info, "`importjs` for routines requires a pattern")
|
||||
setExternName(c, sym, name, it.info)
|
||||
@@ -964,29 +968,29 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
localError(c.config, it.info, "power of two expected")
|
||||
of wNodecl:
|
||||
noVal(c, it)
|
||||
sym.incl(lfNoDecl)
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
of wPure, wAsmNoStackFrame:
|
||||
noVal(c, it)
|
||||
if sym != nil:
|
||||
if k == wPure and sym.kind in routineKinds: invalidPragma(c, it)
|
||||
else: incl(sym, sfPure)
|
||||
else: incl(sym.flags, sfPure)
|
||||
of wVolatile:
|
||||
noVal(c, it)
|
||||
incl(sym, sfVolatile)
|
||||
incl(sym.flags, sfVolatile)
|
||||
of wCursor:
|
||||
noVal(c, it)
|
||||
incl(sym, sfCursor)
|
||||
incl(sym.flags, sfCursor)
|
||||
of wRegister:
|
||||
noVal(c, it)
|
||||
incl(sym, sfRegister)
|
||||
incl(sym.flags, sfRegister)
|
||||
of wNoalias:
|
||||
noVal(c, it)
|
||||
incl(sym, sfNoalias)
|
||||
incl(sym.flags, sfNoalias)
|
||||
of wEffectsOf:
|
||||
processEffectsOf(c, it, sym)
|
||||
of wThreadVar:
|
||||
noVal(c, it)
|
||||
incl(sym, {sfThread, sfGlobal})
|
||||
incl(sym.flags, {sfThread, sfGlobal})
|
||||
of wDeadCodeElimUnused:
|
||||
warningDeprecated(c.config, n.info, "'{.deadcodeelim: on.}' is deprecated, now a noop") # deprecated, dead code elim always on
|
||||
of wNoForward: pragmaNoForward(c, it)
|
||||
@@ -996,50 +1000,51 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
noVal(c, it)
|
||||
if comesFromPush:
|
||||
if sym.kind in {skProc, skFunc}:
|
||||
incl(sym, sfCompileTime)
|
||||
incl(sym.flags, sfCompileTime)
|
||||
else:
|
||||
incl(sym, sfCompileTime)
|
||||
incl(sym.flags, sfCompileTime)
|
||||
#incl(sym.loc.flags, lfNoDecl)
|
||||
of wGlobal:
|
||||
noVal(c, it)
|
||||
incl(sym, {sfGlobal, sfPure})
|
||||
incl(sym.flags, sfGlobal)
|
||||
incl(sym.flags, sfPure)
|
||||
of wConstructor:
|
||||
incl(sym, sfConstructor)
|
||||
incl(sym.flags, sfConstructor)
|
||||
if sfImportc notin sym.flags:
|
||||
sym.constraint = newEmptyStrNode(c, it, getOptionalStr(c, it, ""))
|
||||
sym.constraint.strVal = sym.constraint.strVal
|
||||
sym.flagsImpl.incl {sfExportc, sfMangleCpp}
|
||||
sym.flags.incl {sfExportc, sfMangleCpp}
|
||||
sym.typ.callConv = ccNoConvention
|
||||
of wHeader:
|
||||
var lib = getLib(c, libHeader, getStrLitNode(c, it))
|
||||
addToLib(lib, sym)
|
||||
incl(sym, sfImportc)
|
||||
incl(sym.locImpl.flags, lfHeader)
|
||||
incl(sym.locImpl.flags, lfNoDecl)
|
||||
incl(sym.flags, sfImportc)
|
||||
incl(sym.loc.flags, lfHeader)
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
# implies nodecl, because otherwise header would not make sense
|
||||
if sym.locImpl.snippet == "": sym.locImpl.snippet = rope(sym.name.s)
|
||||
if sym.loc.snippet == "": sym.loc.snippet = rope(sym.name.s)
|
||||
of wNoSideEffect:
|
||||
noVal(c, it)
|
||||
if sym != nil:
|
||||
incl(sym, sfNoSideEffect)
|
||||
if sym.typ != nil: incl(sym.typ, tfNoSideEffect)
|
||||
incl(sym.flags, sfNoSideEffect)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
|
||||
of wSideEffect:
|
||||
noVal(c, it)
|
||||
incl(sym, sfSideEffect)
|
||||
incl(sym.flags, sfSideEffect)
|
||||
of wNoreturn:
|
||||
noVal(c, it)
|
||||
# Disable the 'noreturn' annotation when in the "Quirky Exceptions" mode!
|
||||
if c.config.exc != excQuirky:
|
||||
incl(sym, sfNoReturn)
|
||||
incl(sym.flags, sfNoReturn)
|
||||
if sym.typ.returnType != nil:
|
||||
localError(c.config, sym.ast[paramsPos][0].info,
|
||||
".noreturn with return type not allowed")
|
||||
of wNoDestroy:
|
||||
noVal(c, it)
|
||||
incl(sym, sfGeneratedOp)
|
||||
incl(sym.flags, sfGeneratedOp)
|
||||
of wNosinks:
|
||||
noVal(c, it)
|
||||
incl(sym, sfWasForwarded)
|
||||
incl(sym.flags, sfWasForwarded)
|
||||
of wDynlib:
|
||||
processDynLib(c, it, sym)
|
||||
of wCompilerProc, wCore:
|
||||
@@ -1048,79 +1053,79 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
recordPragma(c, it, "cppdefine", sym.name.s)
|
||||
if sfFromGeneric notin sym.flags: markCompilerProc(c, sym)
|
||||
of wNonReloadable:
|
||||
sym.incl sfNonReloadable
|
||||
sym.flags.incl sfNonReloadable
|
||||
of wProcVar:
|
||||
# old procvar annotation, no longer needed
|
||||
noVal(c, it)
|
||||
of wExplain:
|
||||
sym.incl sfExplain
|
||||
sym.flags.incl sfExplain
|
||||
of wDeprecated:
|
||||
if sym != nil and sym.kind in routineKinds + {skType, skVar, skLet, skConst}:
|
||||
if it.kind in nkPragmaCallKinds: discard getStrLitNode(c, it)
|
||||
incl(sym, sfDeprecated)
|
||||
incl(sym.flags, sfDeprecated)
|
||||
elif sym != nil and sym.kind != skModule:
|
||||
# We don't support the extra annotation field
|
||||
if it.kind in nkPragmaCallKinds:
|
||||
localError(c.config, it.info, "annotation to deprecated not supported here")
|
||||
incl(sym, sfDeprecated)
|
||||
incl(sym.flags, sfDeprecated)
|
||||
# At this point we're quite sure this is a statement and applies to the
|
||||
# whole module
|
||||
elif it.kind in nkPragmaCallKinds: deprecatedStmt(c, it)
|
||||
else: incl(c.module, sfDeprecated)
|
||||
else: incl(c.module.flags, sfDeprecated)
|
||||
of wVarargs:
|
||||
noVal(c, it)
|
||||
if sym.typ == nil: invalidPragma(c, it)
|
||||
else: incl(sym.typ, tfVarargs)
|
||||
else: incl(sym.typ.flags, tfVarargs)
|
||||
of wBorrow:
|
||||
if sym.kind == skType:
|
||||
typeBorrow(c, sym, it)
|
||||
else:
|
||||
noVal(c, it)
|
||||
incl(sym, sfBorrow)
|
||||
incl(sym.flags, sfBorrow)
|
||||
of wFinal:
|
||||
noVal(c, it)
|
||||
if sym.typ == nil: invalidPragma(c, it)
|
||||
else: incl(sym.typ, tfFinal)
|
||||
else: incl(sym.typ.flags, tfFinal)
|
||||
of wInheritable:
|
||||
noVal(c, it)
|
||||
if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(c, it)
|
||||
else: incl(sym.typ, tfInheritable)
|
||||
else: incl(sym.typ.flags, tfInheritable)
|
||||
of wPackage:
|
||||
noVal(c, it)
|
||||
if sym.typ == nil: invalidPragma(c, it)
|
||||
else: incl(sym, sfForward)
|
||||
else: incl(sym.flags, sfForward)
|
||||
of wAcyclic:
|
||||
noVal(c, it)
|
||||
if sym.typ == nil: invalidPragma(c, it)
|
||||
else: incl(sym.typ, tfAcyclic)
|
||||
else: incl(sym.typ.flags, tfAcyclic)
|
||||
of wShallow:
|
||||
noVal(c, it)
|
||||
if sym.typ == nil: invalidPragma(c, it)
|
||||
else: incl(sym.typ, tfShallow)
|
||||
else: incl(sym.typ.flags, tfShallow)
|
||||
of wThread:
|
||||
noVal(c, it)
|
||||
incl(sym, sfThread)
|
||||
incl(sym.flags, sfThread)
|
||||
if sym.typ != nil:
|
||||
incl(sym.typ, tfThread)
|
||||
incl(sym.typ.flags, tfThread)
|
||||
if sym.typ.callConv == ccClosure: sym.typ.callConv = ccNimCall
|
||||
of wSendable:
|
||||
noVal(c, it)
|
||||
if sym != nil and sym.typ != nil:
|
||||
incl(sym.typ, tfSendable)
|
||||
incl(sym.typ.flags, tfSendable)
|
||||
else:
|
||||
invalidPragma(c, it)
|
||||
of wGcSafe:
|
||||
noVal(c, it)
|
||||
if sym != nil:
|
||||
if sym.kind != skType: incl(sym, sfThread)
|
||||
if sym.typ != nil: incl(sym.typ, tfGcSafe)
|
||||
if sym.kind != skType: incl(sym.flags, sfThread)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
|
||||
else: invalidPragma(c, it)
|
||||
else:
|
||||
discard "no checking if used as a code block"
|
||||
of wPacked:
|
||||
noVal(c, it)
|
||||
if sym.typ == nil: invalidPragma(c, it)
|
||||
else: incl(sym.typ, tfPacked)
|
||||
else: incl(sym.typ.flags, tfPacked)
|
||||
of wHint:
|
||||
let s = expectStrLit(c, it)
|
||||
recordPragma(c, it, "hint", s)
|
||||
@@ -1136,8 +1141,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
# distinguish properly between
|
||||
# ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
|
||||
if it.kind in nkPragmaCallKinds: discard getStrLitNode(c, it)
|
||||
incl(sym, sfError)
|
||||
excl(sym, sfForward)
|
||||
incl(sym.flags, sfError)
|
||||
excl(sym.flags, sfForward)
|
||||
else:
|
||||
let s = expectStrLit(c, it)
|
||||
recordPragma(c, it, "error", s)
|
||||
@@ -1147,18 +1152,18 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
of wUndef: processUndef(c, it)
|
||||
of wCompile:
|
||||
let m = sym.getModule()
|
||||
incl(m.flagsImpl, sfUsed)
|
||||
incl(m.flags, sfUsed)
|
||||
processCompile(c, it)
|
||||
of wLink: processLink(c, it)
|
||||
of wPassl:
|
||||
let m = sym.getModule()
|
||||
incl(m.flagsImpl, sfUsed)
|
||||
incl(m.flags, sfUsed)
|
||||
let s = expectStrLit(c, it)
|
||||
extccomp.addLinkOption(c.config, s)
|
||||
recordPragma(c, it, "passl", s)
|
||||
of wPassc:
|
||||
let m = sym.getModule()
|
||||
incl(m.flagsImpl, sfUsed)
|
||||
incl(m.flags, sfUsed)
|
||||
let s = expectStrLit(c, it)
|
||||
extccomp.addCompileOption(c.config, s)
|
||||
recordPragma(c, it, "passc", s)
|
||||
@@ -1176,16 +1181,16 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
result = true
|
||||
of wPragma:
|
||||
if not sym.isNil and sym.kind == skTemplate:
|
||||
sym.incl sfCustomPragma
|
||||
sym.flags.incl sfCustomPragma
|
||||
else:
|
||||
processPragma(c, n, i)
|
||||
result = true
|
||||
of wDiscardable:
|
||||
noVal(c, it)
|
||||
if sym != nil: incl(sym, sfDiscardable)
|
||||
if sym != nil: incl(sym.flags, sfDiscardable)
|
||||
of wNoInit:
|
||||
noVal(c, it)
|
||||
if sym != nil: incl(sym, sfNoInit)
|
||||
if sym != nil: incl(sym.flags, sfNoInit)
|
||||
of wCodegenDecl: processCodegenDecl(c, it, sym)
|
||||
of wChecks, wObjChecks, wFieldChecks, wRangeChecks, wBoundChecks,
|
||||
wOverflowChecks, wNilChecks, wAssertions, wWarnings, wHints,
|
||||
@@ -1195,8 +1200,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
processOption(c, it, c.config.options)
|
||||
of wStackTrace, wLineTrace:
|
||||
if sym.kind in {skProc, skMethod, skConverter}:
|
||||
ensureMutable sym
|
||||
processOption(c, it, sym.optionsImpl)
|
||||
processOption(c, it, sym.options)
|
||||
else:
|
||||
processOption(c, it, c.config.options)
|
||||
of FirstCallConv..LastCallConv:
|
||||
@@ -1204,7 +1208,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
if sym.typ == nil: invalidPragma(c, it)
|
||||
else:
|
||||
sym.typ.callConv = wordToCallConv(k)
|
||||
sym.typ.incl tfExplicitCallConv
|
||||
sym.typ.flags.incl tfExplicitCallConv
|
||||
of wEmit: pragmaEmit(c, it)
|
||||
of wUnroll: pragmaUnroll(c, it)
|
||||
of wLinearScanEnd, wComputedGoto: noVal(c, it)
|
||||
@@ -1214,11 +1218,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
of wIncompleteStruct:
|
||||
noVal(c, it)
|
||||
if sym.typ == nil: invalidPragma(c, it)
|
||||
else: incl(sym.typ, tfIncompleteStruct)
|
||||
else: incl(sym.typ.flags, tfIncompleteStruct)
|
||||
of wCompleteStruct:
|
||||
noVal(c, it)
|
||||
if sym.typ == nil: invalidPragma(c, it)
|
||||
else: incl(sym.typ, tfCompleteStruct)
|
||||
else: incl(sym.typ.flags, tfCompleteStruct)
|
||||
of wUnchecked:
|
||||
noVal(c, it)
|
||||
if sym.typ == nil or sym.typ.kind notin {tyArray, tyUncheckedArray}:
|
||||
@@ -1231,35 +1235,34 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
else:
|
||||
noVal(c, it)
|
||||
if sym.typ == nil: invalidPragma(c, it)
|
||||
else: incl(sym.typ, tfUnion)
|
||||
else: incl(sym.typ.flags, tfUnion)
|
||||
of wRequiresInit:
|
||||
noVal(c, it)
|
||||
if sym.kind == skField:
|
||||
sym.incl sfRequiresInit
|
||||
sym.flags.incl sfRequiresInit
|
||||
elif sym.typ != nil:
|
||||
incl(sym.typ, tfNeedsFullInit)
|
||||
incl(sym.typ.flags, tfNeedsFullInit)
|
||||
else:
|
||||
invalidPragma(c, it)
|
||||
of wByRef:
|
||||
noVal(c, it)
|
||||
if sym != nil and sym.kind == skParam:
|
||||
ensureMutable sym
|
||||
sym.optionsImpl.incl optByRef
|
||||
sym.options.incl optByRef
|
||||
elif sym == nil or sym.typ == nil:
|
||||
processOption(c, it, c.config.options)
|
||||
else:
|
||||
incl(sym.typ, tfByRef)
|
||||
incl(sym.typ.flags, tfByRef)
|
||||
of wByCopy:
|
||||
noVal(c, it)
|
||||
if sym.kind == skParam:
|
||||
incl(sym, sfByCopy)
|
||||
incl(sym.flags, sfByCopy)
|
||||
elif sym.kind != skType or sym.typ == nil: invalidPragma(c, it)
|
||||
else: incl(sym.typ, tfByCopy)
|
||||
else: incl(sym.typ.flags, tfByCopy)
|
||||
of wPartial:
|
||||
noVal(c, it)
|
||||
if sym.kind != skType or sym.typ == nil: invalidPragma(c, it)
|
||||
else:
|
||||
incl(sym.typ, tfPartial)
|
||||
incl(sym.typ.flags, tfPartial)
|
||||
of wInject, wGensym:
|
||||
# We check for errors, but do nothing with these pragmas otherwise
|
||||
# as they are handled directly in 'evalTemplate'.
|
||||
@@ -1287,7 +1290,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
if sym == nil or sym.kind notin {skVar, skLet}:
|
||||
invalidPragma(c, it)
|
||||
else:
|
||||
sym.incl sfGoto
|
||||
sym.flags.incl sfGoto
|
||||
of wExportNims:
|
||||
if sym == nil: invalidPragma(c, it)
|
||||
else: magicsys.registerNimScriptSymbol(c.graph, sym)
|
||||
@@ -1302,7 +1305,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
noVal(c, it)
|
||||
of wBase:
|
||||
noVal(c, it)
|
||||
sym.incl sfBase
|
||||
sym.flags.incl sfBase
|
||||
of wIntDefine:
|
||||
processDefineConst(c, n, sym, mIntDefine)
|
||||
of wStrDefine:
|
||||
@@ -1312,22 +1315,21 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
of wUsed:
|
||||
noVal(c, it)
|
||||
if sym == nil: invalidPragma(c, it)
|
||||
else: sym.incl sfUsed
|
||||
else: sym.flags.incl sfUsed
|
||||
of wLiftLocals:
|
||||
sym.incl(sfForceLift)
|
||||
sym.flags.incl(sfForceLift)
|
||||
of wRequires, wInvariant, wAssume, wAssert:
|
||||
pragmaProposition(c, it)
|
||||
of wEnsures:
|
||||
pragmaEnsures(c, it)
|
||||
of wEnforceNoRaises:
|
||||
sym.incl sfNeverRaises
|
||||
sym.flags.incl sfNeverRaises
|
||||
of wQuirky:
|
||||
sym.incl sfNeverRaises
|
||||
sym.flags.incl sfNeverRaises
|
||||
if sym.kind in {skProc, skMethod, skConverter, skFunc, skIterator}:
|
||||
ensureMutable sym
|
||||
sym.optionsImpl.incl optQuirky
|
||||
sym.options.incl optQuirky
|
||||
of wSystemRaisesDefect:
|
||||
sym.incl sfSystemRaisesDefect
|
||||
sym.flags.incl sfSystemRaisesDefect
|
||||
of wVirtual:
|
||||
processVirtual(c, it, sym, sfVirtual)
|
||||
of wMember:
|
||||
@@ -1384,9 +1386,9 @@ proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
|
||||
var lib = c.optionStack[^1].dynlib
|
||||
if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and
|
||||
sfImportc in sym.flags and lib != nil:
|
||||
incl(sym, lfDynamicLib)
|
||||
incl(sym.loc.flags, lfDynamicLib)
|
||||
addToLib(lib, sym)
|
||||
if sym.locImpl.snippet == "": sym.locImpl.snippet = rope(sym.name.s)
|
||||
if sym.loc.snippet == "": sym.loc.snippet = rope(sym.name.s)
|
||||
|
||||
proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
|
||||
if n == nil: return false
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
{.used.}
|
||||
|
||||
import
|
||||
lexer, options, idents, ast, msgs, lineinfos, wordrecg, trees
|
||||
lexer, options, idents, ast, msgs, lineinfos, wordrecg
|
||||
|
||||
import std/[strutils]
|
||||
|
||||
@@ -66,359 +66,6 @@ proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string
|
||||
# determines how long the subtree will likely be, the second
|
||||
# phase appends to a buffer that will be the output.
|
||||
|
||||
type
|
||||
TPreferedDesc* = enum
|
||||
preferName, # default
|
||||
preferDesc, # probably should become what preferResolved is
|
||||
preferExported,
|
||||
preferModuleInfo, # fully qualified
|
||||
preferGenericArg,
|
||||
preferTypeName,
|
||||
preferResolved, # fully resolved symbols
|
||||
preferMixed,
|
||||
# most useful, shows: symbol + resolved symbols if it differs, e.g.:
|
||||
# tuple[a: MyInt{int}, b: float]
|
||||
preferInlayHint,
|
||||
preferInferredEffects,
|
||||
|
||||
proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string
|
||||
template `$`*(typ: PType): string = typeToString(typ)
|
||||
|
||||
proc valueToString(a: PNode): string =
|
||||
case a.kind
|
||||
of nkCharLit, nkUIntLit..nkUInt64Lit:
|
||||
result = $cast[uint64](a.intVal)
|
||||
of nkIntLit..nkInt64Lit:
|
||||
result = $a.intVal
|
||||
of nkFloatLit..nkFloat128Lit: result = $a.floatVal
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal
|
||||
of nkStaticExpr: result = "static(" & a[0].renderTree & ")"
|
||||
else: result = "<invalid value>"
|
||||
|
||||
proc rangeToStr(n: PNode): string =
|
||||
assert(n.kind == nkRange)
|
||||
result = valueToString(n[0]) & ".." & valueToString(n[1])
|
||||
|
||||
const preferToResolveSymbols = {preferName, preferTypeName, preferModuleInfo,
|
||||
preferGenericArg, preferResolved, preferMixed, preferInlayHint, preferInferredEffects}
|
||||
|
||||
|
||||
const
|
||||
typeToStr: array[TTypeKind, string] = ["None", "bool", "char", "empty",
|
||||
"Alias", "typeof(nil)", "untyped", "typed", "typeDesc",
|
||||
# xxx typeDesc=>typedesc: typedesc is declared as such, and is 10x more common.
|
||||
"GenericInvocation", "GenericBody", "GenericInst", "GenericParam",
|
||||
"distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
|
||||
"set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
|
||||
"pointer", "OpenArray[$1]", "string", "cstring", "Forward",
|
||||
"int", "int8", "int16", "int32", "int64",
|
||||
"float", "float32", "float64", "float128",
|
||||
"uint", "uint8", "uint16", "uint32", "uint64",
|
||||
"owned", "sink",
|
||||
"lent ", "varargs[$1]", "UncheckedArray[$1]", "Error Type",
|
||||
"BuiltInTypeClass", "UserTypeClass",
|
||||
"UserTypeClassInst", "CompositeTypeClass", "inferred",
|
||||
"and", "or", "not", "any", "static", "TypeFromExpr", "concept", # xxx bugfix
|
||||
"void", "iterable"]
|
||||
|
||||
proc addTypeFlags(name: var string, typ: PType) {.inline.} =
|
||||
if tfNotNil in typ.flags: name.add(" not nil")
|
||||
|
||||
proc isIntLit*(t: PType): bool {.inline.} =
|
||||
result = t.kind == tyInt and t.n != nil and t.n.kind == nkIntLit
|
||||
|
||||
proc isFloatLit*(t: PType): bool {.inline.} =
|
||||
result = t.kind == tyFloat and t.n != nil and t.n.kind == nkFloatLit
|
||||
|
||||
# TODO: It would be a good idea to kill the special state of a resolved
|
||||
# concept by switching to tyAlias within the instantiated procs.
|
||||
# Currently, tyAlias is always skipped with skipModifier, which means that
|
||||
# we can store information about the matched concept in another position.
|
||||
# Then builtInFieldAccess can be modified to properly read the derived
|
||||
# consts and types stored within the concept.
|
||||
template isResolvedUserTypeClass*(t: PType): bool =
|
||||
tfResolved in t.flags
|
||||
|
||||
proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
let preferToplevel = prefer
|
||||
proc getPrefer(prefer: TPreferedDesc): TPreferedDesc =
|
||||
if preferToplevel in {preferResolved, preferMixed}:
|
||||
preferToplevel # sticky option
|
||||
else:
|
||||
prefer
|
||||
|
||||
proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
result = ""
|
||||
let prefer = getPrefer(prefer)
|
||||
let t = typ
|
||||
if t == nil: return
|
||||
if prefer in preferToResolveSymbols and t.sym != nil and
|
||||
sfAnon notin t.sym.flags and t.kind notin {tySequence, tyInferred}:
|
||||
if t.kind == tyInt and isIntLit(t):
|
||||
if prefer == preferInlayHint:
|
||||
result = t.sym.name.s
|
||||
else:
|
||||
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
|
||||
elif t.kind == tyAlias and t.elementType.kind != tyAlias:
|
||||
result = typeToString(t.elementType)
|
||||
elif prefer in {preferResolved, preferMixed}:
|
||||
case t.kind
|
||||
of IntegralTypes + {tyFloat..tyFloat128} + {tyString, tyCstring}:
|
||||
result = typeToStr[t.kind]
|
||||
of tyGenericBody:
|
||||
result = typeToString(t.last)
|
||||
of tyCompositeTypeClass:
|
||||
# avoids showing `A[any]` in `proc fun(a: A)` with `A = object[T]`
|
||||
result = typeToString(t.last.last)
|
||||
else:
|
||||
result = t.sym.name.s
|
||||
if prefer == preferMixed and result != t.sym.name.s:
|
||||
result = t.sym.name.s & "{" & result & "}"
|
||||
elif prefer in {preferName, preferTypeName, preferInlayHint, preferInferredEffects} or t.sym.owner.isNil:
|
||||
# note: should probably be: {preferName, preferTypeName, preferGenericArg}
|
||||
result = t.sym.name.s
|
||||
if t.kind == tyGenericParam and t.genericParamHasConstraints:
|
||||
result.add ": "
|
||||
result.add t.elementType.typeToString
|
||||
else:
|
||||
result = t.sym.owner.name.s & '.' & t.sym.name.s
|
||||
result.addTypeFlags(t)
|
||||
return
|
||||
case t.kind
|
||||
of tyInt:
|
||||
if not isIntLit(t) or prefer == preferExported:
|
||||
result = typeToStr[t.kind]
|
||||
else:
|
||||
case prefer:
|
||||
of preferGenericArg:
|
||||
result = $t.n.intVal
|
||||
of preferInlayHint:
|
||||
result = "int"
|
||||
else:
|
||||
result = "int literal(" & $t.n.intVal & ")"
|
||||
of tyGenericInst:
|
||||
result = typeToString(t.genericHead) & '['
|
||||
for needsComma, a in t.genericInstParams:
|
||||
if needsComma: result.add(", ")
|
||||
result.add(typeToString(a, preferGenericArg))
|
||||
result.add(']')
|
||||
of tyGenericInvocation:
|
||||
result = typeToString(t.genericHead) & '['
|
||||
for needsComma, a in t.genericInvocationParams:
|
||||
if needsComma: result.add(", ")
|
||||
result.add(typeToString(a, preferGenericArg))
|
||||
result.add(']')
|
||||
of tyGenericBody:
|
||||
result = typeToString(t.typeBodyImpl) & '['
|
||||
for i, a in t.genericBodyParams:
|
||||
if i > 0: result.add(", ")
|
||||
result.add(typeToString(a, preferTypeName))
|
||||
result.add(']')
|
||||
of tyTypeDesc:
|
||||
if t.elementType.kind == tyNone: result = "typedesc"
|
||||
else: result = "typedesc[" & typeToString(t.elementType) & "]"
|
||||
of tyStatic:
|
||||
if prefer == preferGenericArg and t.n != nil:
|
||||
result = t.n.renderTree
|
||||
else:
|
||||
result = "static[" & (if t.hasElementType: typeToString(t.skipModifier) else: "") & "]"
|
||||
if t.n != nil: result.add "(" & renderTree(t.n) & ")"
|
||||
of tyUserTypeClass:
|
||||
if t.sym != nil and t.sym.owner != nil:
|
||||
if t.isResolvedUserTypeClass: return typeToString(t.last)
|
||||
return t.sym.owner.name.s
|
||||
else:
|
||||
result = "<invalid tyUserTypeClass>"
|
||||
of tyBuiltInTypeClass:
|
||||
result =
|
||||
case t.base.kind
|
||||
of tyVar: "var"
|
||||
of tyRef: "ref"
|
||||
of tyPtr: "ptr"
|
||||
of tySequence: "seq"
|
||||
of tyArray: "array"
|
||||
of tySet: "set"
|
||||
of tyRange: "range"
|
||||
of tyDistinct: "distinct"
|
||||
of tyProc: "proc"
|
||||
of tyObject: "object"
|
||||
of tyTuple: "tuple"
|
||||
of tyOpenArray: "openArray"
|
||||
else: typeToStr[t.base.kind]
|
||||
of tyInferred:
|
||||
let concrete = t.previouslyInferred
|
||||
if concrete != nil: result = typeToString(concrete)
|
||||
else: result = "inferred[" & typeToString(t.base) & "]"
|
||||
of tyUserTypeClassInst:
|
||||
let body = t.base
|
||||
result = body.sym.name.s & "["
|
||||
for needsComma, a in t.userTypeClassInstParams:
|
||||
if needsComma: result.add(", ")
|
||||
result.add(typeToString(a))
|
||||
result.add "]"
|
||||
of tyAnd:
|
||||
for i, son in t.ikids:
|
||||
if i > 0: result.add(" and ")
|
||||
result.add(typeToString(son))
|
||||
of tyOr:
|
||||
for i, son in t.ikids:
|
||||
if i > 0: result.add(" or ")
|
||||
result.add(typeToString(son))
|
||||
of tyNot:
|
||||
result = "not " & typeToString(t.elementType)
|
||||
of tyUntyped:
|
||||
#internalAssert t.len == 0
|
||||
result = "untyped"
|
||||
of tyFromExpr:
|
||||
if t.n == nil:
|
||||
result = "unknown"
|
||||
else:
|
||||
result = "typeof(" & renderTree(t.n) & ")"
|
||||
of tyArray:
|
||||
result = "array"
|
||||
if t.hasElementType:
|
||||
if t.indexType.kind == tyRange:
|
||||
result &= "[" & rangeToStr(t.indexType.n) & ", " &
|
||||
typeToString(t.elementType) & ']'
|
||||
else:
|
||||
result &= "[" & typeToString(t.indexType) & ", " &
|
||||
typeToString(t.elementType) & ']'
|
||||
of tyUncheckedArray:
|
||||
result = "UncheckedArray"
|
||||
if t.hasElementType:
|
||||
result &= "[" & typeToString(t.elementType) & ']'
|
||||
of tySequence:
|
||||
if t.sym != nil and prefer != preferResolved:
|
||||
result = t.sym.name.s
|
||||
else:
|
||||
result = "seq"
|
||||
if t.hasElementType:
|
||||
result &= "[" & typeToString(t.elementType) & ']'
|
||||
of tyOrdinal:
|
||||
result = "ordinal"
|
||||
if t.hasElementType:
|
||||
result &= "[" & typeToString(t.skipModifier) & ']'
|
||||
of tySet:
|
||||
result = "set"
|
||||
if t.hasElementType:
|
||||
result &= "[" & typeToString(t.elementType) & ']'
|
||||
of tyOpenArray:
|
||||
result = "openArray"
|
||||
if t.hasElementType:
|
||||
result &= "[" & typeToString(t.elementType) & ']'
|
||||
of tyDistinct:
|
||||
result = "distinct " & typeToString(t.elementType,
|
||||
if prefer == preferModuleInfo: preferModuleInfo else: preferTypeName)
|
||||
of tyIterable:
|
||||
# xxx factor this pattern
|
||||
result = "iterable"
|
||||
if t.hasElementType:
|
||||
result &= "[" & typeToString(t.skipModifier) & ']'
|
||||
of tyTuple:
|
||||
# we iterate over t.sons here, because t.n may be nil
|
||||
if t.n != nil:
|
||||
result = "tuple["
|
||||
for i in 0..<t.n.len:
|
||||
assert(t.n[i].kind == nkSym)
|
||||
result.add(t.n[i].sym.name.s & ": " & typeToString(t.n[i].sym.typ))
|
||||
if i < t.n.len - 1: result.add(", ")
|
||||
result.add(']')
|
||||
elif t.isEmptyTupleType:
|
||||
result = "tuple[]"
|
||||
elif t.isSingletonTupleType:
|
||||
result = "("
|
||||
for son in t.kids:
|
||||
result.add(typeToString(son))
|
||||
result.add(",)")
|
||||
else:
|
||||
result = "("
|
||||
for i, son in t.ikids:
|
||||
if i > 0: result.add ", "
|
||||
result.add(typeToString(son))
|
||||
result.add(')')
|
||||
of tyPtr, tyRef, tyVar, tyLent:
|
||||
result = if isOutParam(t): "out " else: typeToStr[t.kind]
|
||||
result.add typeToString(t.elementType)
|
||||
of tyRange:
|
||||
result = "range "
|
||||
if t.n != nil and t.n.kind == nkRange:
|
||||
result.add rangeToStr(t.n)
|
||||
if prefer != preferExported:
|
||||
result.add("(" & typeToString(t.elementType) & ")")
|
||||
of tyProc:
|
||||
result = if tfIterator in t.flags: "iterator "
|
||||
elif t.owner != nil:
|
||||
case t.owner.kind
|
||||
of skTemplate: "template "
|
||||
of skMacro: "macro "
|
||||
of skConverter: "converter "
|
||||
else: "proc "
|
||||
else:
|
||||
"proc "
|
||||
if tfUnresolved in t.flags: result.add "[*missing parameters*]"
|
||||
result.add "("
|
||||
for i, a in t.paramTypes:
|
||||
if i > FirstParamAt: result.add(", ")
|
||||
let j = paramTypeToNodeIndex(i)
|
||||
if t.n != nil and j < t.n.len and t.n[j].kind == nkSym:
|
||||
result.add(t.n[j].sym.name.s)
|
||||
result.add(": ")
|
||||
result.add(typeToString(a))
|
||||
result.add(')')
|
||||
if t.returnType != nil: result.add(": " & typeToString(t.returnType))
|
||||
var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: $t.callConv
|
||||
var hasImplicitRaises = false
|
||||
if not isNil(t.owner) and not isNil(t.owner.ast) and (t.owner.ast.len - 1) >= pragmasPos:
|
||||
let pragmasNode = t.owner.ast[pragmasPos]
|
||||
let raisesSpec = effectSpec(pragmasNode, wRaises)
|
||||
if not isNil(raisesSpec):
|
||||
addSep(prag)
|
||||
prag.add("raises: ")
|
||||
prag.add(renderTree raisesSpec)
|
||||
hasImplicitRaises = true
|
||||
if tfNoSideEffect in t.flags:
|
||||
addSep(prag)
|
||||
prag.add("noSideEffect")
|
||||
if tfThread in t.flags:
|
||||
addSep(prag)
|
||||
prag.add("gcsafe")
|
||||
var effectsOfStr = ""
|
||||
for i, a in t.paramTypes:
|
||||
let j = paramTypeToNodeIndex(i)
|
||||
if t.n != nil and j < t.n.len and t.n[j].kind == nkSym and t.n[j].sym.kind == skParam and sfEffectsDelayed in t.n[j].sym.flags:
|
||||
addSep(effectsOfStr)
|
||||
effectsOfStr.add(t.n[j].sym.name.s)
|
||||
if effectsOfStr != "":
|
||||
addSep(prag)
|
||||
prag.add("effectsOf: ")
|
||||
prag.add(effectsOfStr)
|
||||
if not hasImplicitRaises and prefer == preferInferredEffects and not isNil(t.owner) and not isNil(t.owner.typ) and not isNil(t.owner.typ.n) and (t.owner.typ.n.len > 0):
|
||||
let effects = t.n[0]
|
||||
if effects.kind == nkEffectList and effects.len == effectListLen:
|
||||
var inferredRaisesStr = ""
|
||||
let effs = effects[exceptionEffects]
|
||||
if not isNil(effs):
|
||||
for eff in items(effs):
|
||||
if not isNil(eff):
|
||||
addSep(inferredRaisesStr)
|
||||
inferredRaisesStr.add($eff.typ)
|
||||
addSep(prag)
|
||||
prag.add("raises: <inferred> [")
|
||||
prag.add(inferredRaisesStr)
|
||||
prag.add("]")
|
||||
if prag.len != 0: result.add("{." & prag & ".}")
|
||||
of tyVarargs:
|
||||
result = typeToStr[t.kind] % typeToString(t.elementType)
|
||||
of tySink:
|
||||
result = "sink " & typeToString(t.skipModifier)
|
||||
of tyOwned:
|
||||
result = "owned " & typeToString(t.elementType)
|
||||
else:
|
||||
result = typeToStr[t.kind]
|
||||
result.addTypeFlags(t)
|
||||
result = typeToString(typ, prefer)
|
||||
|
||||
|
||||
proc disamb(g: var TSrcGen; s: PSym): int =
|
||||
# we group by 's.name.s' to compute the stable name ID.
|
||||
result = 0
|
||||
@@ -582,7 +229,6 @@ proc put(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) =
|
||||
inc(g.lineLen, s.len)
|
||||
|
||||
proc putComment(g: var TSrcGen, s: string) =
|
||||
const SpecialWhitespace = {' ', '\t', '\r', '\n', '\0'}
|
||||
if s.len == 0: return
|
||||
var i = 0
|
||||
let hi = s.len - 1
|
||||
@@ -612,12 +258,12 @@ proc putComment(g: var TSrcGen, s: string) =
|
||||
# gets too long:
|
||||
# compute length of the following word:
|
||||
var j = i
|
||||
while j <= hi and s[j] notin SpecialWhitespace: inc(j)
|
||||
while j <= hi and s[j] > ' ': inc(j)
|
||||
if not isCode and (g.col + (j - i) > MaxLineLen):
|
||||
put(g, tkComment, com)
|
||||
optNL(g, ind)
|
||||
com = "## "
|
||||
while i <= hi and s[i] notin SpecialWhitespace:
|
||||
while i <= hi and s[i] > ' ':
|
||||
com.add(s[i])
|
||||
inc(i)
|
||||
put(g, tkComment, com)
|
||||
@@ -1216,28 +862,10 @@ proc genSymSuffix(result: var string, s: PSym) {.inline.} =
|
||||
result.add '_'
|
||||
result.addInt s.id
|
||||
|
||||
proc gsemmedParams(g: var TSrcGen, n: PNode) =
|
||||
put(g, tkParLe, "(")
|
||||
for i in 1..<n.len:
|
||||
if i > 1:
|
||||
putWithSpace(g, tkComma, ";")
|
||||
let x {.cursor.} = n[i]
|
||||
if x.kind == nkSym:
|
||||
put g, tkSymbol, renderDefinitionName(x.sym)
|
||||
putWithSpace(g, tkColon, ":")
|
||||
put g, tkSymbol, typeToString(x.sym.typ)
|
||||
else:
|
||||
gsub(g, x)
|
||||
put(g, tkParRi, ")")
|
||||
if not isEmptyType(n[0].typ):
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gsub(g, n[0])
|
||||
|
||||
proc gproc(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext = initContext()
|
||||
var s: PSym = nil
|
||||
if n[namePos].kind == nkSym:
|
||||
s = n[namePos].sym
|
||||
let s = n[namePos].sym
|
||||
var ret = renderDefinitionName(s)
|
||||
ret.genSymSuffix(s)
|
||||
put(g, tkSymbol, ret)
|
||||
@@ -1252,10 +880,7 @@ proc gproc(g: var TSrcGen, n: PNode) =
|
||||
gsub(g, n[miscPos][1])
|
||||
else:
|
||||
gsub(g, n[genericParamsPos])
|
||||
if n[paramsPos].len == 0 and s != nil and s.typ != nil and s.typ.n != nil:
|
||||
gsemmedParams(g, s.typ.n)
|
||||
else:
|
||||
gsub(g, n[paramsPos])
|
||||
gsub(g, n[paramsPos])
|
||||
if renderNoPragmas notin g.flags:
|
||||
gsub(g, n[pragmasPos])
|
||||
if renderNoBody notin g.flags:
|
||||
@@ -2211,9 +1836,6 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
|
||||
putWithSpace(g, tkSymbol, "error")
|
||||
#gcomma(g, n, c)
|
||||
gsub(g, n[0], c)
|
||||
of nkReplayAction:
|
||||
put(g, tkSymbol, "replayaction")
|
||||
#gsons(g, n, c, 0)
|
||||
else:
|
||||
#nkNone, nkExplicitTypeListCall:
|
||||
internalError(g.config, n.info, "renderer.gsub(" & $n.kind & ')')
|
||||
|
||||
@@ -213,10 +213,9 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
|
||||
unregisterArcOrc(conf)
|
||||
conf.globalOptions.excl optOwnedRefs
|
||||
conf.selectedGC = gcUnselected
|
||||
conf.globalOptions.incl optWithinConfigSystem
|
||||
|
||||
var m = graph.makeModule(scriptName)
|
||||
incl(m, sfMainModule)
|
||||
incl(m.flags, sfMainModule)
|
||||
var vm = setupVM(m, cache, scriptName.string, graph, idgen)
|
||||
graph.vm = vm
|
||||
|
||||
@@ -231,7 +230,7 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
|
||||
if optOwnedRefs in oldGlobalOptions:
|
||||
conf.globalOptions.incl {optTinyRtti, optOwnedRefs, optSeqDestructors}
|
||||
defineSymbol(conf.symbols, "nimv2")
|
||||
if conf.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc}:
|
||||
if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
conf.globalOptions.incl {optTinyRtti, optSeqDestructors}
|
||||
defineSymbol(conf.symbols, "nimv2")
|
||||
defineSymbol(conf.symbols, "gcdestructors")
|
||||
@@ -241,8 +240,6 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
|
||||
defineSymbol(conf.symbols, "gcarc")
|
||||
of gcOrc:
|
||||
defineSymbol(conf.symbols, "gcorc")
|
||||
of gcYrc:
|
||||
defineSymbol(conf.symbols, "gcyrc")
|
||||
of gcAtomicArc:
|
||||
defineSymbol(conf.symbols, "gcatomicarc")
|
||||
else:
|
||||
@@ -254,5 +251,4 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
|
||||
#initDefines()
|
||||
undefSymbol(conf.symbols, "nimscript")
|
||||
undefSymbol(conf.symbols, "nimconfig")
|
||||
conf.globalOptions.excl optWithinConfigSystem
|
||||
conf.symbolFiles = oldSymbolFiles
|
||||
|
||||
@@ -102,7 +102,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
|
||||
renderTree(arg, {renderNoComments}))
|
||||
# error correction:
|
||||
result = copyTree(arg)
|
||||
result.typ = formal
|
||||
result.typ() = formal
|
||||
elif arg.kind in nkSymChoices and formal.skipTypes(abstractInst).kind == tyEnum:
|
||||
# Pick the right 'sym' from the sym choice by looking at 'formal' type:
|
||||
result = nil
|
||||
@@ -116,7 +116,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
|
||||
typeMismatch(c.config, info, formal, arg.typ, arg)
|
||||
# error correction:
|
||||
result = copyTree(arg)
|
||||
result.typ = formal
|
||||
result.typ() = formal
|
||||
else:
|
||||
result = fitNodePostMatch(c, formal, result)
|
||||
|
||||
@@ -126,7 +126,7 @@ proc fitNodeConsiderViewType(c: PContext, formal: PType, arg: PNode; info: TLine
|
||||
#classifyViewType(formal) != noView:
|
||||
result = newNodeIT(nkHiddenAddr, a.info, formal)
|
||||
result.add a
|
||||
formal.incl tfVarIsPtr
|
||||
formal.flags.incl tfVarIsPtr
|
||||
else:
|
||||
result = a
|
||||
|
||||
@@ -260,7 +260,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||
else:
|
||||
result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info)
|
||||
if find(result.name.s, '`') >= 0:
|
||||
result.flagsImpl.incl sfWasGenSym
|
||||
result.flags.incl sfWasGenSym
|
||||
#if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
|
||||
# incl(result.flags, sfGlobal)
|
||||
when defined(nimsuggest):
|
||||
@@ -491,7 +491,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||
renderTree(result, {renderNoComments}))
|
||||
result = newSymNode(errorSym(c, result))
|
||||
else:
|
||||
result.typ = makeTypeDesc(c, typ)
|
||||
result.typ() = makeTypeDesc(c, typ)
|
||||
#result = symNodeFromType(c, typ, n.info)
|
||||
else:
|
||||
if s.ast[genericParamsPos] != nil and retType.isMetaType:
|
||||
@@ -650,7 +650,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool, ch
|
||||
newNodeIT(nkType, recNode.info, asgnType)
|
||||
)
|
||||
asgnExpr.flags.incl nfSkipFieldChecking
|
||||
asgnExpr.typ = recNode.typ
|
||||
asgnExpr.typ() = recNode.typ
|
||||
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
|
||||
else:
|
||||
raiseAssert "unreachable"
|
||||
@@ -672,7 +672,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault:
|
||||
if checkDefault: # don't add defaults when checking whether a case branch has default fields
|
||||
return
|
||||
defaultValue = newIntNode(nkIntLit#[c.graph]#, 0)
|
||||
defaultValue.typ = discriminator.typ
|
||||
defaultValue.typ() = discriminator.typ
|
||||
selectedBranch = recNode.pickCaseBranchIndex defaultValue
|
||||
defaultValue.flags.incl nfSkipFieldChecking
|
||||
result.add newTree(nkExprColonExpr, discriminator, defaultValue)
|
||||
@@ -685,7 +685,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault:
|
||||
elif recType.kind in {tyObject, tyArray, tyTuple}:
|
||||
let asgnExpr = defaultNodeField(c, recNode, recNode.typ, checkDefault)
|
||||
if asgnExpr != nil:
|
||||
asgnExpr.typ = recNode.typ
|
||||
asgnExpr.typ() = recNode.typ
|
||||
asgnExpr.flags.incl nfSkipFieldChecking
|
||||
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
|
||||
else:
|
||||
@@ -698,7 +698,7 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
|
||||
let child = defaultFieldsForTheUninitialized(c, aTypSkip.n, checkDefault)
|
||||
if child.len > 0:
|
||||
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTyp))
|
||||
asgnExpr.typ = aTyp
|
||||
asgnExpr.typ() = aTyp
|
||||
asgnExpr.sons.add child
|
||||
result = semExpr(c, asgnExpr)
|
||||
else:
|
||||
@@ -710,11 +710,11 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
|
||||
let node = newNode(nkIntLit)
|
||||
node.intVal = toInt64(lengthOrd(c.graph.config, aTypSkip))
|
||||
let typeNode = newNode(nkType)
|
||||
typeNode.typ = makeTypeDesc(c, aTypSkip[1])
|
||||
typeNode.typ() = makeTypeDesc(c, aTypSkip[1])
|
||||
result = semExpr(c, newTree(nkCall, newTree(nkBracketExpr, newSymNode(getSysSym(c.graph, a.info, "arrayWithDefault"), a.info), typeNode),
|
||||
node
|
||||
))
|
||||
result.typ = aTyp
|
||||
result.typ() = aTyp
|
||||
else:
|
||||
result = nil
|
||||
of tyTuple:
|
||||
@@ -723,7 +723,7 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
|
||||
let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault, checkDefault)
|
||||
if hasDefault and children.len > 0:
|
||||
result = newNodeI(nkTupleConstr, a.info)
|
||||
result.typ = aTyp
|
||||
result.typ() = aTyp
|
||||
result.sons.add children
|
||||
result = semExpr(c, result)
|
||||
else:
|
||||
@@ -855,7 +855,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||
appendToModule(c.module, result)
|
||||
trackStmt(c, c.module, result, isTopLevel = true)
|
||||
if optMultiMethods notin c.config.globalOptions and
|
||||
c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc, gcYrc} and
|
||||
c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
|
||||
Feature.vtables in c.config.features:
|
||||
sortVTableDispatchers(c.graph)
|
||||
|
||||
@@ -889,6 +889,8 @@ proc semWithPContext*(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
#if c.config.cmd == cmdIdeTools: findSuggest(c, n)
|
||||
storeRodNode(c, result)
|
||||
|
||||
|
||||
proc reportUnusedModules(c: PContext) =
|
||||
if c.config.cmd == cmdM: return
|
||||
|
||||
@@ -131,7 +131,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
var sym = syms[0].s
|
||||
let name = sym.name
|
||||
var scope = syms[0].scope
|
||||
c.openShadowScope
|
||||
|
||||
if allowTypeBoundOps:
|
||||
for a in 1 ..< n.len:
|
||||
# for every already typed argument, add type bound ops
|
||||
@@ -160,13 +160,9 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
addTypeBoundSymbols(c.graph, arg.typ, name, filter, symMarker, syms)
|
||||
|
||||
if z.state == csMatch:
|
||||
# Iterator preference is heuristic in iterator-admitting contexts.
|
||||
# The dedicated iterable path uses `iteratorPreference`, other
|
||||
# context use exact-match bump
|
||||
# little hack so that iterators are preferred over everything else:
|
||||
if sym.kind == skIterator:
|
||||
if efPreferIteratorForIterable in flags:
|
||||
inc(z.iteratorPreference)
|
||||
elif not (efWantIterator notin flags and efWantIterable in flags):
|
||||
if not (efWantIterator notin flags and efWantIterable in flags):
|
||||
inc(z.exactMatches, 200)
|
||||
else:
|
||||
dec(z.exactMatches, 200)
|
||||
@@ -218,10 +214,6 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
scope = syms[nextSymIndex].scope
|
||||
inc(nextSymIndex)
|
||||
|
||||
if best.state == csMatch and best.calleeSym != nil and best.calleeSym.kind in {skTemplate, skMacro}:
|
||||
c.closeShadowScope
|
||||
else:
|
||||
c.mergeShadowScope
|
||||
|
||||
proc effectProblem(f, a: PType; result: var string; c: PContext) =
|
||||
if f.kind == tyProc and a.kind == tyProc:
|
||||
@@ -679,7 +671,7 @@ proc bracketNotFoundError(c: PContext; n: PNode; flags: TExprFlags) =
|
||||
# copied from semOverloadedCallAnalyzeEffects, might be overkill:
|
||||
const baseFilter = {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate}
|
||||
let filter =
|
||||
if flags*{efInTypeof, efWantIterator, efWantIterable, efPreferIteratorForIterable} != {}:
|
||||
if flags*{efInTypeof, efWantIterator, efWantIterable} != {}:
|
||||
baseFilter + {skIterator}
|
||||
else: baseFilter
|
||||
# this will add the errors:
|
||||
@@ -703,7 +695,7 @@ proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
|
||||
internalError(c.config, a.info, "generic converter failed rematch")
|
||||
let finalCallee = generateInstance(c, s, convMatch.bindings, a.info)
|
||||
a[0].sym = finalCallee
|
||||
a[0].typ = finalCallee.typ
|
||||
a[0].typ() = finalCallee.typ
|
||||
#a.typ = finalCallee.typ.returnType
|
||||
|
||||
proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
|
||||
@@ -738,13 +730,13 @@ proc inferWithMetatype(c: PContext, formal: PType,
|
||||
# This almost exactly replicates the steps taken by the compiler during
|
||||
# param matching. It performs an embarrassing amount of back-and-forth
|
||||
# type jugling, but it's the price to pay for consistency and correctness
|
||||
result.typ = generateTypeInstance(c, m.bindings, arg.info,
|
||||
result.typ() = generateTypeInstance(c, m.bindings, arg.info,
|
||||
formal.skipTypes({tyCompositeTypeClass}))
|
||||
else:
|
||||
typeMismatch(c.config, arg.info, formal, arg.typ, arg)
|
||||
# error correction:
|
||||
result = copyTree(arg)
|
||||
result.typ = formal
|
||||
result.typ() = formal
|
||||
|
||||
proc updateDefaultParams(c: PContext, call: PNode) =
|
||||
# In generic procs, the default parameter may be unique for each
|
||||
@@ -767,7 +759,7 @@ proc updateDefaultParams(c: PContext, call: PNode) =
|
||||
pushInfoContext(c.config, call.info, call[0].sym.detailedInfo)
|
||||
typeMismatch(c.config, def.info, formal.typ, def.typ, formal.ast)
|
||||
popInfoContext(c.config)
|
||||
def.typ = errorType(c)
|
||||
def.typ() = errorType(c)
|
||||
call[i] = def
|
||||
|
||||
proc getCallLineInfo(n: PNode): TLineInfo =
|
||||
@@ -869,8 +861,8 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
|
||||
result = x.call
|
||||
result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
|
||||
if containsGenericType(result.typ):
|
||||
result.typ = newTypeS(tyError, c)
|
||||
incl result.typ, tfCheckedForDestructor
|
||||
result.typ() = newTypeS(tyError, c)
|
||||
incl result.typ.flags, tfCheckedForDestructor
|
||||
return
|
||||
let gp = finalCallee.ast[genericParamsPos]
|
||||
if gp.isGenericParams:
|
||||
@@ -896,7 +888,7 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
|
||||
# this node will be used in template substitution,
|
||||
# pretend this is an untyped node and let regular sem handle the type
|
||||
# to prevent problems where a generic parameter is treated as a value
|
||||
tn.typ = nil
|
||||
tn.typ() = nil
|
||||
x.call.add tn
|
||||
else:
|
||||
internalAssert c.config, false
|
||||
@@ -908,7 +900,7 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
|
||||
markConvertersUsed(c, result)
|
||||
result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
|
||||
if finalCallee.magic notin {mArrGet, mArrPut}:
|
||||
result.typ = finalCallee.typ.returnType
|
||||
result.typ() = finalCallee.typ.returnType
|
||||
updateDefaultParams(c, result)
|
||||
|
||||
proc canDeref(n: PNode): bool {.inline.} =
|
||||
@@ -917,7 +909,7 @@ proc canDeref(n: PNode): bool {.inline.} =
|
||||
|
||||
proc tryDeref(n: PNode): PNode =
|
||||
result = newNodeI(nkHiddenDeref, n.info)
|
||||
result.typ = n.typ.skipTypes(abstractInst)[0]
|
||||
result.typ() = n.typ.skipTypes(abstractInst)[0]
|
||||
result.add n
|
||||
|
||||
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||
@@ -936,7 +928,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||
else:
|
||||
if c.inGenericContext > 0 and c.matchedConcept == nil:
|
||||
result = semGenericStmt(c, n)
|
||||
result.typ = makeTypeFromExpr(c, result.copyTree)
|
||||
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
||||
elif efNoUndeclared in flags:
|
||||
result = nil
|
||||
elif efExplain notin flags:
|
||||
@@ -968,7 +960,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym, errors: var CandidateErr
|
||||
diagnostics: m.diagnostics))
|
||||
return nil
|
||||
var newInst = generateInstance(c, s, m.bindings, n.info)
|
||||
newInst.typ.excl tfUnresolved
|
||||
newInst.typ.flags.excl tfUnresolved
|
||||
let info = getCallLineInfo(n)
|
||||
markUsed(c, info, s, isGenericInstance = false)
|
||||
onUse(info, s, isGenericInstance = false)
|
||||
@@ -987,9 +979,9 @@ proc setGenericParams(c: PContext, n, expectedParams: PNode) =
|
||||
nil
|
||||
e = semExprWithType(c, n[i], expectedType = constraint)
|
||||
if e.typ == nil:
|
||||
n[i].typ = errorType(c)
|
||||
n[i].typ() = errorType(c)
|
||||
else:
|
||||
n[i].typ = e.typ
|
||||
n[i].typ() = e.typ.skipTypes({tyTypeDesc})
|
||||
|
||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym, doError: bool): PNode =
|
||||
assert n.kind == nkBracketExpr
|
||||
@@ -1006,7 +998,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym, doError: bool)
|
||||
# same as in semOverloadedCall, make expression untyped,
|
||||
# may have failed match due to unresolved types
|
||||
result = semGenericStmt(c, n)
|
||||
result.typ = makeTypeFromExpr(c, result.copyTree)
|
||||
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
||||
elif doError:
|
||||
notFoundError(c, n, errors)
|
||||
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
|
||||
@@ -1024,7 +1016,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym, doError: bool)
|
||||
# any failing match stops building the symchoice for correctness,
|
||||
# can also make it untyped from the start
|
||||
result = semGenericStmt(c, n)
|
||||
result.typ = makeTypeFromExpr(c, result.copyTree)
|
||||
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
||||
return
|
||||
# get rid of nkClosedSymChoice if not ambiguous:
|
||||
if result.len == 0:
|
||||
|
||||
@@ -19,6 +19,8 @@ import
|
||||
magicsys, vmdef, modulegraphs, lineinfos, pathutils, layeredtable,
|
||||
types, lowerings, trees, parampatterns, astalgo
|
||||
|
||||
import ic / ic
|
||||
|
||||
type
|
||||
TOptionEntry* = object # entries to put on a stack for pragma parsing
|
||||
options*: TOptions
|
||||
@@ -54,18 +56,7 @@ type
|
||||
inst*: PInstantiation
|
||||
|
||||
TExprFlag* = enum
|
||||
efLValue,
|
||||
# The expression is used as an assignable location.
|
||||
efWantIterator,
|
||||
# Admit iterator candidates and prefer them during overload resolution.
|
||||
efWantIterable,
|
||||
# Admit iterator candidates for expressions that may feed iterable-style
|
||||
# chaining.
|
||||
efPreferIteratorForIterable,
|
||||
# Prefer iterator candidates for `iterable[T]` matching and wrap a
|
||||
# successful iterator call as `tyIterable`.
|
||||
efInTypeof,
|
||||
# The expression is being semchecked under `typeof`.
|
||||
efLValue, efWantIterator, efWantIterable, efInTypeof,
|
||||
efNeedStatic,
|
||||
# Use this in contexts where a static value is mandatory
|
||||
efPreferStatic,
|
||||
@@ -180,12 +171,7 @@ type
|
||||
sideEffects*: Table[int, seq[(TLineInfo, PSym)]] # symbol.id index
|
||||
inUncheckedAssignSection*: int
|
||||
importModuleLookup*: Table[int, seq[int]] # (module.ident.id, [module.id])
|
||||
forwardTypeUpdates*: seq[(PSym, PType, PNode)]
|
||||
# top-level owner, type, and type node for delayed retries inside a
|
||||
# type section due to containing forward types
|
||||
forwardFieldUpdates*: seq[(PType, PNode, PType)]
|
||||
# object/tuple field definitions whose default values mention forward
|
||||
# types and need delayed const checking
|
||||
skipTypes*: seq[PNode] # used to skip types between passes in type section. So far only used for inheritance, sets and generic bodies.
|
||||
inTypeofContext*: int
|
||||
|
||||
semAsgnOpr*: proc (c: PContext; n: PNode; k: TNodeKind): PNode {.nimcall.}
|
||||
@@ -213,29 +199,29 @@ proc getIntLitType*(c: PContext; literal: PNode): PType =
|
||||
proc setIntLitType*(c: PContext; result: PNode) =
|
||||
let i = result.intVal
|
||||
case c.config.target.intSize
|
||||
of 8: result.typ = getIntLitType(c, result)
|
||||
of 8: result.typ() = getIntLitType(c, result)
|
||||
of 4:
|
||||
if i >= low(int32) and i <= high(int32):
|
||||
result.typ = getIntLitType(c, result)
|
||||
result.typ() = getIntLitType(c, result)
|
||||
else:
|
||||
result.typ = getSysType(c.graph, result.info, tyInt64)
|
||||
result.typ() = getSysType(c.graph, result.info, tyInt64)
|
||||
of 2:
|
||||
if i >= low(int16) and i <= high(int16):
|
||||
result.typ = getIntLitType(c, result)
|
||||
result.typ() = getIntLitType(c, result)
|
||||
elif i >= low(int32) and i <= high(int32):
|
||||
result.typ = getSysType(c.graph, result.info, tyInt32)
|
||||
result.typ() = getSysType(c.graph, result.info, tyInt32)
|
||||
else:
|
||||
result.typ = getSysType(c.graph, result.info, tyInt64)
|
||||
result.typ() = getSysType(c.graph, result.info, tyInt64)
|
||||
of 1:
|
||||
# 8 bit CPUs are insane ...
|
||||
if i >= low(int8) and i <= high(int8):
|
||||
result.typ = getIntLitType(c, result)
|
||||
result.typ() = getIntLitType(c, result)
|
||||
elif i >= low(int16) and i <= high(int16):
|
||||
result.typ = getSysType(c.graph, result.info, tyInt16)
|
||||
result.typ() = getSysType(c.graph, result.info, tyInt16)
|
||||
elif i >= low(int32) and i <= high(int32):
|
||||
result.typ = getSysType(c.graph, result.info, tyInt32)
|
||||
result.typ() = getSysType(c.graph, result.info, tyInt32)
|
||||
else:
|
||||
result.typ = getSysType(c.graph, result.info, tyInt64)
|
||||
result.typ() = getSysType(c.graph, result.info, tyInt64)
|
||||
else:
|
||||
internalError(c.config, result.info, "invalid int size")
|
||||
|
||||
@@ -348,17 +334,28 @@ proc newContext*(graph: ModuleGraph; module: PSym): PContext =
|
||||
signatures: initStrTable(),
|
||||
features: graph.config.features
|
||||
)
|
||||
if graph.config.symbolFiles != disabledSf:
|
||||
let id = module.position
|
||||
if graph.config.cmd != cmdM:
|
||||
assert graph.packed[id].status in {undefined, outdated}
|
||||
graph.packed[id].status = storing
|
||||
graph.packed[id].module = module
|
||||
initEncoder graph, module
|
||||
|
||||
template packedRepr*(c): untyped = c.graph.packed[c.module.position].fromDisk
|
||||
template encoder*(c): untyped = c.graph.encoders[c.module.position]
|
||||
|
||||
proc addIncludeFileDep*(c: PContext; f: FileIndex) =
|
||||
discard
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
addIncludeFileDep(c.encoder, c.packedRepr, f)
|
||||
|
||||
proc addImportFileDep*(c: PContext; f: FileIndex) =
|
||||
discard
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
addImportFileDep(c.encoder, c.packedRepr, f)
|
||||
|
||||
proc addPragmaComputation*(c: PContext; n: PNode) =
|
||||
# Also store for NIF-based IC (cmdM mode or optCompress)
|
||||
if optCompress in c.config.globalOptions or c.config.cmd == cmdM:
|
||||
addNifReplayAction(c.graph, c.module.position.int32, n)
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
addPragmaComputation(c.encoder, c.packedRepr, n)
|
||||
|
||||
proc inclSym(sq: var seq[PSym], s: PSym): bool =
|
||||
for i in 0..<sq.len:
|
||||
@@ -366,28 +363,38 @@ proc inclSym(sq: var seq[PSym], s: PSym): bool =
|
||||
sq.add s
|
||||
result = true
|
||||
|
||||
proc addConverter*(c: PContext, conv: PSym) =
|
||||
assert conv != nil
|
||||
if inclSym(c.converters, conv):
|
||||
proc addConverter*(c: PContext, conv: LazySym) =
|
||||
assert conv.sym != nil
|
||||
if inclSym(c.converters, conv.sym):
|
||||
add(c.graph.ifaces[c.module.position].converters, conv)
|
||||
|
||||
proc addConverterDef*(c: PContext, conv: PSym) =
|
||||
proc addConverterDef*(c: PContext, conv: LazySym) =
|
||||
addConverter(c, conv)
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
addConverter(c.encoder, c.packedRepr, conv.sym)
|
||||
|
||||
proc addPureEnum*(c: PContext, e: PSym) =
|
||||
assert e != nil
|
||||
proc addPureEnum*(c: PContext, e: LazySym) =
|
||||
assert e.sym != nil
|
||||
add(c.graph.ifaces[c.module.position].pureEnums, e)
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
addPureEnum(c.encoder, c.packedRepr, e.sym)
|
||||
|
||||
proc addPattern*(c: PContext, p: PSym) =
|
||||
assert p != nil
|
||||
if inclSym(c.patterns, p):
|
||||
proc addPattern*(c: PContext, p: LazySym) =
|
||||
assert p.sym != nil
|
||||
if inclSym(c.patterns, p.sym):
|
||||
add(c.graph.ifaces[c.module.position].patterns, p)
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
addTrmacro(c.encoder, c.packedRepr, p.sym)
|
||||
|
||||
proc exportSym*(c: PContext; s: PSym) =
|
||||
strTableAdds(c.graph, c.module, s)
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
addExported(c.encoder, c.packedRepr, s)
|
||||
|
||||
proc reexportSym*(c: PContext; s: PSym) =
|
||||
strTableAdds(c.graph, c.module, s)
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
addReexport(c.encoder, c.packedRepr, s)
|
||||
|
||||
proc newLib*(kind: TLibKind): PLib =
|
||||
result = PLib(kind: kind) #result.syms = initObjectSet()
|
||||
@@ -424,7 +431,7 @@ proc makeVarType*(c: PContext, baseType: PType; kind = tyVar): PType =
|
||||
|
||||
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
|
||||
let typedesc = newTypeS(tyTypeDesc, c)
|
||||
incl typedesc.flagsImpl, tfCheckedForDestructor
|
||||
incl typedesc.flags, tfCheckedForDestructor
|
||||
internalAssert(c.config, typ != nil)
|
||||
typedesc.addSonSkipIntLit(typ, c.idgen)
|
||||
let sym = newSym(skType, c.cache.idAnon, c.idgen, getCurrOwner(c), info,
|
||||
@@ -448,7 +455,7 @@ when false:
|
||||
proc makeStaticExpr*(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkStaticExpr, n.info)
|
||||
result.sons = @[n]
|
||||
result.typ = if n.typ != nil and n.typ.kind == tyStatic: n.typ
|
||||
result.typ() = if n.typ != nil and n.typ.kind == tyStatic: n.typ
|
||||
else: newTypeS(tyStatic, c, n.typ)
|
||||
|
||||
proc makeAndType*(c: PContext, t1, t2: PType): PType =
|
||||
@@ -457,8 +464,8 @@ proc makeAndType*(c: PContext, t1, t2: PType): PType =
|
||||
result.rawAddSon t2
|
||||
propagateToOwner(result, t1)
|
||||
propagateToOwner(result, t2)
|
||||
result.flagsImpl.incl((t1.flags + t2.flags) * {tfHasStatic})
|
||||
result.flagsImpl.incl tfHasMeta
|
||||
result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
|
||||
result.flags.incl tfHasMeta
|
||||
|
||||
proc makeOrType*(c: PContext, t1, t2: PType): PType =
|
||||
if t1.kind != tyOr and t2.kind != tyOr:
|
||||
@@ -476,14 +483,14 @@ proc makeOrType*(c: PContext, t1, t2: PType): PType =
|
||||
addOr(t2)
|
||||
propagateToOwner(result, t1)
|
||||
propagateToOwner(result, t2)
|
||||
result.incl((t1.flags + t2.flags) * {tfHasStatic})
|
||||
result.incl tfHasMeta
|
||||
result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
|
||||
result.flags.incl tfHasMeta
|
||||
|
||||
proc makeNotType*(c: PContext, t1: PType): PType =
|
||||
result = newTypeS(tyNot, c, son = t1)
|
||||
propagateToOwner(result, t1)
|
||||
result.flagsImpl.incl(t1.flags * {tfHasStatic})
|
||||
result.flagsImpl.incl tfHasMeta
|
||||
result.flags.incl(t1.flags * {tfHasStatic})
|
||||
result.flags.incl tfHasMeta
|
||||
|
||||
proc nMinusOne(c: PContext; n: PNode): PNode =
|
||||
result = newTreeI(nkCall, n.info, newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n)
|
||||
@@ -493,7 +500,7 @@ proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
|
||||
let intType = getSysType(c.graph, n.info, tyInt)
|
||||
result = newTypeS(tyRange, c, son = intType)
|
||||
if n.typ != nil and n.typ.n == nil:
|
||||
result.incl tfUnresolved
|
||||
result.flags.incl tfUnresolved
|
||||
result.n = newTreeI(nkRange, n.info, newIntTypeNode(0, intType),
|
||||
makeStaticExpr(c, nMinusOne(c, n)))
|
||||
|
||||
@@ -503,11 +510,11 @@ template rangeHasUnresolvedStatic*(t: PType): bool =
|
||||
proc errorType*(c: PContext): PType =
|
||||
## creates a type representing an error state
|
||||
result = newTypeS(tyError, c)
|
||||
result.flagsImpl.incl tfCheckedForDestructor
|
||||
result.flags.incl tfCheckedForDestructor
|
||||
|
||||
proc errorNode*(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
result.typ = errorType(c)
|
||||
result.typ() = errorType(c)
|
||||
|
||||
# These mimic localError
|
||||
template localErrorNode*(c: PContext, n: PNode, info: TLineInfo, msg: TMsgKind, arg: string): PNode =
|
||||
@@ -553,21 +560,21 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
|
||||
result = typ
|
||||
else:
|
||||
result = newTypeS(tyTypeDesc, c, skipIntLit(typ, c.idgen))
|
||||
incl result, tfCheckedForDestructor
|
||||
incl result.flags, tfCheckedForDestructor
|
||||
|
||||
proc symFromType*(c: PContext; t: PType, info: TLineInfo): PSym =
|
||||
if t.sym != nil: return t.sym
|
||||
result = newSym(skType, getIdent(c.cache, "AnonType"), c.idgen, t.owner, info)
|
||||
result.flagsImpl.incl sfAnon
|
||||
result.flags.incl sfAnon
|
||||
result.typ = t
|
||||
|
||||
proc symNodeFromType*(c: PContext, t: PType, info: TLineInfo): PNode =
|
||||
result = newSymNode(symFromType(c, t, info), info)
|
||||
result.typ = makeTypeDesc(c, t)
|
||||
result.typ() = makeTypeDesc(c, t)
|
||||
|
||||
proc markIndirect*(c: PContext, s: PSym) {.inline.} =
|
||||
if s.kind in {skProc, skFunc, skConverter, skMethod, skIterator}:
|
||||
incl(s.flagsImpl, sfAddrTaken)
|
||||
incl(s.flags, sfAddrTaken)
|
||||
# XXX add to 'c' for global analysis
|
||||
|
||||
proc illFormedAst*(n: PNode; conf: ConfigRef) =
|
||||
@@ -602,11 +609,19 @@ template addExport*(c: PContext; s: PSym) =
|
||||
## convenience to export a symbol from the current module
|
||||
addExport(c.graph, c.module, s)
|
||||
|
||||
proc storeRodNode*(c: PContext, n: PNode) =
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
toPackedNodeTopLevel(n, c.encoder, c.packedRepr)
|
||||
|
||||
proc addToGenericProcCache*(c: PContext; s: PSym; inst: PInstantiation) =
|
||||
c.graph.procInstCache.mgetOrPut(s.itemId, @[]).add inst
|
||||
c.graph.procInstCache.mgetOrPut(s.itemId, @[]).add LazyInstantiation(module: c.module.position, inst: inst)
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
storeInstantiation(c.encoder, c.packedRepr, s, inst)
|
||||
|
||||
proc addToGenericCache*(c: PContext; s: PSym; inst: PType) =
|
||||
c.graph.typeInstCache.mgetOrPut(s.itemId, @[]).add inst
|
||||
c.graph.typeInstCache.mgetOrPut(s.itemId, @[]).add LazyType(typ: inst)
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
storeTypeInst(c.encoder, c.packedRepr, s, inst)
|
||||
|
||||
proc sealRodFile*(c: PContext) =
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
@@ -622,8 +637,9 @@ proc rememberExpansion*(c: PContext; info: TLineInfo; expandedSym: PSym) =
|
||||
## in the sem'checked AST. This is very bad for IDE-like tooling
|
||||
## ("find all usages of this template" would not work). We need special
|
||||
## logic to remember macro/template expansions. This is done here and
|
||||
## delegated to the "NIF" file mechanism.
|
||||
discard "XXX To implement"
|
||||
## delegated to the "rod" file mechanism.
|
||||
if c.config.symbolFiles != disabledSf:
|
||||
storeExpansion(c.encoder, c.packedRepr, info, expandedSym)
|
||||
|
||||
const
|
||||
errVarForOutParamNeededX = "for a 'var' type a variable needs to be passed; but '$1' is immutable"
|
||||
@@ -637,11 +653,6 @@ proc renderNotLValue*(n: PNode): string =
|
||||
elif n.kind in {nkHiddenStdConv, nkHiddenSubConv} and n.len == 2:
|
||||
result = typeToString(n.typ.skipTypes(abstractVar)) & "(" & result & ")"
|
||||
|
||||
proc isSsoStringIndex*(conf: ConfigRef; n: PNode): bool =
|
||||
result = conf.usesSso() and n.kind == nkBracketExpr and n.len >= 1 and
|
||||
n[0].typ != nil and
|
||||
n[0].typ.skipTypes(abstractVar + abstractInst - {tyTypeDesc}).kind == tyString
|
||||
|
||||
proc isAssignable(c: PContext, n: PNode): TAssignableResult =
|
||||
result = parampatterns.isAssignable(c.p.owner, n)
|
||||
|
||||
@@ -671,7 +682,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
|
||||
# n.sym.typ can be nil in 'check' mode ...
|
||||
if n.sym.typ != nil and
|
||||
skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
|
||||
incl(n.sym.flagsImpl, sfAddrTaken)
|
||||
incl(n.sym.flags, sfAddrTaken)
|
||||
result = newHiddenAddrTaken(c, n, isOutParam)
|
||||
of nkDotExpr:
|
||||
checkSonsLen(n, 2, c.config)
|
||||
@@ -679,12 +690,12 @@ proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
|
||||
internalError(c.config, n.info, "analyseIfAddressTaken")
|
||||
return
|
||||
if skipTypes(n[1].sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
|
||||
incl(n[1].sym.flagsImpl, sfAddrTaken)
|
||||
incl(n[1].sym.flags, sfAddrTaken)
|
||||
result = newHiddenAddrTaken(c, n, isOutParam)
|
||||
of nkBracketExpr:
|
||||
checkMinSonsLen(n, 1, c.config)
|
||||
if skipTypes(n[0].typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
|
||||
if n[0].kind == nkSym: incl(n[0].sym.flagsImpl, sfAddrTaken)
|
||||
if n[0].kind == nkSym: incl(n[0].sym.flags, sfAddrTaken)
|
||||
result = newHiddenAddrTaken(c, n, isOutParam)
|
||||
else:
|
||||
result = newHiddenAddrTaken(c, n, isOutParam)
|
||||
@@ -749,7 +760,7 @@ proc replaceHookMagic*(c: PContext, n: PNode, kind: TTypeAttachedOp): PNode =
|
||||
case kind
|
||||
of attachedDestructor:
|
||||
result = n
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar, tySink})
|
||||
let t = n[1].typ.skipTypes(abstractVar)
|
||||
let op = getAttachedOp(c.graph, t, attachedDestructor)
|
||||
if op != nil:
|
||||
result[0] = newSymNode(op)
|
||||
@@ -761,42 +772,34 @@ proc replaceHookMagic*(c: PContext, n: PNode, kind: TTypeAttachedOp): PNode =
|
||||
result[1] = skipAddr(n[1])
|
||||
of attachedTrace:
|
||||
result = n
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar, tySink})
|
||||
let t = n[1].typ.skipTypes(abstractVar)
|
||||
let op = getAttachedOp(c.graph, t, attachedTrace)
|
||||
if op != nil:
|
||||
result[0] = newSymNode(op)
|
||||
of attachedDup:
|
||||
result = n
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar, tySink})
|
||||
let t = n[1].typ.skipTypes(abstractVar)
|
||||
let op = getAttachedOp(c.graph, t, attachedDup)
|
||||
if op != nil:
|
||||
result[0] = newSymNode(op)
|
||||
if op.typ.len == 3:
|
||||
let boolLit = newIntLit(c.graph, n.info, 1)
|
||||
boolLit.typ = getSysType(c.graph, n.info, tyBool)
|
||||
boolLit.typ() = getSysType(c.graph, n.info, tyBool)
|
||||
result.add boolLit
|
||||
of attachedWasMoved:
|
||||
result = n
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar, tySink})
|
||||
let t = n[1].typ.skipTypes(abstractVar)
|
||||
let op = getAttachedOp(c.graph, t, attachedWasMoved)
|
||||
if op != nil:
|
||||
result[0] = newSymNode(op)
|
||||
analyseIfAddressTakenInCall(c, result, false)
|
||||
of attachedSink:
|
||||
result = n
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar, tySink})
|
||||
let op = getAttachedOp(c.graph, t, kind)
|
||||
if op != nil:
|
||||
result[0] = newSymNode(op)
|
||||
result = c.semAsgnOpr(c, n, nkSinkAsgn)
|
||||
of attachedAsgn:
|
||||
result = n
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar, tySink})
|
||||
let op = getAttachedOp(c.graph, t, kind)
|
||||
if op != nil:
|
||||
result[0] = newSymNode(op)
|
||||
result = c.semAsgnOpr(c, n, nkAsgn)
|
||||
of attachedDeepCopy:
|
||||
result = n
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar, tySink})
|
||||
let t = n[1].typ.skipTypes(abstractVar)
|
||||
let op = getAttachedOp(c.graph, t, kind)
|
||||
if op != nil:
|
||||
result[0] = newSymNode(op)
|
||||
|
||||
@@ -55,11 +55,11 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
if result.typ != nil:
|
||||
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
|
||||
elif {efWantStmt, efAllowStmt} * flags != {}:
|
||||
result.typ = newTypeS(tyVoid, c)
|
||||
result.typ() = newTypeS(tyVoid, c)
|
||||
else:
|
||||
localError(c.config, n.info, errExprXHasNoType %
|
||||
renderTree(result, {renderNoComments}))
|
||||
result.typ = errorType(c)
|
||||
result.typ() = errorType(c)
|
||||
|
||||
proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType = nil): PNode =
|
||||
rejectEmptyNode(n)
|
||||
@@ -81,14 +81,14 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType
|
||||
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
|
||||
result = semExprCheck(c, n, flags-{efTypeAllowed}, expectedType)
|
||||
if result.typ == nil and efInTypeof in flags:
|
||||
result.typ = c.voidType
|
||||
result.typ() = c.voidType
|
||||
elif result.typ == nil or result.typ == c.enforceVoidContext:
|
||||
localError(c.config, n.info, errExprXHasNoType %
|
||||
renderTree(result, {renderNoComments}))
|
||||
result.typ = errorType(c)
|
||||
result.typ() = errorType(c)
|
||||
elif result.typ.kind == tyError:
|
||||
# associates the type error to the current owner
|
||||
result.typ = errorType(c)
|
||||
result.typ() = errorType(c)
|
||||
elif efTypeAllowed in flags and result.typ.kind == tyProc and
|
||||
hasUnresolvedParams(result, {}):
|
||||
# mirrored with semOperand but only on efTypeAllowed
|
||||
@@ -100,7 +100,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType
|
||||
else:
|
||||
errProcHasNoConcreteType % n.renderTree
|
||||
localError(c.config, n.info, err)
|
||||
result.typ = errorType(c)
|
||||
result.typ() = errorType(c)
|
||||
else:
|
||||
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
|
||||
|
||||
@@ -109,7 +109,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
if result.typ == nil:
|
||||
localError(c.config, n.info, errExprXHasNoType %
|
||||
renderTree(result, {renderNoComments}))
|
||||
result.typ = errorType(c)
|
||||
result.typ() = errorType(c)
|
||||
|
||||
proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
@@ -195,7 +195,7 @@ proc semOpenSym(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType,
|
||||
result = nil
|
||||
if not isSym:
|
||||
# set symchoice node type back to None
|
||||
n.typ = newTypeS(tyNone, c)
|
||||
n.typ() = newTypeS(tyNone, c)
|
||||
|
||||
proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
|
||||
if n.kind == nkOpenSymChoice:
|
||||
@@ -217,7 +217,7 @@ proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: P
|
||||
err.add " " & candidate.owner.name.s & "." & candidate.name.s
|
||||
err.add ": " & typeToString(candidate.typ) & "\n"
|
||||
localError(c.config, n.info, err)
|
||||
n.typ = errorType(c)
|
||||
n.typ() = errorType(c)
|
||||
result = n
|
||||
if result.kind == nkSym:
|
||||
result = semSym(c, result, result.sym, flags)
|
||||
@@ -228,7 +228,7 @@ proc inlineConst(c: PContext, n: PNode, s: PSym): PNode {.inline.} =
|
||||
localError(c.config, n.info, "constant of type '" & typeToString(s.typ) & "' has no value")
|
||||
result = newSymNode(s)
|
||||
else:
|
||||
result.typ = s.typ
|
||||
result.typ() = s.typ
|
||||
result.info = n.info
|
||||
|
||||
type
|
||||
@@ -333,7 +333,7 @@ proc isCastable(c: PContext; dst, src: PType, info: TLineInfo): bool =
|
||||
if skipTypes(dst, abstractInst).kind == tyBuiltInTypeClass:
|
||||
return false
|
||||
let conf = c.config
|
||||
if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc, gcYrc}:
|
||||
if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
let d = skipTypes(dst, abstractInst)
|
||||
let s = skipTypes(src, abstractInst)
|
||||
if d.kind == tyRef and s.kind == tyRef and s[0].isFinal != d[0].isFinal:
|
||||
@@ -396,7 +396,7 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType
|
||||
var evaluated = semStaticExpr(c, n[1], expectedType)
|
||||
if evaluated.kind == nkType or evaluated.typ.kind == tyTypeDesc:
|
||||
result = n
|
||||
result.typ = c.makeTypeDesc semStaticType(c, evaluated, nil)
|
||||
result.typ() = c.makeTypeDesc semStaticType(c, evaluated, nil)
|
||||
return
|
||||
elif targetType.base.kind == tyNone:
|
||||
return evaluated
|
||||
@@ -412,9 +412,9 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType
|
||||
let baseType = semTypeNode(c, n[1], nil).skipTypes({tyTypeDesc})
|
||||
let t = newTypeS(targetType.kind, c, baseType)
|
||||
if targetType.kind == tyOwned:
|
||||
t.incl tfHasOwned
|
||||
t.flags.incl tfHasOwned
|
||||
result = newNodeI(nkType, n.info)
|
||||
result.typ = makeTypeDesc(c, t)
|
||||
result.typ() = makeTypeDesc(c, t)
|
||||
return
|
||||
|
||||
result.add copyTree(n[0])
|
||||
@@ -430,10 +430,10 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType
|
||||
if targetType.kind != tyGenericParam and targetType.isMetaType:
|
||||
let final = inferWithMetatype(c, targetType, op, true)
|
||||
result.add final
|
||||
result.typ = final.typ
|
||||
result.typ() = final.typ
|
||||
return
|
||||
|
||||
result.typ = targetType
|
||||
result.typ() = targetType
|
||||
# XXX op is overwritten later on, this is likely added too early
|
||||
# here or needs to be overwritten too then.
|
||||
result.add op
|
||||
@@ -441,7 +441,7 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType
|
||||
if targetType.kind == tyGenericParam or
|
||||
(op.typ != nil and op.typ.kind == tyFromExpr and c.inGenericContext > 0):
|
||||
# expression is compiled early in a generic body
|
||||
result.typ = makeTypeFromExpr(c, copyTree(result))
|
||||
result.typ() = makeTypeFromExpr(c, copyTree(result))
|
||||
return result
|
||||
|
||||
if not isSymChoice(op):
|
||||
@@ -491,7 +491,7 @@ proc semCast(c: PContext, n: PNode): PNode =
|
||||
if not isCastable(c, targetType, castedExpr.typ, n.info):
|
||||
localError(c.config, n.info, "expression cannot be cast to '$1'" % $targetType)
|
||||
result = newNodeI(nkCast, n.info)
|
||||
result.typ = targetType
|
||||
result.typ() = targetType
|
||||
result.add copyTree(n[0])
|
||||
result.add castedExpr
|
||||
|
||||
@@ -505,18 +505,18 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
|
||||
var typ = skipTypes(n[1].typ, abstractVarRange + {tyTypeDesc, tyUserTypeClassInst})
|
||||
case typ.kind
|
||||
of tySequence, tyString, tyCstring, tyOpenArray, tyVarargs:
|
||||
n.typ = getSysType(c.graph, n.info, tyInt)
|
||||
n.typ() = getSysType(c.graph, n.info, tyInt)
|
||||
of tyArray:
|
||||
n.typ = typ.indexType
|
||||
n.typ() = typ.indexType
|
||||
if n.typ.kind == tyRange and emptyRange(n.typ.n[0], n.typ.n[1]): #Invalid range
|
||||
n.typ = getSysType(c.graph, n.info, tyInt)
|
||||
n.typ() = getSysType(c.graph, n.info, tyInt)
|
||||
of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt..tyUInt64, tyFloat..tyFloat64:
|
||||
n.typ = n[1].typ.skipTypes({tyTypeDesc})
|
||||
n.typ() = n[1].typ.skipTypes({tyTypeDesc})
|
||||
of tyGenericParam:
|
||||
# prepare this for resolving in semtypinst:
|
||||
# we must use copyTree here in order to avoid creating a cycle
|
||||
# that could easily turn into an infinite recursion in semtypinst
|
||||
n.typ = makeTypeFromExpr(c, n.copyTree)
|
||||
n.typ() = makeTypeFromExpr(c, n.copyTree)
|
||||
else:
|
||||
localError(c.config, n.info, "invalid argument for: " & opToStr[m])
|
||||
result = n
|
||||
@@ -532,7 +532,7 @@ proc fixupStaticType(c: PContext, n: PNode) =
|
||||
# apply this measure only in code that is enlightened to work
|
||||
# with static types.
|
||||
if n.typ.kind != tyStatic:
|
||||
n.typ = newTypeS(tyStatic, c, n.typ)
|
||||
n.typ() = newTypeS(tyStatic, c, n.typ)
|
||||
n.typ.n = n # XXX: cycles like the one here look dangerous.
|
||||
# Consider using `n.copyTree`
|
||||
|
||||
@@ -578,18 +578,11 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
if efExplain in flags:
|
||||
m.diagnostics = @[]
|
||||
m.diagnosticsEnabled = true
|
||||
let rel = typeRel(m, t2, t1)
|
||||
res = rel >= isSubtype # isNone
|
||||
if res and rel == isEqual and
|
||||
not compareTypes(t1, t2,
|
||||
flags = {ExactTypeDescValues,
|
||||
PickyCAliases,
|
||||
PickyBackendAliases}):
|
||||
res = false
|
||||
res = typeRel(m, t2, t1) >= isSubtype # isNone
|
||||
# `res = sameType(t1, t2)` would be wrong, e.g. for `int is (int|float)`
|
||||
|
||||
result = newIntNode(nkIntLit, ord(res))
|
||||
result.typ = n.typ
|
||||
result.typ() = n.typ
|
||||
|
||||
proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
if n.len != 3 or n[2].kind == nkEmpty:
|
||||
@@ -598,7 +591,7 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
|
||||
let boolType = getSysType(c.graph, n.info, tyBool)
|
||||
result = n
|
||||
n.typ = boolType
|
||||
n.typ() = boolType
|
||||
var liftLhs = true
|
||||
|
||||
n[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator})
|
||||
@@ -612,7 +605,7 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
n[1] = evaluated
|
||||
else:
|
||||
result = newIntNode(nkIntLit, 0)
|
||||
result.typ = boolType
|
||||
result.typ() = boolType
|
||||
return
|
||||
elif t2.kind == tyTypeDesc and
|
||||
(t2.base.kind == tyNone or tfExplicit in t2.flags):
|
||||
@@ -642,7 +635,7 @@ proc semOpAux(c: PContext, n: PNode) =
|
||||
let info = a[0].info
|
||||
a[0] = newIdentNode(considerQuotedIdent(c, a[0], a), info)
|
||||
a[1] = semExprWithType(c, a[1], flags)
|
||||
a.typ = a[1].typ
|
||||
a.typ() = a[1].typ
|
||||
else:
|
||||
n[i] = semExprWithType(c, a, flags)
|
||||
|
||||
@@ -659,9 +652,6 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
|
||||
result = semExpr(c, result, flags = {efNoUndeclared})
|
||||
|
||||
proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
|
||||
template isViewTarget(t: PType): bool =
|
||||
t.skipTypes({tyGenericInst, tyAlias, tySink}).kind in {tyVar, tyLent}
|
||||
|
||||
case n.kind
|
||||
of nkCurly:
|
||||
for i in 0..<n.len:
|
||||
@@ -690,15 +680,12 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
|
||||
if f == nil:
|
||||
globalError(c.config, m.info, "unknown identifier: " & m.sym.name.s)
|
||||
return
|
||||
if not isViewTarget(f.typ):
|
||||
changeType(c, n[i][1], f.typ, check)
|
||||
changeType(c, n[i][1], f.typ, check)
|
||||
else:
|
||||
if not isViewTarget(tup[i]):
|
||||
changeType(c, n[i][1], tup[i], check)
|
||||
changeType(c, n[i][1], tup[i], check)
|
||||
else:
|
||||
for i in 0..<n.len:
|
||||
if not isViewTarget(tup[i]):
|
||||
changeType(c, n[i], tup[i], check)
|
||||
changeType(c, n[i], tup[i], check)
|
||||
when false:
|
||||
var m = n[i]
|
||||
var a = newNodeIT(nkExprColonExpr, m.info, newType[i])
|
||||
@@ -721,8 +708,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
|
||||
localError(c.config, n.info, "cannot convert '" & n.sym.name.s &
|
||||
"' to '" & typeNameAndDesc(newType) & "'")
|
||||
else: discard
|
||||
|
||||
n.typ = newType
|
||||
n.typ() = newType
|
||||
|
||||
proc arrayConstrType(c: PContext, n: PNode): PType =
|
||||
var typ = newTypeS(tyArray, c)
|
||||
@@ -744,12 +730,12 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
|
||||
var expectedElementType, expectedIndexType: PType = nil
|
||||
var expectedBase: PType = nil
|
||||
if constructType:
|
||||
result.typ = newTypeS(tyArray, c)
|
||||
result.typ() = newTypeS(tyArray, c)
|
||||
rawAddSon(result.typ, nil) # index type
|
||||
if expectedType != nil:
|
||||
expectedBase = expectedType.skipTypes(abstractRange-{tyDistinct})
|
||||
else:
|
||||
result.typ = n.typ
|
||||
result.typ() = n.typ
|
||||
expectedBase = n.typ.skipTypes(abstractRange) # include tyDistinct this time
|
||||
if expectedBase != nil:
|
||||
case expectedBase.kind
|
||||
@@ -829,9 +815,9 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
|
||||
for i in 0..<result.len:
|
||||
if result[i].typ != nil and isIntLit(result[i].typ):
|
||||
# generic instantiation strips int lit type which makes conversions fail
|
||||
result[i].typ = nil
|
||||
result.typ = nil # current result.typ is invalid, index type is nil
|
||||
result.typ = makeTypeFromExpr(c, result.copyTree)
|
||||
result[i].typ() = nil
|
||||
result.typ() = nil # current result.typ is invalid, index type is nil
|
||||
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
||||
return
|
||||
if constructType:
|
||||
addSonSkipIntLit(result.typ, typ, c.idgen)
|
||||
@@ -929,8 +915,8 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||
if n[i].typ.isNil or n[i].typ.kind != tyStatic or
|
||||
tfUnresolved notin n[i].typ.flags:
|
||||
break maybeLabelAsStatic
|
||||
n.typ = newTypeS(tyStatic, c, n.typ)
|
||||
n.typ.incl tfUnresolved
|
||||
n.typ() = newTypeS(tyStatic, c, n.typ)
|
||||
n.typ.flags.incl tfUnresolved
|
||||
|
||||
# optimization pass: not necessary for correctness of the semantic pass
|
||||
if (callee.kind == skConst or
|
||||
@@ -977,15 +963,12 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||
# echo "SUCCESS evaluated at compile time: ", call.renderTree
|
||||
|
||||
proc semStaticExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
|
||||
let oldErrorCount = c.config.errorCounter
|
||||
inc c.inStaticContext
|
||||
openScope(c)
|
||||
let a = semExprWithType(c, n, expectedType = expectedType)
|
||||
closeScope(c)
|
||||
dec c.inStaticContext
|
||||
if a.findUnresolvedStatic != nil or
|
||||
c.config.errorCounter != oldErrorCount:
|
||||
return a
|
||||
if a.findUnresolvedStatic != nil: return a
|
||||
result = evalStaticExpr(c.module, c.idgen, c.graph, a, c.p.owner)
|
||||
if result.isNil:
|
||||
localError(c.config, n.info, errCannotInterpretNodeX % renderTree(n))
|
||||
@@ -996,7 +979,7 @@ proc semStaticExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
|
||||
|
||||
proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
||||
flags: TExprFlags; expectedType: PType = nil): PNode =
|
||||
if flags*{efInTypeof, efWantIterator, efWantIterable, efPreferIteratorForIterable} != {}:
|
||||
if flags*{efInTypeof, efWantIterator, efWantIterable} != {}:
|
||||
# consider: 'for x in pReturningArray()' --> we don't want the restriction
|
||||
# to 'skIterator' anymore; skIterator is preferred in sigmatch already
|
||||
# for typeof support.
|
||||
@@ -1023,11 +1006,10 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
||||
# See bug #2051:
|
||||
result[0] = newSymNode(errorSym(c, n))
|
||||
elif callee.kind == skIterator:
|
||||
if result.typ.kind != tyIterable and
|
||||
flags * {efWantIterable, efPreferIteratorForIterable} != {}:
|
||||
if efWantIterable in flags:
|
||||
let typ = newTypeS(tyIterable, c)
|
||||
rawAddSon(typ, result.typ)
|
||||
result.typ = typ
|
||||
result.typ() = typ
|
||||
|
||||
proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
|
||||
t: PType): TCandidate =
|
||||
@@ -1114,7 +1096,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
|
||||
elif n0.typ.kind == tyFromExpr and c.inGenericContext > 0:
|
||||
# don't make assumptions, entire expression needs to be tyFromExpr
|
||||
result = semGenericStmt(c, n)
|
||||
result.typ = makeTypeFromExpr(c, result.copyTree)
|
||||
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
||||
return
|
||||
else:
|
||||
n[0] = n0
|
||||
@@ -1376,7 +1358,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
of tyStatic:
|
||||
if typ.n != nil:
|
||||
result = typ.n
|
||||
result.typ = typ.base
|
||||
result.typ() = typ.base
|
||||
else:
|
||||
result = newSymNode(s, n.info)
|
||||
else:
|
||||
@@ -1422,11 +1404,11 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
onUse(n.info, s)
|
||||
if s.typ.kind == tyStatic:
|
||||
result = newSymNode(s, n.info)
|
||||
result.typ = s.typ
|
||||
result.typ() = s.typ
|
||||
elif s.ast != nil:
|
||||
result = semExpr(c, s.ast)
|
||||
else:
|
||||
n.typ = s.typ
|
||||
n.typ() = s.typ
|
||||
return n
|
||||
of skType:
|
||||
if n.kind != nkDotExpr: # dotExpr is already checked by builtinFieldAccess
|
||||
@@ -1437,7 +1419,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil:
|
||||
return s.typ.n
|
||||
result = newSymNode(s, n.info)
|
||||
result.typ = makeTypeDesc(c, s.typ)
|
||||
result.typ() = makeTypeDesc(c, s.typ)
|
||||
of skField:
|
||||
# old code, not sure if it's live code:
|
||||
markUsed(c, n.info, s)
|
||||
@@ -1463,7 +1445,7 @@ proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode =
|
||||
if result == c.graph.emptyNode:
|
||||
if c.inGenericContext > 0:
|
||||
result = semGenericStmt(c, n)
|
||||
result.typ = makeTypeFromExpr(c, result.copyTree)
|
||||
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
||||
else:
|
||||
result = nil
|
||||
of tyUserTypeClasses:
|
||||
@@ -1471,7 +1453,7 @@ proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode =
|
||||
result = readTypeParameter(c, t, i, n.info)
|
||||
elif c.inGenericContext > 0:
|
||||
result = semGenericStmt(c, n)
|
||||
result.typ = makeTypeFromExpr(c, copyTree(result))
|
||||
result.typ() = makeTypeFromExpr(c, copyTree(result))
|
||||
else:
|
||||
result = nil
|
||||
of tyGenericBody, tyCompositeTypeClass:
|
||||
@@ -1480,12 +1462,12 @@ proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode =
|
||||
if result != nil:
|
||||
# generic parameter exists, stop here but delay until instantiation
|
||||
result = semGenericStmt(c, n)
|
||||
result.typ = makeTypeFromExpr(c, copyTree(result))
|
||||
result.typ() = makeTypeFromExpr(c, copyTree(result))
|
||||
else:
|
||||
result = nil
|
||||
elif c.inGenericContext > 0 and t.containsUnresolvedType:
|
||||
result = semGenericStmt(c, n)
|
||||
result.typ = makeTypeFromExpr(c, copyTree(result))
|
||||
result.typ() = makeTypeFromExpr(c, copyTree(result))
|
||||
else:
|
||||
result = nil
|
||||
|
||||
@@ -1503,14 +1485,14 @@ proc tryReadingTypeField(c: PContext, n: PNode, i: PIdent, ty: PType): PNode =
|
||||
if f != nil:
|
||||
result = newSymNode(f)
|
||||
result.info = n.info
|
||||
result.typ = ty
|
||||
result.typ() = ty
|
||||
markUsed(c, n.info, f)
|
||||
onUse(n.info, f)
|
||||
of tyObject, tyTuple:
|
||||
if ty.n != nil and ty.n.kind == nkRecList:
|
||||
let field = lookupInRecord(ty.n, i)
|
||||
if field != nil:
|
||||
n.typ = makeTypeDesc(c, field.typ)
|
||||
n.typ() = makeTypeDesc(c, field.typ)
|
||||
result = n
|
||||
of tyGenericInst:
|
||||
result = tryReadingTypeField(c, n, i, ty.skipModifier)
|
||||
@@ -1543,7 +1525,7 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
|
||||
return
|
||||
|
||||
# extra flags since LHS may become a call operand:
|
||||
n[0] = semExprWithType(c, n[0], flags + {efDetermineType, efWantIterable, efAllowSymChoice})
|
||||
n[0] = semExprWithType(c, n[0], flags+{efDetermineType, efWantIterable, efAllowSymChoice})
|
||||
#restoreOldStyleType(n[0])
|
||||
var i = considerQuotedIdent(c, n[1], n)
|
||||
var ty = n[0].typ
|
||||
@@ -1557,7 +1539,7 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
|
||||
# tyFromExpr, but when this happen in a macro this is not a built-in
|
||||
# field access and we leave the compiler to compile a normal call:
|
||||
if getCurrOwner(c).kind != skMacro:
|
||||
n.typ = makeTypeFromExpr(c, n.copyTree)
|
||||
n.typ() = makeTypeFromExpr(c, n.copyTree)
|
||||
flags.incl efCannotBeDotCall
|
||||
return n
|
||||
else:
|
||||
@@ -1597,12 +1579,12 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
|
||||
n[0] = makeDeref(n[0])
|
||||
n[1] = newSymNode(f) # we now have the correct field
|
||||
n[1].info = info # preserve the original info
|
||||
n.typ = f.typ
|
||||
n.typ() = f.typ
|
||||
if check == nil:
|
||||
result = n
|
||||
else:
|
||||
check[0] = n
|
||||
check.typ = n.typ
|
||||
check.typ() = n.typ
|
||||
result = check
|
||||
elif ty.kind == tyTuple and ty.n != nil:
|
||||
f = getSymFromList(ty.n, i)
|
||||
@@ -1611,7 +1593,7 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
|
||||
onUse(n[1].info, f)
|
||||
n[0] = makeDeref(n[0])
|
||||
n[1] = newSymNode(f)
|
||||
n.typ = f.typ
|
||||
n.typ() = f.typ
|
||||
result = n
|
||||
|
||||
# we didn't find any field, let's look for a generic param
|
||||
@@ -1680,9 +1662,9 @@ proc semDeref(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
localError(c.config, n.info, "missing generic parameter")
|
||||
return nil
|
||||
case t.kind
|
||||
of tyRef, tyPtr: n.typ = t.elementType
|
||||
of tyRef, tyPtr: n.typ() = t.elementType
|
||||
of tyMetaTypes, tyFromExpr:
|
||||
n.typ = makeTypeFromExpr(c, n.copyTree)
|
||||
n.typ() = makeTypeFromExpr(c, n.copyTree)
|
||||
else: result = nil
|
||||
#GlobalError(n[0].info, errCircumNeedsPointer)
|
||||
|
||||
@@ -1715,7 +1697,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags, afterOverloading = f
|
||||
if arr.kind == tyStatic:
|
||||
if arr.base.kind == tyNone:
|
||||
result = n
|
||||
result.typ = semStaticType(c, n[1], nil)
|
||||
result.typ() = semStaticType(c, n[1], nil)
|
||||
return
|
||||
elif arr.n != nil:
|
||||
return semSubscript(c, arr.n, flags, afterOverloading)
|
||||
@@ -1737,18 +1719,18 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags, afterOverloading = f
|
||||
if arg != nil:
|
||||
n[1] = arg
|
||||
result = n
|
||||
result.typ = elemType(arr)
|
||||
result.typ() = elemType(arr)
|
||||
# Other types have a bit more of leeway
|
||||
elif n[1].typ.skipTypes(abstractRange-{tyDistinct}).kind in
|
||||
{tyInt..tyInt64, tyUInt..tyUInt64}:
|
||||
result = n
|
||||
result.typ = elemType(arr)
|
||||
result.typ() = elemType(arr)
|
||||
of tyTypeDesc:
|
||||
# The result so far is a tyTypeDesc bound
|
||||
# a tyGenericBody. The line below will substitute
|
||||
# it with the instantiated type.
|
||||
result = n
|
||||
result.typ = makeTypeDesc(c, semTypeNode(c, n, nil))
|
||||
result.typ() = makeTypeDesc(c, semTypeNode(c, n, nil))
|
||||
#result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
|
||||
of tyTuple:
|
||||
if n.len != 2: return nil
|
||||
@@ -1758,7 +1740,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags, afterOverloading = f
|
||||
if skipTypes(n[1].typ, {tyGenericInst, tyRange, tyOrdinal, tyAlias, tySink}).kind in
|
||||
{tyInt..tyInt64}:
|
||||
let idx = getOrdValue(n[1])
|
||||
if idx >= 0 and idx < arr.len: n.typ = arr[toInt(idx)]
|
||||
if idx >= 0 and idx < arr.len: n.typ() = arr[toInt(idx)]
|
||||
else:
|
||||
localError(c.config, n.info,
|
||||
"invalid index $1 in subscript for tuple of length $2" %
|
||||
@@ -1855,7 +1837,7 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
|
||||
localError(c.config, n.info, errExprHasNoAddress)
|
||||
result = newNodeIT(nkHiddenAddr, n.info, if n.typ.kind in {tyVar, tyLent}: n.typ else: makePtrType(c, n.typ))
|
||||
if n.typ.kind in {tyVar, tyLent}:
|
||||
n.typ = n.typ.elementType
|
||||
n.typ() = n.typ.elementType
|
||||
result.add(n)
|
||||
|
||||
proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
|
||||
@@ -1865,10 +1847,10 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
|
||||
if x.sym.kind == skResult and (x.typ.kind in {tyVar, tyLent} or classifyViewType(x.typ) != noView):
|
||||
n[0] = x # 'result[]' --> 'result'
|
||||
n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent)
|
||||
x.typ.incl tfVarIsPtr
|
||||
x.typ.flags.incl tfVarIsPtr
|
||||
#echo x.info, " setting it for this type ", typeToString(x.typ), " ", n.info
|
||||
elif sfGlobal in x.sym.flags:
|
||||
x.typ.incl tfVarIsPtr
|
||||
x.typ.flags.incl tfVarIsPtr
|
||||
|
||||
proc borrowCheck(c: PContext, n, le, ri: PNode) =
|
||||
const
|
||||
@@ -1938,7 +1920,7 @@ proc makeTupleAssignments(c: PContext; n: PNode): PNode =
|
||||
|
||||
let temp = newSym(skTemp, getIdent(c.cache, "tmpTupleAsgn"), c.idgen, getCurrOwner(c), n.info)
|
||||
temp.typ = value.typ
|
||||
temp.flagsImpl.incl(sfGenSym)
|
||||
temp.flags.incl(sfGenSym)
|
||||
var v = newNodeI(nkLetSection, value.info)
|
||||
let tempNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
|
||||
var vpart = newNodeI(nkIdentDefs, v.info, 3)
|
||||
@@ -1955,7 +1937,7 @@ proc makeTupleAssignments(c: PContext; n: PNode): PNode =
|
||||
# generate `let _ = temp[i]` which should generate a destructor
|
||||
let utemp = newSym(skLet, lhs[i].ident, c.idgen, getCurrOwner(c), lhs[i].info)
|
||||
utemp.typ = value.typ[i]
|
||||
temp.flagsImpl.incl(sfGenSym)
|
||||
temp.flags.incl(sfGenSym)
|
||||
var uv = newNodeI(nkLetSection, lhs[i].info)
|
||||
let utempNode = newSymNode(utemp)
|
||||
var uvpart = newNodeI(nkIdentDefs, v.info, 3)
|
||||
@@ -2049,7 +2031,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||
let lhs = n[0]
|
||||
let rhs = semExprWithType(c, n[1], {efTypeAllowed}, le)
|
||||
if lhs.kind == nkSym and lhs.sym.kind == skResult:
|
||||
n.typ = c.enforceVoidContext
|
||||
n.typ() = c.enforceVoidContext
|
||||
if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ):
|
||||
var rhsTyp = rhs.typ
|
||||
if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass:
|
||||
@@ -2060,7 +2042,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||
internalAssert c.config, c.p.resultSym != nil
|
||||
# Make sure the type is valid for the result variable
|
||||
typeAllowedCheck(c, n.info, rhsTyp, skResult)
|
||||
lhs.typ = rhsTyp
|
||||
lhs.typ() = rhsTyp
|
||||
c.p.resultSym.typ = rhsTyp
|
||||
c.p.owner.typ.setReturnType rhsTyp
|
||||
else:
|
||||
@@ -2108,7 +2090,7 @@ proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode =
|
||||
if result.kind == nkNilLit:
|
||||
# or ImplicitlyDiscardable(result):
|
||||
# new semantic: 'result = x' triggers the void context
|
||||
result.typ = nil
|
||||
result.typ() = nil
|
||||
elif result.kind == nkStmtListExpr and result.typ.kind == tyNil:
|
||||
# to keep backwards compatibility bodies like:
|
||||
# nil
|
||||
@@ -2142,7 +2124,7 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
|
||||
var t = skipTypes(restype, {tyGenericInst, tyAlias, tySink})
|
||||
case t.kind
|
||||
of tyVar, tyLent:
|
||||
t.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
|
||||
t.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
|
||||
if n[0].kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
||||
n[0] = n[0][1]
|
||||
n[0] = takeImplicitAddr(c, n[0], t.kind == tyLent)
|
||||
@@ -2150,7 +2132,7 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
|
||||
for i in 0..<t.len:
|
||||
let e = skipTypes(t[i], {tyGenericInst, tyAlias, tySink})
|
||||
if e.kind in {tyVar, tyLent}:
|
||||
e.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
|
||||
e.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
|
||||
let tupleConstr = if n[0].kind in {nkHiddenStdConv, nkHiddenSubConv}: n[0][1] else: n[0]
|
||||
if tupleConstr.kind in {nkPar, nkTupleConstr}:
|
||||
if tupleConstr[i].kind == nkExprColonExpr:
|
||||
@@ -2211,7 +2193,7 @@ proc semDefined(c: PContext, n: PNode): PNode =
|
||||
result = newIntNode(nkIntLit, 0)
|
||||
result.intVal = ord isDefined(c.config, considerQuotedIdentOrDot(c, n[1], n).s)
|
||||
result.info = n.info
|
||||
result.typ = getSysType(c.graph, n.info, tyBool)
|
||||
result.typ() = getSysType(c.graph, n.info, tyBool)
|
||||
|
||||
proc lookUpForDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
|
||||
case n.kind
|
||||
@@ -2247,7 +2229,7 @@ proc semDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
|
||||
result = newIntNode(nkIntLit, 0)
|
||||
result.intVal = ord lookUpForDeclared(c, n[1], onlyCurrentScope) != nil
|
||||
result.info = n.info
|
||||
result.typ = getSysType(c.graph, n.info, tyBool)
|
||||
result.typ() = getSysType(c.graph, n.info, tyBool)
|
||||
|
||||
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym =
|
||||
## The argument to the proc should be nkCall(...) or similar
|
||||
@@ -2320,10 +2302,10 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||
localError(c.config, n.info, "getAst takes a call, but got " & n.renderTree)
|
||||
# Preserve the magic symbol in order to be handled in evals.nim
|
||||
internalAssert c.config, n[0].sym.magic == mExpandToAst
|
||||
#n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType
|
||||
#n.typ() = getSysSym("NimNode").typ # expandedSym.getReturnType
|
||||
if n.kind == nkStmtList and n.len == 1: result = n[0]
|
||||
else: result = n
|
||||
result.typ = sysTypeFromName(c.graph, n.info, "NimNode")
|
||||
result.typ() = sysTypeFromName(c.graph, n.info, "NimNode")
|
||||
|
||||
proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
|
||||
flags: TExprFlags = {}): PNode =
|
||||
@@ -2394,7 +2376,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||
processQuotations(c, quotedBlock, op, quotes, ids)
|
||||
|
||||
let dummyTemplateSym = newAnonSym(c, skTemplate, n.info)
|
||||
incl(dummyTemplateSym.flagsImpl, sfTemplateRedefinition)
|
||||
incl(dummyTemplateSym.flags, sfTemplateRedefinition)
|
||||
var dummyTemplate = newProcNode(
|
||||
nkTemplateDef, quotedBlock.info, body = quotedBlock,
|
||||
params = c.graph.emptyNode,
|
||||
@@ -2493,7 +2475,7 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
|
||||
result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil))
|
||||
result.info = n.info
|
||||
result.typ = getSysType(c.graph, n.info, tyBool)
|
||||
result.typ() = getSysType(c.graph, n.info, tyBool)
|
||||
|
||||
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
if n.len == 3:
|
||||
@@ -2523,9 +2505,8 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
|
||||
# since it's an instantiation, we unmark it as a compilerproc. Otherwise
|
||||
# codegen would fail:
|
||||
if sfCompilerProc in result.flags:
|
||||
ensureMutable result
|
||||
result.flagsImpl.excl {sfCompilerProc, sfExportc, sfImportc}
|
||||
result.locImpl.snippet = ""
|
||||
result.flags.excl {sfCompilerProc, sfExportc, sfImportc}
|
||||
result.loc.snippet = ""
|
||||
|
||||
proc setMs(n: PNode, s: PSym): PNode =
|
||||
result = n
|
||||
@@ -2538,7 +2519,7 @@ proc semSizeof(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
n[1] = semExprWithType(c, n[1], {efDetermineType})
|
||||
#restoreOldStyleType(n[1])
|
||||
n.typ = getSysType(c.graph, n.info, tyInt)
|
||||
n.typ() = getSysType(c.graph, n.info, tyInt)
|
||||
result = foldSizeOf(c.config, n, n)
|
||||
|
||||
proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: PType = nil): PNode =
|
||||
@@ -2580,7 +2561,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
|
||||
markUsed(c, n.info, s)
|
||||
checkSonsLen(n, 2, c.config)
|
||||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph)
|
||||
result.typ = getSysType(c.graph, n.info, tyString)
|
||||
result.typ() = getSysType(c.graph, n.info, tyString)
|
||||
of mParallel:
|
||||
markUsed(c, n.info, s)
|
||||
if parallel notin c.features:
|
||||
@@ -2606,9 +2587,9 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
|
||||
let typ = result[^1].typ
|
||||
if not typ.isEmptyType:
|
||||
if spawnResult(typ, c.inParallelStmt > 0) == srFlowVar:
|
||||
result.typ = createFlowVar(c, typ, n.info)
|
||||
result.typ() = createFlowVar(c, typ, n.info)
|
||||
else:
|
||||
result.typ = typ
|
||||
result.typ() = typ
|
||||
result.add instantiateCreateFlowVarCall(c, typ, n.info).newSymNode
|
||||
else:
|
||||
result.add c.graph.emptyNode
|
||||
@@ -2616,7 +2597,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
|
||||
markUsed(c, n.info, s)
|
||||
result = setMs(n, s)
|
||||
result[1] = semExpr(c, n[1])
|
||||
result.typ = n[1].typ
|
||||
result.typ() = n[1].typ
|
||||
of mPlugin:
|
||||
markUsed(c, n.info, s)
|
||||
# semDirectOp with conditional 'afterCallActions':
|
||||
@@ -2747,19 +2728,19 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||
else: illFormedAst(n, c.config)
|
||||
if cannotResolve:
|
||||
result = semGenericStmt(c, n)
|
||||
result.typ = makeTypeFromExpr(c, result.copyTree)
|
||||
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
||||
return
|
||||
if result == nil:
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
if whenNimvm:
|
||||
result.typ = typ
|
||||
result.typ() = typ
|
||||
if n.len == 1:
|
||||
result.add(newTree(nkElse, newNode(nkStmtList)))
|
||||
|
||||
proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
|
||||
result = newNodeI(nkCurly, n.info)
|
||||
result.typ = newTypeS(tySet, c)
|
||||
result.typ.incl tfIsConstructor
|
||||
result.typ() = newTypeS(tySet, c)
|
||||
result.typ.flags.incl tfIsConstructor
|
||||
var expectedElementType: PType = nil
|
||||
if expectedType != nil and (
|
||||
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
|
||||
@@ -2789,7 +2770,7 @@ proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
|
||||
if doSetType:
|
||||
typ = skipTypes(n[i][1].typ,
|
||||
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
||||
n[i].typ = n[i][2].typ # range node needs type too
|
||||
n[i].typ() = n[i][2].typ # range node needs type too
|
||||
elif n[i].kind == nkRange:
|
||||
# already semchecked
|
||||
if doSetType:
|
||||
@@ -2820,9 +2801,9 @@ proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
|
||||
for i in 0..<n.len:
|
||||
if n[i].typ != nil and isIntLit(n[i].typ):
|
||||
# generic instantiation strips int lit type which makes conversions fail
|
||||
n[i].typ = nil
|
||||
n[i].typ() = nil
|
||||
result.add n[i]
|
||||
result.typ = makeTypeFromExpr(c, result.copyTree)
|
||||
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
||||
return
|
||||
addSonSkipIntLit(result.typ, typ, c.idgen)
|
||||
for i in 0..<n.len:
|
||||
@@ -2920,7 +2901,7 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType
|
||||
|
||||
if n[i][1].typ.kind == tyTypeDesc:
|
||||
localError(c.config, n[i][1].info, "typedesc not allowed as tuple field.")
|
||||
n[i][1].typ = errorType(c)
|
||||
n[i][1].typ() = errorType(c)
|
||||
|
||||
var f = newSymS(skField, n[i][0], c)
|
||||
f.typ = skipIntLit(n[i][1].typ.skipTypes({tySink}), c.idgen)
|
||||
@@ -2933,17 +2914,17 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType
|
||||
for i in 0..<result.len:
|
||||
if result[i][1].typ != nil and isIntLit(result[i][1].typ):
|
||||
# generic instantiation strips int lit type which makes conversions fail
|
||||
result[i][1].typ = nil
|
||||
result.typ = makeTypeFromExpr(c, result.copyTree)
|
||||
result[i][1].typ() = nil
|
||||
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
||||
return
|
||||
let oldType = n.typ
|
||||
result.typ = typ
|
||||
result.typ() = typ
|
||||
if oldType != nil and not hasEmpty(oldType): # see hasEmpty comment above
|
||||
# convert back to old type
|
||||
let conversion = indexTypesMatch(c, oldType, typ, result)
|
||||
# ignore matching error, the goal is just to keep the original type info
|
||||
if conversion != nil:
|
||||
result.typ = oldType
|
||||
result.typ() = oldType
|
||||
|
||||
proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
|
||||
result = n # we don't modify n, but compute the type:
|
||||
@@ -2974,17 +2955,17 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedT
|
||||
for i in 0..<result.len:
|
||||
if result[i].typ != nil and isIntLit(result[i].typ):
|
||||
# generic instantiation strips int lit type which makes conversions fail
|
||||
result[i].typ = nil
|
||||
result.typ = makeTypeFromExpr(c, result.copyTree)
|
||||
result[i].typ() = nil
|
||||
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
||||
return
|
||||
let oldType = n.typ
|
||||
result.typ = typ
|
||||
result.typ() = typ
|
||||
if oldType != nil and not hasEmpty(oldType): # see hasEmpty comment above
|
||||
# convert back to old type
|
||||
let conversion = indexTypesMatch(c, oldType, typ, result)
|
||||
# ignore matching error, the goal is just to keep the original type info
|
||||
if conversion != nil:
|
||||
result.typ = oldType
|
||||
result.typ() = oldType
|
||||
|
||||
include semobjconstr
|
||||
|
||||
@@ -3006,7 +2987,7 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = ni
|
||||
styleCheckDef(c, labl)
|
||||
onDef(n[0].info, labl)
|
||||
n[1] = semExpr(c, n[1], flags, expectedType)
|
||||
n.typ = n[1].typ
|
||||
n.typ() = n[1].typ
|
||||
if isEmptyType(n.typ): n.transitionSonsKind(nkBlockStmt)
|
||||
else: n.transitionSonsKind(nkBlockExpr)
|
||||
closeScope(c)
|
||||
@@ -3031,9 +3012,9 @@ proc semExportExcept(c: PContext, n: PNode): PNode =
|
||||
|
||||
proc semExport(c: PContext, n: PNode): PNode =
|
||||
proc specialSyms(c: PContext; s: PSym) {.inline.} =
|
||||
if s.kind == skConverter: addConverter(c, s)
|
||||
if s.kind == skConverter: addConverter(c, LazySym(sym: s))
|
||||
elif s.kind == skType and s.typ != nil and s.typ.kind == tyEnum and sfPure in s.flags:
|
||||
addPureEnum(c, s)
|
||||
addPureEnum(c, LazySym(sym: s))
|
||||
|
||||
result = newNodeI(nkExportStmt, n.info)
|
||||
for i in 0..<n.len:
|
||||
@@ -3097,7 +3078,7 @@ proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
|
||||
if isTupleType: # expressions as ``(int, string)`` are reinterpret as type expressions
|
||||
result = n
|
||||
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
|
||||
result.typ = makeTypeDesc(c, typ)
|
||||
result.typ() = makeTypeDesc(c, typ)
|
||||
|
||||
proc isExplicitGenericCall(c: PContext, n: PNode): bool =
|
||||
## checks if a call node `n` is a routine call with explicit generic params
|
||||
@@ -3242,7 +3223,7 @@ proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym; flags: TExprFlags): PNod
|
||||
a = initOverloadIter(o, c, n)
|
||||
while a != nil:
|
||||
if a.kind == skEnumField:
|
||||
incl(a.flagsImpl, sfUsed)
|
||||
incl(a.flags, sfUsed)
|
||||
markOwnerModuleAsUsed(c, a)
|
||||
result.add newSymNode(a, info)
|
||||
onUse(info, a)
|
||||
@@ -3317,10 +3298,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
|
||||
if expectedType != nil and (
|
||||
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
|
||||
expected.kind == typeKind):
|
||||
result.typ = expected
|
||||
result.typ() = expected
|
||||
changeType(c, result, expectedType, check=true)
|
||||
else:
|
||||
result.typ = getSysType(c.graph, n.info, typeKind)
|
||||
result.typ() = getSysType(c.graph, n.info, typeKind)
|
||||
|
||||
result = n
|
||||
when defined(nimsuggest):
|
||||
@@ -3356,7 +3337,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
|
||||
# localError(c.config, n.info, errInstantiateXExplicitly, s.name.s)
|
||||
# "procs literals" are 'owned'
|
||||
if optOwnedRefs in c.config.globalOptions:
|
||||
result.typ = makeVarType(c, result.typ, tyOwned)
|
||||
result.typ() = makeVarType(c, result.typ, tyOwned)
|
||||
of skEnumField:
|
||||
result = enumFieldSymChoice(c, n, s, flags)
|
||||
else:
|
||||
@@ -3385,11 +3366,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
|
||||
discard
|
||||
of nkNilLit:
|
||||
if result.typ == nil:
|
||||
result.typ = getNilType(c)
|
||||
result.typ() = getNilType(c)
|
||||
if expectedType != nil and expectedType.kind notin {tyUntyped, tyTyped}:
|
||||
var m = newCandidate(c, result.typ)
|
||||
if typeRel(m, expectedType, result.typ) >= isSubtype:
|
||||
result.typ = expectedType
|
||||
result.typ() = expectedType
|
||||
# or: result = fitNode(c, expectedType, result, n.info)
|
||||
of nkIntLit:
|
||||
if result.typ == nil:
|
||||
@@ -3417,10 +3398,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
|
||||
if expectedType != nil and (
|
||||
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
|
||||
expected.kind in {tyFloat..tyFloat128}):
|
||||
result.typ = expected
|
||||
result.typ() = expected
|
||||
changeType(c, result, expectedType, check=true)
|
||||
else:
|
||||
result.typ = getSysType(c.graph, n.info, tyFloat64)
|
||||
result.typ() = getSysType(c.graph, n.info, tyFloat64)
|
||||
of nkFloat32Lit: directLiteral(tyFloat32)
|
||||
of nkFloat64Lit: directLiteral(tyFloat64)
|
||||
of nkFloat128Lit: directLiteral(tyFloat128)
|
||||
@@ -3429,9 +3410,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
|
||||
if expectedType != nil and (
|
||||
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
|
||||
expected.kind in {tyString, tyCstring}):
|
||||
result.typ = expectedType
|
||||
result.typ() = expectedType
|
||||
else:
|
||||
result.typ = getSysType(c.graph, n.info, tyString)
|
||||
result.typ() = getSysType(c.graph, n.info, tyString)
|
||||
of nkCharLit: directLiteral(tyChar)
|
||||
of nkDotExpr:
|
||||
result = semFieldAccess(c, n, flags)
|
||||
@@ -3446,13 +3427,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
|
||||
let modifier = n.modifierTypeKindOfNode
|
||||
if modifier != tyNone:
|
||||
var baseType = semExpr(c, n[0]).typ.skipTypes({tyTypeDesc})
|
||||
result.typ = c.makeTypeDesc(newTypeS(modifier, c, baseType))
|
||||
result.typ() = c.makeTypeDesc(newTypeS(modifier, c, baseType))
|
||||
return
|
||||
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
|
||||
result.typ = makeTypeDesc(c, typ)
|
||||
result.typ() = makeTypeDesc(c, typ)
|
||||
of nkStmtListType:
|
||||
let typ = semTypeNode(c, n, nil)
|
||||
result.typ = makeTypeDesc(c, typ)
|
||||
result.typ() = makeTypeDesc(c, typ)
|
||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
||||
# check if it is an expression macro:
|
||||
checkMinSonsLen(n, 1, c.config)
|
||||
|
||||
@@ -24,7 +24,7 @@ proc wrapNewScope(c: PContext, n: PNode): PNode {.inline.} =
|
||||
# a scope has to be opened in the codegen as well for reused
|
||||
# template instantiations
|
||||
let trueLit = newIntLit(c.graph, n.info, 1)
|
||||
trueLit.typ = getSysType(c.graph, n.info, tyBool)
|
||||
trueLit.typ() = getSysType(c.graph, n.info, tyBool)
|
||||
result = newTreeI(nkIfStmt, n.info, newTreeI(nkElifBranch, n.info, trueLit, n))
|
||||
|
||||
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
|
||||
|
||||
@@ -24,7 +24,7 @@ when defined(nimPreviewSlimSystem):
|
||||
proc errorType*(g: ModuleGraph): PType =
|
||||
## creates a type representing an error state
|
||||
result = newType(tyError, g.idgen, g.owners[^1])
|
||||
result.flagsImpl.incl tfCheckedForDestructor
|
||||
result.flags.incl tfCheckedForDestructor
|
||||
|
||||
proc getIntLitTypeG(g: ModuleGraph; literal: PNode; idgen: IdGenerator): PType =
|
||||
# we cache some common integer literal types for performance:
|
||||
@@ -38,7 +38,7 @@ proc newIntNodeT*(intVal: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph):
|
||||
# original type was 'int', not a distinct int etc.
|
||||
if n.typ.kind == tyInt:
|
||||
# access cache for the int lit type
|
||||
result.typ = getIntLitTypeG(g, result, idgen)
|
||||
result.typ() = getIntLitTypeG(g, result, idgen)
|
||||
result.info = n.info
|
||||
|
||||
proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
|
||||
@@ -46,12 +46,12 @@ proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
|
||||
result = newFloatNode(nkFloat32Lit, floatVal)
|
||||
else:
|
||||
result = newFloatNode(nkFloatLit, floatVal)
|
||||
result.typ = n.typ
|
||||
result.typ() = n.typ
|
||||
result.info = n.info
|
||||
|
||||
proc newStrNodeT*(strVal: string, n: PNode; g: ModuleGraph): PNode =
|
||||
result = newStrNode(nkStrLit, strVal)
|
||||
result.typ = n.typ
|
||||
result.typ() = n.typ
|
||||
result.info = n.info
|
||||
|
||||
proc getConstExpr*(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
|
||||
@@ -201,8 +201,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
|
||||
result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl valueB), n, idgen, g)
|
||||
else: internalError(g.config, n.info, "constant folding for shl")
|
||||
of mShrI:
|
||||
var a = castToUInt64(getInt(a))
|
||||
let b = castToUInt64(getInt(b)) and cast[uint64](n.typ.size * 8 - 1)
|
||||
var a = cast[uint64](getInt(a))
|
||||
let b = cast[uint64](getInt(b)) and cast[uint64](n.typ.size * 8 - 1)
|
||||
# To support the ``-d:nimOldShiftRight`` flag, we need to mask the
|
||||
# signed integers to cut off the extended sign bit in the internal
|
||||
# representation.
|
||||
@@ -321,7 +321,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
|
||||
of mEnumToStr: result = newStrNodeT(ordinalValToString(a, g), n, g)
|
||||
of mArrToSeq:
|
||||
result = copyTree(a)
|
||||
result.typ = n.typ
|
||||
result.typ() = n.typ
|
||||
of mCompileOption:
|
||||
result = newIntNodeT(toInt128(ord(commands.testCompileOption(g.config, a.getStr, n.info))), n, idgen, g)
|
||||
of mCompileOptionArg:
|
||||
@@ -416,7 +416,7 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P
|
||||
result = newIntNodeT(toInt128(a.getOrdValue != 0), n, idgen, g)
|
||||
of tyBool, tyEnum: # xxx shouldn't we disallow `tyEnum`?
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
result.typ() = n.typ
|
||||
else:
|
||||
raiseAssert $srcTyp.kind
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
@@ -433,7 +433,7 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P
|
||||
result = newIntNodeT(val, n, idgen, g)
|
||||
else:
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
result.typ() = n.typ
|
||||
if check and result.kind in {nkCharLit..nkUInt64Lit} and
|
||||
dstTyp.kind notin {tyUInt..tyUInt64}:
|
||||
rangeCheck(n, getInt(result), g)
|
||||
@@ -443,12 +443,12 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P
|
||||
result = newFloatNodeT(toFloat64(getOrdValue(a)), n, g)
|
||||
else:
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
result.typ() = n.typ
|
||||
of tyOpenArray, tyVarargs, tyProc, tyPointer:
|
||||
result = nil
|
||||
else:
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
result.typ() = n.typ
|
||||
|
||||
proc getArrayConstr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
|
||||
if n.kind == nkBracket:
|
||||
@@ -520,10 +520,10 @@ proc foldConStrStr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
|
||||
proc newSymNodeTypeDesc*(s: PSym; idgen: IdGenerator; info: TLineInfo): PNode =
|
||||
result = newSymNode(s, info)
|
||||
if s.typ.kind != tyTypeDesc:
|
||||
result.typ = newType(tyTypeDesc, idgen, s.owner)
|
||||
result.typ() = newType(tyTypeDesc, idgen, s.owner)
|
||||
result.typ.addSonSkipIntLit(s.typ, idgen)
|
||||
else:
|
||||
result.typ = s.typ
|
||||
result.typ() = s.typ
|
||||
|
||||
proc foldDefine(m, s: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
|
||||
result = nil
|
||||
@@ -642,7 +642,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
|
||||
if s.typ.kind == tyStatic:
|
||||
if s.typ.n != nil and tfUnresolved notin s.typ.flags:
|
||||
result = s.typ.n
|
||||
result.typ = s.typ.base
|
||||
result.typ() = s.typ.base
|
||||
elif s.typ.isIntLit:
|
||||
result = s.typ.n
|
||||
else:
|
||||
@@ -755,7 +755,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
|
||||
if a == nil: return
|
||||
if leValueConv(n[1], a) and leValueConv(a, n[2]):
|
||||
result = a # a <= x and x <= b
|
||||
result.typ = n.typ
|
||||
result.typ() = n.typ
|
||||
elif n.typ.kind in {tyUInt..tyUInt64}:
|
||||
discard "don't check uints"
|
||||
else:
|
||||
@@ -766,7 +766,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
|
||||
var a = getConstExpr(m, n[0], idgen, g)
|
||||
if a == nil: return
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
result.typ() = n.typ
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
var a = getConstExpr(m, n[1], idgen, g)
|
||||
if a == nil: return
|
||||
@@ -783,7 +783,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
|
||||
not (n.typ.kind == tyProc and a.typ.kind == tyProc):
|
||||
# we allow compile-time 'cast' for pointer types:
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
result.typ() = n.typ
|
||||
of nkBracketExpr: result = foldArrayAccess(m, n, idgen, g)
|
||||
of nkDotExpr: result = foldFieldAccess(m, n, idgen, g)
|
||||
of nkCheckedFieldExpr:
|
||||
|
||||
@@ -50,13 +50,13 @@ proc semGenericStmtScope(c: PContext, n: PNode,
|
||||
result = semGenericStmt(c, n, flags, ctx)
|
||||
closeScope(c)
|
||||
|
||||
template isMixedIn(sym): bool {.dirty.} =
|
||||
template isMixedIn(sym): bool =
|
||||
let s = sym
|
||||
s.name.id in ctx.toMixin or (withinConcept in flags and
|
||||
s.magic == mNone and
|
||||
s.kind in OverloadableSyms)
|
||||
|
||||
template canOpenSym(s): bool {.dirty.} =
|
||||
template canOpenSym(s): bool =
|
||||
{withinMixin, withinConcept} * flags == {withinMixin} and s.id notin ctx.toBind
|
||||
|
||||
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
@@ -65,7 +65,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
fromDotExpr=false): PNode =
|
||||
result = nil
|
||||
semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
|
||||
incl(s.flagsImpl, sfUsed)
|
||||
incl(s.flags, sfUsed)
|
||||
template maybeDotChoice(c: PContext, n: PNode, s: PSym, fromDotExpr: bool) =
|
||||
if fromDotExpr:
|
||||
result = symChoice(c, n, s, scForceOpen)
|
||||
@@ -78,10 +78,10 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
if result.kind == nkSym:
|
||||
result = newOpenSym(result)
|
||||
else:
|
||||
result.typ = nil
|
||||
result.typ() = nil
|
||||
else:
|
||||
result.flags.incl nfDisabledOpenSym
|
||||
result.typ = nil
|
||||
result.typ() = nil
|
||||
case s.kind
|
||||
of skUnknown:
|
||||
# Introduced in this pass! Leave it as an identifier.
|
||||
@@ -116,7 +116,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
result = newOpenSym(result)
|
||||
else:
|
||||
result.flags.incl nfDisabledOpenSym
|
||||
result.typ = nil
|
||||
result.typ() = nil
|
||||
else:
|
||||
result = n
|
||||
else:
|
||||
@@ -126,7 +126,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
result = newOpenSym(result)
|
||||
else:
|
||||
result.flags.incl nfDisabledOpenSym
|
||||
result.typ = nil
|
||||
result.typ() = nil
|
||||
onUse(n.info, s)
|
||||
of skParam:
|
||||
result = n
|
||||
@@ -145,7 +145,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
result = newOpenSym(result)
|
||||
else:
|
||||
result.flags.incl nfDisabledOpenSym
|
||||
result.typ = nil
|
||||
result.typ() = nil
|
||||
elif c.inGenericContext > 0 and withinConcept notin flags:
|
||||
# don't leave generic param as identifier node in generic type,
|
||||
# sigmatch will try to instantiate generic type AST without all params
|
||||
@@ -157,7 +157,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
result = newOpenSym(result)
|
||||
else:
|
||||
result.flags.incl nfDisabledOpenSym
|
||||
result.typ = nil
|
||||
result.typ() = nil
|
||||
else:
|
||||
result = n
|
||||
onUse(n.info, s)
|
||||
@@ -168,7 +168,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
result = newOpenSym(result)
|
||||
else:
|
||||
result.flags.incl nfDisabledOpenSym
|
||||
result.typ = nil
|
||||
result.typ() = nil
|
||||
onUse(n.info, s)
|
||||
|
||||
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
@@ -248,13 +248,13 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
|
||||
onDef(n.info, s)
|
||||
|
||||
proc addTempDeclToIdents(c: PContext; n: PNode; kind: TSymKind; inCall: bool) =
|
||||
case n.kind
|
||||
case n.kind
|
||||
of nkIdent:
|
||||
if inCall:
|
||||
addTempDecl(c, n, kind)
|
||||
of nkCallKinds:
|
||||
for s in n:
|
||||
addTempDeclToIdents(c, s, kind, true)
|
||||
addTempDeclToIdents(c, s, kind, true)
|
||||
else:
|
||||
for s in n:
|
||||
addTempDeclToIdents(c, s, kind, inCall)
|
||||
@@ -274,7 +274,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
result = lookup(c, n, flags, ctx)
|
||||
if result != nil and result.kind == nkSym:
|
||||
assert result.sym != nil
|
||||
incl result.sym.flagsImpl, sfUsed
|
||||
incl result.sym.flags, sfUsed
|
||||
markOwnerModuleAsUsed(c, result.sym)
|
||||
of nkDotExpr:
|
||||
#let luf = if withinMixin notin flags: {checkUndeclared} else: {}
|
||||
@@ -318,7 +318,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
var first = int ord(withinConcept in flags)
|
||||
var mixinContext = false
|
||||
if s != nil:
|
||||
incl(s.flagsImpl, sfUsed)
|
||||
incl(s.flags, sfUsed)
|
||||
mixinContext = s.magic in {mDefined, mDeclared, mDeclaredInScope, mCompiles, mAstToStr}
|
||||
let whichChoice = if s.id in ctx.toBind: scClosed
|
||||
elif s.isMixedIn: scForceOpen
|
||||
@@ -632,7 +632,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
# treat as mixin context for user pragmas & macro args
|
||||
x[j] = semGenericStmt(c, x[j], flags+{withinMixin}, ctx)
|
||||
elif prag == wInvalid:
|
||||
# only sem if not a language-level pragma
|
||||
# only sem if not a language-level pragma
|
||||
# treat as mixin context for user pragmas & macro args
|
||||
result[i] = semGenericStmt(c, x, flags+{withinMixin}, ctx)
|
||||
of nkExprColonExpr, nkExprEqExpr:
|
||||
|
||||
@@ -24,7 +24,7 @@ proc addObjFieldsToLocalScope(c: PContext; n: PNode) =
|
||||
let f = n.sym
|
||||
if f.kind == skField and fieldVisible(c, f):
|
||||
c.currentScope.symbols.strTableIncl(f, onConflictKeepOld=true)
|
||||
incl(f.flagsImpl, sfUsed)
|
||||
incl(f.flags, sfUsed)
|
||||
# it is not an error to shadow fields via parameters
|
||||
else: discard
|
||||
|
||||
@@ -42,7 +42,7 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: LayeredIdTable):
|
||||
if q.typ.kind in {tyTypeDesc, tyGenericParam, tyStatic, tyConcept}+tyTypeClasses:
|
||||
let symKind = if q.typ.kind == tyStatic: skConst else: skType
|
||||
var s = newSym(symKind, q.name, c.idgen, getCurrOwner(c), q.info)
|
||||
s.flagsImpl.incl {sfUsed, sfFromGeneric}
|
||||
s.flags.incl {sfUsed, sfFromGeneric}
|
||||
var t = lookup(pt, q.typ)
|
||||
if t == nil:
|
||||
if tfRetType in q.typ.flags:
|
||||
@@ -81,8 +81,7 @@ proc sameInstantiation(a, b: TInstantiation): bool =
|
||||
if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
|
||||
flags = {ExactTypeDescValues,
|
||||
ExactGcSafety,
|
||||
PickyCAliases,
|
||||
PickyBackendAliases}): return
|
||||
PickyCAliases}): return
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
@@ -150,7 +149,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
|
||||
nil
|
||||
b = semProcBody(c, b, resultType)
|
||||
result.ast[bodyPos] = hloBody(c, b)
|
||||
excl(result, sfForward)
|
||||
excl(result.flags, sfForward)
|
||||
trackProc(c, result, result.ast[bodyPos])
|
||||
dec c.inGenericInst
|
||||
|
||||
@@ -209,7 +208,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||
|
||||
# this scope was not created by the user,
|
||||
# unused params shouldn't be reported.
|
||||
param.flagsImpl.incl sfUsed
|
||||
param.flags.incl sfUsed
|
||||
addDecl(c, param)
|
||||
|
||||
result = replaceTypeVarsT(cl, header)
|
||||
@@ -245,8 +244,7 @@ proc instantiateProcType(c: PContext, pt: LayeredIdTable,
|
||||
var result = instCopyType(cl, prc.typ)
|
||||
let originalParams = result.n
|
||||
result.n = originalParams.shallowCopy
|
||||
for i in 1 ..< originalParams.len:
|
||||
let resulti = originalParams[i].sym.typ
|
||||
for i, resulti in paramTypes(result):
|
||||
# twrong_field_caching requires these 'resetIdTable' calls:
|
||||
if i > FirstParamAt:
|
||||
resetIdTable(cl.symMap)
|
||||
@@ -259,24 +257,24 @@ proc instantiateProcType(c: PContext, pt: LayeredIdTable,
|
||||
let needsStaticSkipping = resulti.kind == tyFromExpr
|
||||
let needsTypeDescSkipping = resulti.kind == tyTypeDesc and tfUnresolved in resulti.flags
|
||||
if resulti.kind == tyFromExpr:
|
||||
resulti.incl tfNonConstExpr
|
||||
var paramType = replaceTypeVarsT(cl, resulti)
|
||||
resulti.flags.incl tfNonConstExpr
|
||||
result[i] = replaceTypeVarsT(cl, resulti)
|
||||
if needsStaticSkipping:
|
||||
paramType = paramType.skipTypes({tyStatic})
|
||||
result[i] = result[i].skipTypes({tyStatic})
|
||||
if needsTypeDescSkipping:
|
||||
paramType = paramType.skipTypes({tyTypeDesc})
|
||||
typeToFit = paramType
|
||||
result[i] = result[i].skipTypes({tyTypeDesc})
|
||||
typeToFit = result[i]
|
||||
|
||||
# ...otherwise, we use the instantiated type in `fitNode`
|
||||
if (typeToFit.kind != tyTypeDesc or typeToFit.base.kind != tyNone) and
|
||||
(typeToFit.kind != tyStatic):
|
||||
typeToFit = paramType
|
||||
typeToFit = result[i]
|
||||
|
||||
internalAssert c.config, originalParams[i].kind == nkSym
|
||||
let oldParam = originalParams[i].sym
|
||||
let param = copySym(oldParam, c.idgen)
|
||||
setOwner(param, prc)
|
||||
param.typ = paramType
|
||||
param.typ = result[i]
|
||||
|
||||
# The default value is instantiated and fitted against the final
|
||||
# concrete param type. We avoid calling `replaceTypeVarsN` on the
|
||||
@@ -284,7 +282,7 @@ proc instantiateProcType(c: PContext, pt: LayeredIdTable,
|
||||
if oldParam.ast != nil:
|
||||
var def = oldParam.ast.copyTree
|
||||
if def.typ.kind == tyFromExpr:
|
||||
def.typ.incl tfNonConstExpr
|
||||
def.typ.flags.incl tfNonConstExpr
|
||||
if not isIntLit(def.typ):
|
||||
def = prepareNode(cl, def)
|
||||
|
||||
@@ -304,15 +302,15 @@ proc instantiateProcType(c: PContext, pt: LayeredIdTable,
|
||||
# the only way the default value might be inserted).
|
||||
param.ast = errorNode(c, def)
|
||||
# we know the node is empty, we need the actual type for error message
|
||||
param.ast.typ = def.typ
|
||||
param.ast.typ() = def.typ
|
||||
else:
|
||||
param.ast = fitNodePostMatch(c, typeToFit, converted)
|
||||
param.typ = paramType
|
||||
param.typ = result[i]
|
||||
|
||||
result.n[i] = newSymNode(param)
|
||||
if isRecursiveStructuralType(paramType):
|
||||
if isRecursiveStructuralType(result[i]):
|
||||
localError(c.config, originalParams[i].sym.info, "illegal recursion in type '" & typeToString(result[i]) & "'")
|
||||
propagateToOwner(result, paramType)
|
||||
propagateToOwner(result, result[i])
|
||||
addDecl(c, param)
|
||||
|
||||
resetIdTable(cl.symMap)
|
||||
@@ -339,7 +337,7 @@ proc instantiateOnlyProcType(c: PContext, pt: LayeredIdTable, prc: PSym, info: T
|
||||
# examples are in texplicitgenerics
|
||||
# might be buggy, see rest of generateInstance if problems occur
|
||||
let fakeSym = copySym(prc, c.idgen)
|
||||
incl(fakeSym.flagsImpl, sfFromGeneric)
|
||||
incl(fakeSym.flags, sfFromGeneric)
|
||||
fakeSym.instantiatedFrom = prc
|
||||
openScope(c)
|
||||
for s in instantiateGenericParamList(c, prc.ast[genericParamsPos], pt):
|
||||
@@ -395,7 +393,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: LayeredIdTable,
|
||||
let oldScope = c.currentScope
|
||||
while not isTopLevel(c): c.currentScope = c.currentScope.parent
|
||||
result = copySym(fn, c.idgen)
|
||||
incl(result, sfFromGeneric)
|
||||
incl(result.flags, sfFromGeneric)
|
||||
result.instantiatedFrom = fn
|
||||
if sfGlobal in result.flags and c.config.symbolFiles != disabledSf:
|
||||
let passc = getLocalPassC(c, producer)
|
||||
@@ -431,7 +429,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: LayeredIdTable,
|
||||
addDecl(c, s)
|
||||
entry.concreteTypes[i] = s.typ
|
||||
inc i
|
||||
entry.genericParamsCount = i
|
||||
c.matchedConcept = nil
|
||||
pushProcCon(c, result)
|
||||
instantiateProcType(c, pt, result, info)
|
||||
@@ -440,7 +437,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: LayeredIdTable,
|
||||
inc i
|
||||
#echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " ", entry.concreteTypes.len
|
||||
if tfTriggersCompileTime in result.typ.flags:
|
||||
incl(result, sfCompileTime)
|
||||
incl(result.flags, sfCompileTime)
|
||||
n[genericParamsPos] = c.graph.emptyNode
|
||||
var oldPrc = genericCacheGet(c.graph, fn, entry[], c.compilesContextId)
|
||||
if oldPrc == nil:
|
||||
@@ -452,10 +449,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: LayeredIdTable,
|
||||
entry.compilesId = c.compilesContextId
|
||||
addToGenericProcCache(c, fn, entry)
|
||||
c.generics.add(makeInstPair(fn, entry))
|
||||
# Log the generic instance so it gets written to the NIF file.
|
||||
# This is needed for cyclic module dependencies where generic instances
|
||||
# may be created in one module but referenced from another.
|
||||
logGenericInstance(c.graph, result)
|
||||
# bug #12985 bug #22913
|
||||
# TODO: use the context of the declaration of generic functions instead
|
||||
# TODO: consider fixing options as well
|
||||
|
||||
@@ -93,8 +93,8 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef; producedClosure: var boo
|
||||
case n.kind
|
||||
of nkObjConstr:
|
||||
let x = t.skipTypes(abstractPtrs)
|
||||
n.typ = t
|
||||
n[0].typ = t
|
||||
n.typ() = t
|
||||
n[0].typ() = t
|
||||
for i in 1..<n.len:
|
||||
var tracker = FieldTracker(index: i-1, remaining: i-1, constr: n, delete: false)
|
||||
let field = x.ithField(tracker)
|
||||
@@ -108,12 +108,12 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef; producedClosure: var boo
|
||||
incl(n[i].flags, nfPreventCg)
|
||||
of nkPar, nkTupleConstr:
|
||||
if x.kind == tyTuple:
|
||||
n.typ = t
|
||||
n.typ() = t
|
||||
for i in 0..<n.len:
|
||||
if i >= x.kidsLen: globalError conf, n.info, "invalid field at index " & $i
|
||||
else: annotateType(n[i], x[i], conf, producedClosure)
|
||||
elif x.kind == tyProc and x.callConv == ccClosure:
|
||||
n.typ = t
|
||||
n.typ() = t
|
||||
if n.len > 1 and n[1].kind notin {nkEmpty, nkNilLit}:
|
||||
producedClosure = true
|
||||
elif x.kind == tyOpenArray: # `opcSlice` transforms slices into tuples
|
||||
@@ -136,18 +136,18 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef; producedClosure: var boo
|
||||
globalError(conf, n.info, "Incorrectly generated tuple constr")
|
||||
n[] = bracketExpr[]
|
||||
|
||||
n.typ = t
|
||||
n.typ() = t
|
||||
else:
|
||||
globalError(conf, n.info, "() must have a tuple type")
|
||||
of nkBracket:
|
||||
if x.kind in {tyArray, tySequence, tyOpenArray}:
|
||||
n.typ = t
|
||||
n.typ() = t
|
||||
for m in n: annotateType(m, x.elemType, conf, producedClosure)
|
||||
else:
|
||||
globalError(conf, n.info, "[] must have some form of array type")
|
||||
of nkCurly:
|
||||
if x.kind in {tySet}:
|
||||
n.typ = t
|
||||
n.typ() = t
|
||||
for m in n:
|
||||
if m.kind == nkRange:
|
||||
annotateType(m[0], x.elemType, conf, producedClosure)
|
||||
@@ -158,22 +158,22 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef; producedClosure: var boo
|
||||
globalError(conf, n.info, "{} must have the set type")
|
||||
of nkFloatLit..nkFloat128Lit:
|
||||
if x.kind in {tyFloat..tyFloat128}:
|
||||
n.typ = t
|
||||
n.typ() = t
|
||||
else:
|
||||
globalError(conf, n.info, "float literal must have some float type")
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}:
|
||||
n.typ = t
|
||||
n.typ() = t
|
||||
else:
|
||||
globalError(conf, n.info, "integer literal must have some int type")
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if x.kind in {tyString, tyCstring}:
|
||||
n.typ = t
|
||||
n.typ() = t
|
||||
else:
|
||||
globalError(conf, n.info, "string literal must be of some string type")
|
||||
of nkNilLit:
|
||||
if x.kind in NilableTypes+{tyString, tySequence}:
|
||||
n.typ = t
|
||||
n.typ() = t
|
||||
else:
|
||||
globalError(conf, n.info, "nil literal must be of some pointer type")
|
||||
else: discard
|
||||
|
||||
@@ -18,7 +18,7 @@ proc addDefaultFieldForNew(c: PContext, n: PNode): PNode =
|
||||
let typ = result[1].typ # new(x)
|
||||
if typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyRef and typ.skipTypes({tyGenericInst, tyAlias, tySink})[0].kind == tyObject:
|
||||
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[1].info, typ))
|
||||
asgnExpr.typ = typ
|
||||
asgnExpr.typ() = typ
|
||||
var t = typ.skipTypes({tyGenericInst, tyAlias, tySink})[0]
|
||||
while true:
|
||||
asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n, false)
|
||||
@@ -34,13 +34,11 @@ proc semAddr(c: PContext; n: PNode): PNode =
|
||||
result = newNodeI(nkAddr, n.info)
|
||||
let x = semExprWithType(c, n)
|
||||
if x.kind == nkSym:
|
||||
x.sym.flagsImpl.incl(sfAddrTaken)
|
||||
let aa = isAssignable(c, x)
|
||||
if aa notin {arLValue, arLocalLValue, arAddressableConst, arLentValue} and
|
||||
(aa != arDiscriminant or c.inUncheckedAssignSection <= 0):
|
||||
x.sym.flags.incl(sfAddrTaken)
|
||||
if isAssignable(c, x) notin {arLValue, arLocalLValue, arAddressableConst, arLentValue}:
|
||||
localError(c.config, n.info, errExprHasNoAddress)
|
||||
result.add x
|
||||
result.typ = makePtrType(c, x.typ.skipTypes({tySink}))
|
||||
result.typ() = makePtrType(c, x.typ.skipTypes({tySink}))
|
||||
|
||||
proc semTypeOf(c: PContext; n: PNode): PNode =
|
||||
var m = BiggestInt 1 # typeOfIter
|
||||
@@ -56,16 +54,16 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
|
||||
let typExpr = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
|
||||
result.add typExpr
|
||||
if typExpr.typ.kind == tyFromExpr:
|
||||
typExpr.typ.incl tfNonConstExpr
|
||||
typExpr.typ.flags.incl tfNonConstExpr
|
||||
var t = typExpr.typ
|
||||
if t.kind == tyStatic:
|
||||
let base = t.skipTypes({tyStatic})
|
||||
if c.inGenericContext > 0 and base.containsGenericType:
|
||||
t = makeTypeFromExpr(c, copyTree(typExpr))
|
||||
t.incl tfNonConstExpr
|
||||
t.flags.incl tfNonConstExpr
|
||||
else:
|
||||
t = base
|
||||
result.typ = makeTypeDesc(c, t)
|
||||
result.typ() = makeTypeDesc(c, t)
|
||||
|
||||
type
|
||||
SemAsgnMode = enum asgnNormal, noOverloadedSubscript, noOverloadedAsgn
|
||||
@@ -86,8 +84,8 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
|
||||
if a.typ != nil and a.typ.kind in {tyGenericParam, tyFromExpr}:
|
||||
# expression is compiled early in a generic body
|
||||
result = semGenericStmt(c, x)
|
||||
result.typ = makeTypeFromExpr(c, copyTree(result))
|
||||
result.typ.incl tfNonConstExpr
|
||||
result.typ() = makeTypeFromExpr(c, copyTree(result))
|
||||
result.typ.flags.incl tfNonConstExpr
|
||||
return
|
||||
let s = # extract sym from first arg
|
||||
if n.len > 1:
|
||||
@@ -210,15 +208,15 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
|
||||
let preferStr = traitCall[2].strVal
|
||||
prefer = parseEnum[TPreferedDesc](preferStr)
|
||||
result = newStrNode(nkStrLit, operand.typeToString(prefer))
|
||||
result.typ = getSysType(c.graph, traitCall[1].info, tyString)
|
||||
result.typ() = getSysType(c.graph, traitCall[1].info, tyString)
|
||||
result.info = traitCall.info
|
||||
of "name", "$":
|
||||
result = newStrNode(nkStrLit, operand.typeToString(preferTypeName))
|
||||
result.typ = getSysType(c.graph, traitCall[1].info, tyString)
|
||||
result.typ() = getSysType(c.graph, traitCall[1].info, tyString)
|
||||
result.info = traitCall.info
|
||||
of "arity":
|
||||
result = newIntNode(nkIntLit, operand.len - ord(operand.kind==tyProc))
|
||||
result.typ = newType(tyInt, c.idgen, context)
|
||||
result.typ() = newType(tyInt, c.idgen, context)
|
||||
result.info = traitCall.info
|
||||
of "genericHead":
|
||||
var arg = operand
|
||||
@@ -234,9 +232,10 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
|
||||
of "stripGenericParams":
|
||||
result = uninstantiate(operand).toNode(traitCall.info)
|
||||
of "supportsCopyMem":
|
||||
result = newIntNodeT(toInt128(ord(supportsCopyMem(operand))), traitCall, c.idgen, c.graph)
|
||||
of "canFormCycles":
|
||||
result = newIntNodeT(toInt128(ord(types.canFormAcycle(c.graph, operand))), traitCall, c.idgen, c.graph)
|
||||
let t = operand.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink, tyInferred})
|
||||
let complexObj = containsGarbageCollectedRef(t) or
|
||||
hasDestructor(t)
|
||||
result = newIntNodeT(toInt128(ord(not complexObj)), traitCall, c.idgen, c.graph)
|
||||
of "hasDefaultValue":
|
||||
result = newIntNodeT(toInt128(ord(not operand.requiresInit)), traitCall, c.idgen, c.graph)
|
||||
of "isNamedTuple":
|
||||
@@ -248,13 +247,10 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
|
||||
assert operand.kind == tyTuple, $operand.kind
|
||||
result = newIntNodeT(toInt128(operand.len), traitCall, c.idgen, c.graph)
|
||||
of "distinctBase":
|
||||
var arg = operand.skipTypes(skippedTypes)
|
||||
var arg = operand.skipTypes({tyGenericInst})
|
||||
let rec = semConstExpr(c, traitCall[2]).intVal != 0
|
||||
while true:
|
||||
let distinctArg = arg.skipTypes(skippedTypes + {tyGenericInst})
|
||||
if distinctArg.kind != tyDistinct:
|
||||
break
|
||||
arg = distinctArg.base.skipTypes(skippedTypes)
|
||||
while arg.kind == tyDistinct:
|
||||
arg = arg.base.skipTypes(skippedTypes + {tyGenericInst})
|
||||
if not rec: break
|
||||
result = getTypeDescNode(c, arg, operand.owner, traitCall.info)
|
||||
of "rangeBase":
|
||||
@@ -290,7 +286,7 @@ proc semOrd(c: PContext, n: PNode): PNode =
|
||||
discard
|
||||
else:
|
||||
localError(c.config, n.info, errOrdinalTypeExpected % typeToString(parType, preferDesc))
|
||||
result.typ = errorType(c)
|
||||
result.typ() = errorType(c)
|
||||
|
||||
proc semBindSym(c: PContext, n: PNode): PNode =
|
||||
result = copyNode(n)
|
||||
@@ -406,7 +402,7 @@ proc semOf(c: PContext, n: PNode): PNode =
|
||||
message(c.config, n.info, hintConditionAlwaysTrue, renderTree(n))
|
||||
result = newIntNode(nkIntLit, 1)
|
||||
result.info = n.info
|
||||
result.typ = getSysType(c.graph, n.info, tyBool)
|
||||
result.typ() = getSysType(c.graph, n.info, tyBool)
|
||||
return result
|
||||
elif diff == high(int):
|
||||
if commonSuperclass(a, b) == nil:
|
||||
@@ -415,10 +411,10 @@ proc semOf(c: PContext, n: PNode): PNode =
|
||||
message(c.config, n.info, hintConditionAlwaysFalse, renderTree(n))
|
||||
result = newIntNode(nkIntLit, 0)
|
||||
result.info = n.info
|
||||
result.typ = getSysType(c.graph, n.info, tyBool)
|
||||
result.typ() = getSysType(c.graph, n.info, tyBool)
|
||||
else:
|
||||
localError(c.config, n.info, "'of' takes 2 arguments")
|
||||
n.typ = getSysType(c.graph, n.info, tyBool)
|
||||
n.typ() = getSysType(c.graph, n.info, tyBool)
|
||||
result = n
|
||||
|
||||
proc semUnown(c: PContext; n: PNode): PNode =
|
||||
@@ -446,16 +442,16 @@ proc semUnown(c: PContext; n: PNode): PNode =
|
||||
copyTypeProps(c.graph, c.idgen.module, result, t)
|
||||
|
||||
result[^1] = b
|
||||
result.excl tfHasOwned
|
||||
result.flags.excl tfHasOwned
|
||||
else:
|
||||
result = t
|
||||
else:
|
||||
result = t
|
||||
|
||||
result = copyTree(n[1])
|
||||
result.typ = unownedType(c, result.typ)
|
||||
result.typ() = unownedType(c, result.typ)
|
||||
# little hack for injectdestructors.nim (see bug #11350):
|
||||
#result[0].typ = nil
|
||||
#result[0].typ() = nil
|
||||
|
||||
proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym =
|
||||
# We need to do 2 things: Replace n.typ which is a 'ref T' by a 'var T' type.
|
||||
@@ -465,7 +461,7 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym
|
||||
proc transform(c: PContext; n: PNode; old, fresh: PType; oldParam, newParam: PSym): PNode =
|
||||
result = shallowCopy(n)
|
||||
if sameTypeOrNil(n.typ, old):
|
||||
result.typ = fresh
|
||||
result.typ() = fresh
|
||||
if n.kind == nkSym and n.sym == oldParam:
|
||||
result.sym = newParam
|
||||
for i in 0 ..< safeLen(n):
|
||||
@@ -475,7 +471,7 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym
|
||||
|
||||
result = copySym(orig, c.idgen)
|
||||
result.info = info
|
||||
result.incl sfFromGeneric
|
||||
result.flags.incl sfFromGeneric
|
||||
setOwner(result, orig)
|
||||
let origParamType = orig.typ.firstParamType
|
||||
let newParamType = makeVarType(result, origParamType.skipTypes(abstractPtrs), c.idgen)
|
||||
@@ -554,8 +550,8 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
|
||||
else:
|
||||
let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), c.idgen, fin.owner, fin.info)
|
||||
let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, c.idgen))
|
||||
selfSymNode.typ = fin.typ.firstParamType
|
||||
wrapperSym.flagsImpl.incl sfUsed
|
||||
selfSymNode.typ() = fin.typ.firstParamType
|
||||
wrapperSym.flags.incl sfUsed
|
||||
|
||||
let wrapper = c.semExpr(c, newProcNode(nkProcDef, fin.info, body = newTree(nkCall, newSymNode(fin), selfSymNode),
|
||||
params = nkFormalParams.newTree(c.graph.emptyNode,
|
||||
@@ -572,7 +568,7 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
|
||||
let selfSymbolType = makePtrType(c, origParamType.skipTypes(abstractPtrs))
|
||||
let selfPtr = newNodeI(nkHiddenAddr, transFormedSym.ast[bodyPos][1].info)
|
||||
selfPtr.add transFormedSym.ast[bodyPos][1]
|
||||
selfPtr.typ = selfSymbolType
|
||||
selfPtr.typ() = selfSymbolType
|
||||
transFormedSym.ast[bodyPos][1] = c.semExpr(c, selfPtr)
|
||||
bindTypeHook(c, transFormedSym, n, attachedDestructor)
|
||||
result = addDefaultFieldForNew(c, n)
|
||||
@@ -618,16 +614,16 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
of mAsgn:
|
||||
case n[0].sym.name.s
|
||||
of "=", "=copy":
|
||||
result = replaceHookMagic(c, n, attachedAsgn)
|
||||
result = semAsgnOpr(c, n, nkAsgn)
|
||||
of "=sink":
|
||||
result = replaceHookMagic(c, n, attachedSink)
|
||||
result = semAsgnOpr(c, n, nkSinkAsgn)
|
||||
else:
|
||||
result = semShallowCopy(c, n, flags)
|
||||
of mIsPartOf: result = semIsPartOf(c, n, flags)
|
||||
of mTypeTrait: result = semTypeTraits(c, n)
|
||||
of mAstToStr:
|
||||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph)
|
||||
result.typ = getSysType(c.graph, n.info, tyString)
|
||||
result.typ() = getSysType(c.graph, n.info, tyString)
|
||||
of mInstantiationInfo: result = semInstantiationInfo(c, n)
|
||||
of mOrd: result = semOrd(c, n)
|
||||
of mOf: result = semOf(c, n)
|
||||
@@ -640,7 +636,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
result = semDynamicBindSym(c, n)
|
||||
of mProcCall:
|
||||
result = n
|
||||
result.typ = n[1].typ
|
||||
result.typ() = n[1].typ
|
||||
of mDotDot:
|
||||
result = n
|
||||
of mPlugin:
|
||||
@@ -696,7 +692,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
result = n
|
||||
if result.typ != nil and expectedType != nil and result.typ.kind == tySequence and
|
||||
expectedType.kind == tySequence and result.typ.elementType.kind == tyEmpty:
|
||||
result.typ = expectedType # type inference for empty sequence # bug #21377
|
||||
result.typ() = expectedType # type inference for empty sequence # bug #21377
|
||||
of mEnsureMove:
|
||||
result = n
|
||||
if n[1].kind in {nkStmtListExpr, nkBlockExpr,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user