mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-01 03:13:41 +00:00
Compare commits
798 Commits
pr_move_sy
...
pr_no_forw
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52bf954ba5 | ||
|
|
a4781dc4bc | ||
|
|
c0ecdb01a9 | ||
|
|
93407096db | ||
|
|
d77ada5bdf | ||
|
|
6eb722c47d | ||
|
|
c44c8ddb44 | ||
|
|
20cbdc2741 | ||
|
|
eb83d20d0d | ||
|
|
7fababd583 | ||
|
|
98c39e8e57 | ||
|
|
fede757238 | ||
|
|
019b488e1f | ||
|
|
2e3d9cdbee | ||
|
|
ee817557ec | ||
|
|
60307cc373 | ||
|
|
299394d21a | ||
|
|
940b1607b8 | ||
|
|
ade75a1483 | ||
|
|
6c4e7835bf | ||
|
|
9296b45de4 | ||
|
|
a660c17d30 | ||
|
|
1927ae72d0 | ||
|
|
09d0fda7fd | ||
|
|
7bb2462d06 | ||
|
|
9bf605cf98 | ||
|
|
9207d77848 | ||
|
|
4c89223171 | ||
|
|
f642c9dbf1 | ||
|
|
23f3f9ae2c | ||
|
|
3f7e1d7daa | ||
|
|
48da472dd2 | ||
|
|
469c9cfab4 | ||
|
|
72bc72bf9e | ||
|
|
277393d0f1 | ||
|
|
3bb75f2dea | ||
|
|
9fed58d5a0 | ||
|
|
0bf286583a | ||
|
|
faf1c91e6a | ||
|
|
7be2e2bef5 | ||
|
|
8523b543d6 | ||
|
|
8625e71250 | ||
|
|
05f7c4f79d | ||
|
|
2aab03bdfb | ||
|
|
a6610745d8 | ||
|
|
baf350493b | ||
|
|
fa58d23080 | ||
|
|
6ec1c80779 | ||
|
|
91c3221855 | ||
|
|
46e94c83d4 | ||
|
|
5ec81d076b | ||
|
|
d53a89e453 | ||
|
|
5334dc921f | ||
|
|
989da75b84 | ||
|
|
c622e58db9 | ||
|
|
28b2e429ef | ||
|
|
ce079a8da4 | ||
|
|
3aaef9e4cf | ||
|
|
d136af0122 | ||
|
|
73e661d01b | ||
|
|
10a6e4c236 | ||
|
|
bf5d173bc6 | ||
|
|
4c6be40b34 | ||
|
|
37d8f32ae9 | ||
|
|
47d06d3d4c | ||
|
|
0219c5a607 | ||
|
|
b4b555d8d1 | ||
|
|
260b4236fc | ||
|
|
b5b4b48c94 | ||
|
|
fe9ae2c69a | ||
|
|
614a18cd05 | ||
|
|
26eb0a944f | ||
|
|
e7b4c7cddb | ||
|
|
93ced31353 | ||
|
|
53586d1f32 | ||
|
|
67122a9cb6 | ||
|
|
d2b197bdcd | ||
|
|
f18e4c4050 | ||
|
|
95c751a9e4 | ||
|
|
137d608d7d | ||
|
|
b2c3b8f931 | ||
|
|
7bf7496557 | ||
|
|
e0396900ed | ||
|
|
9872453365 | ||
|
|
e15e19308e | ||
|
|
873eaa3f65 | ||
|
|
db435a4a79 | ||
|
|
73a29d72e3 | ||
|
|
26f183043f | ||
|
|
3efabd3ec6 | ||
|
|
7c2a2c8dc8 | ||
|
|
fb7acd6600 | ||
|
|
d37b620757 | ||
|
|
14bc3f3268 | ||
|
|
8d8d75706c | ||
|
|
6b913b4741 | ||
|
|
b40da812f7 | ||
|
|
825a0e7df4 | ||
|
|
f3a7622514 | ||
|
|
da368885da | ||
|
|
1d2c27d2e6 | ||
|
|
a23e53b490 | ||
|
|
35ff70f36c | ||
|
|
0b3ddd4e47 | ||
|
|
b56df5c07f | ||
|
|
569ccc50ff | ||
|
|
d51bc084fd | ||
|
|
281016a802 | ||
|
|
19d1fe7af3 | ||
|
|
e70992d291 | ||
|
|
f0f3904ff0 | ||
|
|
f1ac979184 | ||
|
|
db77c98471 | ||
|
|
11c8dfc9b3 | ||
|
|
c0994c2dbd | ||
|
|
1c2ccfad08 | ||
|
|
dce714b259 | ||
|
|
8216d7dd46 | ||
|
|
49a108b302 | ||
|
|
808c9c6c2a | ||
|
|
be1844541c | ||
|
|
62869a5c68 | ||
|
|
b10d3cd98d | ||
|
|
e2ea9140ac | ||
|
|
0e555ade31 | ||
|
|
576f4a7348 | ||
|
|
3ebe24977c | ||
|
|
b02c1dd6ca | ||
|
|
993fcf5bda | ||
|
|
91987f8eb5 | ||
|
|
2f817ee5b4 | ||
|
|
3f9e16594f | ||
|
|
c1a82aa5c5 | ||
|
|
5ed44e1ec4 | ||
|
|
0d3bde95f5 | ||
|
|
7d9fe106ec | ||
|
|
1aff402998 | ||
|
|
14a9929464 | ||
|
|
f16b94a9d7 | ||
|
|
17915d93bf | ||
|
|
50d435cd39 | ||
|
|
f9280090f6 | ||
|
|
db1ce4ff12 | ||
|
|
3b377937de | ||
|
|
9471b5f964 | ||
|
|
9ddd768cce | ||
|
|
ecc6ab7ee0 | ||
|
|
1b132ddaa2 | ||
|
|
6ec10a4c91 | ||
|
|
54d7c9fdf8 | ||
|
|
2e987cb75a | ||
|
|
148ff74c93 | ||
|
|
a15db5d60b | ||
|
|
dfa0d2569e | ||
|
|
7616e6ee2b | ||
|
|
145e002c74 | ||
|
|
86ff37fab8 | ||
|
|
31ba1046fc | ||
|
|
c513e37a70 | ||
|
|
d9a24b9b81 | ||
|
|
1ad618d96c | ||
|
|
57296a5139 | ||
|
|
83a5865024 | ||
|
|
aedb4c26de | ||
|
|
7cb59efd4b | ||
|
|
2f109595e9 | ||
|
|
4d2ebbb877 | ||
|
|
3a1adf7d66 | ||
|
|
210b10dd0d | ||
|
|
41ec894cb0 | ||
|
|
d139d99946 | ||
|
|
57de460437 | ||
|
|
b35942ef83 | ||
|
|
d195877615 | ||
|
|
427ad17161 | ||
|
|
9616762cfe | ||
|
|
ce0909f047 | ||
|
|
faa59b1e1f | ||
|
|
e422b3c860 | ||
|
|
d52b1d848e | ||
|
|
47635d3031 | ||
|
|
cb40f11e6c | ||
|
|
4b761295e7 | ||
|
|
4ce3a68e79 | ||
|
|
4546f5dfe5 | ||
|
|
43a3de9077 | ||
|
|
3e44d5742f | ||
|
|
942c378659 | ||
|
|
20037a4749 | ||
|
|
f718f295df | ||
|
|
c6c85f84db | ||
|
|
beaac609ab | ||
|
|
88114948c4 | ||
|
|
d137a3b52a | ||
|
|
ac7b8b678c | ||
|
|
eb2f0353bc | ||
|
|
3ad2e7df1c | ||
|
|
ede03782a3 | ||
|
|
5e529b3bfa | ||
|
|
a345cde26e | ||
|
|
db41f04ab0 | ||
|
|
f524d60fa1 | ||
|
|
29a43124cf | ||
|
|
2054f1c3a9 | ||
|
|
2bb7277a61 | ||
|
|
6d21637245 | ||
|
|
647d9611ae | ||
|
|
e8d0f1c3ae | ||
|
|
0de9e6bbf3 | ||
|
|
8c3b0e9b48 | ||
|
|
7ea8f1d5dd | ||
|
|
88388040db | ||
|
|
77beb15214 | ||
|
|
0750210a50 | ||
|
|
3ac2d81601 | ||
|
|
b4d9be0f8a | ||
|
|
0a19d78b22 | ||
|
|
4937aa952b | ||
|
|
edb64bcff4 | ||
|
|
d90581c677 | ||
|
|
13b7e4e0e5 | ||
|
|
44f377edaf | ||
|
|
20dfdba2df | ||
|
|
894a19c6ed | ||
|
|
606e9941d0 | ||
|
|
cca5e5ffb9 | ||
|
|
fda8b6f193 | ||
|
|
2e12d3e26b | ||
|
|
5679f2b84c | ||
|
|
db8f6f4e38 | ||
|
|
93cace160e | ||
|
|
71801c2b8f | ||
|
|
e0ad71a912 | ||
|
|
7b1c448744 | ||
|
|
5139a2ec37 | ||
|
|
9b5f310b9e | ||
|
|
21d941c16a | ||
|
|
8bba04078c | ||
|
|
d3af0882cf | ||
|
|
b2d7761975 | ||
|
|
65c412e3f0 | ||
|
|
744a99d75c | ||
|
|
1d6fd30afb | ||
|
|
64b27edd3a | ||
|
|
49e11d9dcc | ||
|
|
18462b1026 | ||
|
|
f09101416f | ||
|
|
a7682325a2 | ||
|
|
a3bbb71240 | ||
|
|
a4f9413a65 | ||
|
|
a8d0dda833 | ||
|
|
750a33cbf1 | ||
|
|
64accd1c57 | ||
|
|
6514eaa8e0 | ||
|
|
7ee00d86b1 | ||
|
|
ba4fb21032 | ||
|
|
ea91cfb305 | ||
|
|
d29237b3c7 | ||
|
|
7fad6e5c70 | ||
|
|
47fa7506ab | ||
|
|
ebecfbc7a5 | ||
|
|
ce72b564bc | ||
|
|
fcc383d899 | ||
|
|
9f3d1b1290 | ||
|
|
ccc706ff12 | ||
|
|
1dedad5620 | ||
|
|
80fc749835 | ||
|
|
134b1890d5 | ||
|
|
0f3d6b5a52 | ||
|
|
7ca55f7de6 | ||
|
|
b97d603cd0 | ||
|
|
2ab948ce53 | ||
|
|
0a212f97a5 | ||
|
|
c7c3362cc8 | ||
|
|
1edae67efd | ||
|
|
211ef26f29 | ||
|
|
85d8ee2cee | ||
|
|
767fec1640 | ||
|
|
a1b7d2278a | ||
|
|
0d4d70f15c | ||
|
|
929cb4d601 | ||
|
|
25fe4124e6 | ||
|
|
f552618d6b | ||
|
|
3d18b204dd | ||
|
|
b86060b2ba | ||
|
|
8cc49f221e | ||
|
|
6dd30a6d86 | ||
|
|
1133f20fe2 | ||
|
|
ead7e20926 | ||
|
|
c507ced51e | ||
|
|
8e35b3d577 | ||
|
|
b3e1892eb7 | ||
|
|
8f760080c5 | ||
|
|
b880cdff49 | ||
|
|
0e5c18a73a | ||
|
|
086a3e42eb | ||
|
|
bf9ee00998 | ||
|
|
e43a51fcf3 | ||
|
|
20446b437b | ||
|
|
a9385a6b4a | ||
|
|
4d20227438 | ||
|
|
546af8c571 | ||
|
|
40f88da90b | ||
|
|
7e055413f9 | ||
|
|
171b916613 | ||
|
|
244565397d | ||
|
|
ef060e8184 | ||
|
|
108410ac34 | ||
|
|
f47b27d532 | ||
|
|
8c55e2999b | ||
|
|
7ebb042f79 | ||
|
|
5997324709 | ||
|
|
9cb0fcf319 | ||
|
|
c2abcb06cc | ||
|
|
2900987c2f | ||
|
|
b96c501836 | ||
|
|
d5ba14db61 | ||
|
|
2dcc7195da | ||
|
|
ef3c0bec1c | ||
|
|
af3fd5a010 | ||
|
|
73095e2abb | ||
|
|
6048367a9f | ||
|
|
b0e1bc02c6 | ||
|
|
38fdf13982 | ||
|
|
6128ef53c5 | ||
|
|
09f36f5198 | ||
|
|
2beea72810 | ||
|
|
1aaff9dc48 | ||
|
|
656706026b | ||
|
|
f2d26f2973 | ||
|
|
b50babd0ae | ||
|
|
ab4d044a81 | ||
|
|
908e971732 | ||
|
|
609bf3d7c8 | ||
|
|
0eb508e434 | ||
|
|
a8718d8a9e | ||
|
|
b7925bf5c9 | ||
|
|
446e5fbbb3 | ||
|
|
cb3f6fdc66 | ||
|
|
4d6be458a0 | ||
|
|
c7f2541914 | ||
|
|
b63b5c930e | ||
|
|
266cc69f19 | ||
|
|
761b927e47 | ||
|
|
9493e67291 | ||
|
|
bdccc9fef9 | ||
|
|
1252070193 | ||
|
|
d372ad3ee6 | ||
|
|
76a98fee65 | ||
|
|
d696ef5ad7 | ||
|
|
ee3650b29e | ||
|
|
b14043c39e | ||
|
|
9c2d2773ec | ||
|
|
28a116a477 | ||
|
|
5606702e6d | ||
|
|
44f059c75e | ||
|
|
016aa1d98c | ||
|
|
fcf2dcf099 | ||
|
|
641e34bcb2 | ||
|
|
a852b2e9cf | ||
|
|
476e032004 | ||
|
|
4186529ff7 | ||
|
|
21ff10b882 | ||
|
|
02a10ec379 | ||
|
|
1314ea7516 | ||
|
|
f22e5067c5 | ||
|
|
eecf12c4b5 | ||
|
|
ce1ba91573 | ||
|
|
cf1ab2a30b | ||
|
|
f4a9b258c3 | ||
|
|
0ece98620f | ||
|
|
ddce555998 | ||
|
|
871e4af6ef | ||
|
|
9c40dd2406 | ||
|
|
161f50643a | ||
|
|
c6e2dc1919 | ||
|
|
ea39c600ab | ||
|
|
9810b8cf7f | ||
|
|
ebbad9e960 | ||
|
|
c004483581 | ||
|
|
f7ed293fbd | ||
|
|
802d57c237 | ||
|
|
3b9999b93c | ||
|
|
fa5e7dc44a | ||
|
|
71dc929ad7 | ||
|
|
02be212dae | ||
|
|
3a08e2e6ac | ||
|
|
055a00a6ef | ||
|
|
71439c2891 | ||
|
|
f3a4cc584e | ||
|
|
deaf684375 | ||
|
|
4b76037e5f | ||
|
|
5592d1ef2c | ||
|
|
b169dad1e5 | ||
|
|
5491e0c274 | ||
|
|
4ee70165f1 | ||
|
|
ec3bca8fab | ||
|
|
e45eb39ef7 | ||
|
|
4533e894ad | ||
|
|
ebdff1c7d3 | ||
|
|
71f2e1a502 | ||
|
|
4a94f3606e | ||
|
|
8cf5643621 | ||
|
|
b562e1e6d8 | ||
|
|
ba698d37c3 | ||
|
|
d0c62fa169 | ||
|
|
365a753eed | ||
|
|
53c15f24e9 | ||
|
|
b74d49c037 | ||
|
|
10328e50a5 | ||
|
|
85dbfc68b5 | ||
|
|
07233ceca0 | ||
|
|
724866b14f | ||
|
|
e92d7681bb | ||
|
|
62f1ad54ae | ||
|
|
79ac242c72 | ||
|
|
acfa7849d3 | ||
|
|
a929e513fa | ||
|
|
c34950f8f5 | ||
|
|
34b78be396 | ||
|
|
44736d26cd | ||
|
|
f37ecbb994 | ||
|
|
1d80dc7df6 | ||
|
|
a154950570 | ||
|
|
e5d0907a42 | ||
|
|
ca82b4ea16 | ||
|
|
c2bcfd8cd9 | ||
|
|
afc30ca879 | ||
|
|
2844ac8b5e | ||
|
|
3e82a315fc | ||
|
|
aec5a4c474 | ||
|
|
8e0f336f6d | ||
|
|
a593e40ad6 | ||
|
|
77093bf7b9 | ||
|
|
43f29842fc | ||
|
|
91abf35442 | ||
|
|
560fa9a1fe | ||
|
|
220b450489 | ||
|
|
8f79a124c9 | ||
|
|
69c193e5e2 | ||
|
|
0032322ea8 | ||
|
|
f0ae1ed544 | ||
|
|
897dff69dd | ||
|
|
4754c51f1b | ||
|
|
0f226c0e48 | ||
|
|
20b011de19 | ||
|
|
380dafcc32 | ||
|
|
265a340e80 | ||
|
|
6ad246b215 | ||
|
|
63d29ddd69 | ||
|
|
c136ebf1ed | ||
|
|
4fa86422c0 | ||
|
|
48de0d0cf4 | ||
|
|
b54b03d04f | ||
|
|
175a83c2de | ||
|
|
d76458a6cd | ||
|
|
418e54452b | ||
|
|
f9477396a6 | ||
|
|
ed7c6cdc98 | ||
|
|
135b677704 | ||
|
|
9cb06d357e | ||
|
|
0d6b994bee | ||
|
|
d2d849db8e | ||
|
|
24b6378382 | ||
|
|
2f547afb0f | ||
|
|
9dc1f2dd0f | ||
|
|
202b190473 | ||
|
|
b0a98cc01e | ||
|
|
2621f78b68 | ||
|
|
65223e6f59 | ||
|
|
91e4381a20 | ||
|
|
8c4b7129b5 | ||
|
|
1af21c2668 | ||
|
|
938f5c5e99 | ||
|
|
a0da74ed4c | ||
|
|
ea8aafa7c9 | ||
|
|
512517c223 | ||
|
|
1a99bcd6ab | ||
|
|
2a0d8a9a06 | ||
|
|
c694d8e4fd | ||
|
|
16f42084d3 | ||
|
|
3f51b6f73d | ||
|
|
c33ab0ba38 | ||
|
|
1ed54b7718 | ||
|
|
f05387045d | ||
|
|
be06446ffe | ||
|
|
1bb117cd7a | ||
|
|
420b0c14eb | ||
|
|
4c073cffbe | ||
|
|
5e016e4466 | ||
|
|
75205fee93 | ||
|
|
4d683fc689 | ||
|
|
16bc546aea | ||
|
|
686c75cef0 | ||
|
|
a37a83cbff | ||
|
|
814d3e6818 | ||
|
|
4898b054ce | ||
|
|
baa577e9e8 | ||
|
|
c71192043b | ||
|
|
3575f2bf9c | ||
|
|
31d3606fe8 | ||
|
|
6ec9c7f683 | ||
|
|
63b4b3c5b8 | ||
|
|
0c6f14af04 | ||
|
|
a80f1a324f | ||
|
|
1c7fd71720 | ||
|
|
d5719c47dc | ||
|
|
2e4ba4ad93 | ||
|
|
b865f6a5f0 | ||
|
|
72ca444122 | ||
|
|
ecf9efa397 | ||
|
|
51ced0d684 | ||
|
|
c06623bf8c | ||
|
|
2315b01ae6 | ||
|
|
4fc9f0c3a3 | ||
|
|
115cec1745 | ||
|
|
0630c649c6 | ||
|
|
ff5ed1dbb1 | ||
|
|
7d83dfd0d1 | ||
|
|
3936071772 | ||
|
|
55636a2913 | ||
|
|
e8a70ff179 | ||
|
|
d84b02f0e0 | ||
|
|
c814c4d993 | ||
|
|
f7e3af0c2d | ||
|
|
c155e20796 | ||
|
|
274d61865f | ||
|
|
9df8ca0d81 | ||
|
|
da7833c68b | ||
|
|
285ea3c48e | ||
|
|
fb00b482eb | ||
|
|
ba22826e9b | ||
|
|
741fed716e | ||
|
|
ae06c6623d | ||
|
|
0c1d595fae | ||
|
|
cae539996a | ||
|
|
a9d0124b5d | ||
|
|
fd4e3ae3e4 | ||
|
|
b5ee81fd23 | ||
|
|
6552a27ec1 | ||
|
|
c43ac90390 | ||
|
|
26b7a74a45 | ||
|
|
c52e44d845 | ||
|
|
b2c1dcbbc9 | ||
|
|
ffadc75afe | ||
|
|
af086b68f2 | ||
|
|
46d2161c23 | ||
|
|
f2dad94902 | ||
|
|
0319824322 | ||
|
|
72e262666b | ||
|
|
8e9fc5e639 | ||
|
|
2f89f1eb78 | ||
|
|
6ef9430153 | ||
|
|
25eef64fe1 | ||
|
|
64a0355f3f | ||
|
|
2d9af2bd55 | ||
|
|
4d76725299 | ||
|
|
05e8a60bb4 | ||
|
|
7bde421e4d | ||
|
|
04a494f8cf | ||
|
|
d950e5f3a8 | ||
|
|
6994e1b1d7 | ||
|
|
b2c5f8a05f | ||
|
|
2e2affb13c | ||
|
|
d51a392149 | ||
|
|
d4d28f2ffe | ||
|
|
38d299dfc0 | ||
|
|
50baf21eac | ||
|
|
612abda4f4 | ||
|
|
9b5ae2b2eb | ||
|
|
a137e50150 | ||
|
|
9948fed919 | ||
|
|
070938720a | ||
|
|
cf083af262 | ||
|
|
89d8c0b246 | ||
|
|
1b1412f3d1 | ||
|
|
c4dd0c4301 | ||
|
|
39d0a93d0e | ||
|
|
dd629c8f45 | ||
|
|
83e3320725 | ||
|
|
6fea221d65 | ||
|
|
89a60939f8 | ||
|
|
4ae598762e | ||
|
|
425225119a | ||
|
|
b2edfe7a02 | ||
|
|
d4782c9e42 | ||
|
|
7837e57e93 | ||
|
|
bbb6d2c69d | ||
|
|
8a19ac2070 | ||
|
|
7dc80a7fef | ||
|
|
38f876dd48 | ||
|
|
fdd7520257 | ||
|
|
ab1d4a5d58 | ||
|
|
64a788cafb | ||
|
|
a3603c8a6e | ||
|
|
0a45543cc1 | ||
|
|
de65b380ed | ||
|
|
6d423f1856 | ||
|
|
e54d3cc418 | ||
|
|
bdc850916f | ||
|
|
ffd6bc8749 | ||
|
|
f7bd2088aa | ||
|
|
c73c76fdc6 | ||
|
|
c66dc913ce | ||
|
|
e896977bd1 | ||
|
|
6b93db7070 | ||
|
|
13711b101d | ||
|
|
03dd853815 | ||
|
|
3b9e9fd7b2 | ||
|
|
93e4f278a1 | ||
|
|
fc7385bfda | ||
|
|
c91ef1a09f | ||
|
|
e24d0e5faf | ||
|
|
56a4d246a4 | ||
|
|
cac49694c0 | ||
|
|
1d06c2b6cf | ||
|
|
406d302131 | ||
|
|
684c3b3aeb | ||
|
|
6c15958a83 | ||
|
|
642136ec4f | ||
|
|
51f410e1d5 | ||
|
|
be4912681f | ||
|
|
9fb4c2b3c7 | ||
|
|
cbb6001d1e | ||
|
|
9f651f05d5 | ||
|
|
8e53fba083 | ||
|
|
17115cbc73 | ||
|
|
43b1b9d077 | ||
|
|
900fe8f501 | ||
|
|
ff8ab06720 | ||
|
|
cbf3ed9d92 | ||
|
|
b5f64f55d0 | ||
|
|
ebaa07b955 | ||
|
|
4459c272ec | ||
|
|
1431f90d8c | ||
|
|
a7bae919ad | ||
|
|
7031ea65cd | ||
|
|
4647c7b596 | ||
|
|
fc068ee06d | ||
|
|
23bd812b0c | ||
|
|
af0f3639ec | ||
|
|
c4d3d650ba | ||
|
|
d54a7f078d | ||
|
|
5e7f7109e1 | ||
|
|
36e489e69b | ||
|
|
f5ec4fbde3 | ||
|
|
b82b5d44af | ||
|
|
4c74b9b54c | ||
|
|
9afb466d73 | ||
|
|
ac982d8a96 | ||
|
|
7c6dcfd968 | ||
|
|
00ef27f4d1 | ||
|
|
f04f3e8bf7 | ||
|
|
fc5b7a01ec | ||
|
|
fd207827c5 | ||
|
|
fc35f83eee | ||
|
|
c4035d7f7c | ||
|
|
cc08a9015e | ||
|
|
30da566d9d | ||
|
|
71c60bf6f7 | ||
|
|
5f41be3b45 | ||
|
|
1e52423774 | ||
|
|
e4e947232b | ||
|
|
8be46f3d16 | ||
|
|
b68b28fd24 | ||
|
|
a55604a3d8 | ||
|
|
76e4f8afb1 | ||
|
|
24d297b437 | ||
|
|
05c6db6500 | ||
|
|
b34412ff0f | ||
|
|
2620da9bf9 | ||
|
|
b2328b44ba | ||
|
|
81b7f9108f | ||
|
|
3b965f463b | ||
|
|
cf1b16ef8b | ||
|
|
e9ed090c33 | ||
|
|
5b20f0685c | ||
|
|
4032eb4baa | ||
|
|
e5639408d5 | ||
|
|
c598d0b6ec | ||
|
|
ebd1c678be | ||
|
|
705da9d452 | ||
|
|
e602ebeb66 | ||
|
|
761c5a0830 | ||
|
|
646932b3f3 | ||
|
|
4b63ac4b87 | ||
|
|
7a74c2dc3a | ||
|
|
3d5dbf8f96 | ||
|
|
9efa56a8bb | ||
|
|
9e35631191 | ||
|
|
5684093135 | ||
|
|
82d80e6e2c | ||
|
|
f232329bb1 | ||
|
|
9b4516fbcb | ||
|
|
f7c203fb6c | ||
|
|
b08c50bb55 | ||
|
|
9323cb7b2a | ||
|
|
86a6c90c9e | ||
|
|
ac5a36c0a4 | ||
|
|
0ffc322cf6 | ||
|
|
0b319fee3d | ||
|
|
ca9c74391a | ||
|
|
13251c2ac9 | ||
|
|
3bba2b34fd | ||
|
|
18c115c8d0 | ||
|
|
37daed3897 | ||
|
|
314a24472e | ||
|
|
7931bdac95 | ||
|
|
93b59da490 | ||
|
|
70fe360456 | ||
|
|
c5a72ebddd | ||
|
|
613829f7a4 | ||
|
|
d0721eadf8 | ||
|
|
81d8ea95af | ||
|
|
8a77798dac | ||
|
|
0aec095b26 | ||
|
|
40b5c4c4c3 | ||
|
|
886572a516 | ||
|
|
e278a781fc | ||
|
|
70c575095e | ||
|
|
53eed2be45 | ||
|
|
100b304ac2 | ||
|
|
b8d200683a | ||
|
|
ae4645e8df | ||
|
|
d83f66a24d | ||
|
|
7fa983f5e6 | ||
|
|
296e7f598e | ||
|
|
84200f28a1 | ||
|
|
a9bd78d579 | ||
|
|
8a3b76b287 | ||
|
|
644318ad9c | ||
|
|
78b68421da | ||
|
|
d00477dffb | ||
|
|
8054be6e52 | ||
|
|
d88f46df38 | ||
|
|
91ce8c385d | ||
|
|
9a50033d5b | ||
|
|
2564b5c938 | ||
|
|
e4aadcf1c1 | ||
|
|
7ae7832f76 | ||
|
|
1fefb8e92a | ||
|
|
d84f64d2e7 | ||
|
|
b0a850adbf | ||
|
|
4388636010 | ||
|
|
584cfa6af8 | ||
|
|
fd7da7da62 | ||
|
|
19923aa8b7 | ||
|
|
28bed059aa | ||
|
|
cbeefc877c | ||
|
|
b981f3eeb7 | ||
|
|
5917c2d5b7 | ||
|
|
3812d91390 | ||
|
|
c7493bbdd0 | ||
|
|
1585bfec3b | ||
|
|
07be1791ba | ||
|
|
7a18c1ef44 | ||
|
|
b59c657be3 | ||
|
|
2ebd71bfd4 | ||
|
|
f330b33e2b | ||
|
|
db56fc3bcb | ||
|
|
da3274d1b3 | ||
|
|
0cd9bdcf9f | ||
|
|
ef190f349d | ||
|
|
f8e64d879c | ||
|
|
0a1d4ba842 | ||
|
|
e669835665 | ||
|
|
696def2bf7 | ||
|
|
c5eb3fd4f0 | ||
|
|
4480fd3e93 | ||
|
|
4da3ead294 | ||
|
|
53fbb497e9 | ||
|
|
d6b485493d | ||
|
|
9ba07edb2e | ||
|
|
4ca2dcb404 | ||
|
|
1564ae650f | ||
|
|
b2c7019006 | ||
|
|
6d8cf25bd7 | ||
|
|
739e1badb6 | ||
|
|
5d469686b0 | ||
|
|
feb0481ba3 | ||
|
|
e98efdcc5e | ||
|
|
c47d5196be | ||
|
|
b83bd282dc | ||
|
|
a8090f7d65 | ||
|
|
794bcc8029 | ||
|
|
6f96c4bc96 | ||
|
|
1b5e03f975 | ||
|
|
78b387d948 | ||
|
|
5536f74992 | ||
|
|
55373e65b4 | ||
|
|
83493e4294 | ||
|
|
ece41d2605 | ||
|
|
79ec6d677c | ||
|
|
10b6e4f5b4 | ||
|
|
8266750497 | ||
|
|
a104aa4714 | ||
|
|
658b28dc57 | ||
|
|
a70d3abd37 |
3
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
3
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -71,5 +71,6 @@ body:
|
||||
which should give more context on a compiler crash.
|
||||
- If it's a regression, you can help us by identifying which version introduced the bug,
|
||||
see [Bisecting for regressions](https://nim-lang.github.io/Nim/intern.html#bisecting-for-regressions),
|
||||
or at least try known past releases (eg `choosenim 1.2.0`).
|
||||
or at least try known past releases (e.g. `choosenim 2.0.0`). The Nim repo also supports online bisecting
|
||||
via making a comment, which contains a code block starting by `!nim c`, `!nim js` etc. , see [nimrun-action](https://github.com/juancarlospaco/nimrun-action).
|
||||
- [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html)
|
||||
|
||||
69
.github/stale.yml
vendored
69
.github/stale.yml
vendored
@@ -1,69 +0,0 @@
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||
daysUntilStale: 365
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
|
||||
daysUntilClose: 30
|
||||
|
||||
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
|
||||
onlyLabels: []
|
||||
|
||||
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
||||
exemptLabels:
|
||||
- ARC
|
||||
- bounty
|
||||
- Codegen
|
||||
- Crash
|
||||
- Generics
|
||||
- High Priority
|
||||
- Macros
|
||||
- Next release
|
||||
- Showstopper
|
||||
- Static[T]
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: false
|
||||
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: false
|
||||
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: false
|
||||
|
||||
# Label to use when marking as stale
|
||||
staleLabel: stale
|
||||
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This pull request has been automatically marked as stale because it has not had
|
||||
recent activity.
|
||||
If you think it is still a valid PR, please rebase it on the latest devel;
|
||||
otherwise it will be closed. Thank you for your contributions.
|
||||
|
||||
# Comment to post when removing the stale label.
|
||||
# unmarkComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Comment to post when closing a stale Issue or Pull Request.
|
||||
# closeComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 20
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
only: pulls
|
||||
|
||||
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
||||
# pulls:
|
||||
# daysUntilStale: 30
|
||||
# markComment: >
|
||||
# This pull request has been automatically marked as stale because it has not had
|
||||
# recent activity. It will be closed if no further activity occurs. Thank you
|
||||
# for your contributions.
|
||||
|
||||
# issues:
|
||||
# exemptLabels:
|
||||
# - confirmed
|
||||
23
.github/workflows/bisects.yml
vendored
Normal file
23
.github/workflows/bisects.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# See https://github.com/juancarlospaco/nimrun-action/issues/3#issuecomment-1607344901
|
||||
name: issue comments bisects
|
||||
on:
|
||||
issue_comment:
|
||||
types: created
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
# nimrun-action requires Nim installed.
|
||||
- uses: jiro4989/setup-nim-action@v1
|
||||
with:
|
||||
nim-version: 'devel'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get install --no-install-recommends -yq valgrind
|
||||
|
||||
- uses: juancarlospaco/nimrun-action@nim
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
115
.github/workflows/ci_bench.yml
vendored
Normal file
115
.github/workflows/ci_bench.yml
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
name: Benchmarks CI
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- 'devel'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-20.04]
|
||||
cpu: [amd64]
|
||||
name: '${{ matrix.os }}'
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60 # refs bug #18178
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
run: |
|
||||
sudo apt-fast update -qq
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
sudo apt-fast install --no-install-recommends -yq \
|
||||
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
|
||||
valgrind libc6-dbg libblas-dev xorg-dev
|
||||
|
||||
- name: 'Add build binaries to PATH'
|
||||
shell: bash
|
||||
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: 'Build csourcesAny'
|
||||
shell: bash
|
||||
run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}'
|
||||
|
||||
- name: 'Build koch'
|
||||
shell: bash
|
||||
run: nim c koch
|
||||
|
||||
- name: 'Build Nim'
|
||||
shell: bash
|
||||
run: ./koch boot -d:release -d:nimStrictMode --lib:lib
|
||||
|
||||
- name: 'Build Nimble'
|
||||
shell: bash
|
||||
run: ./koch nimble
|
||||
|
||||
- name: 'Action'
|
||||
shell: bash
|
||||
run: nim c -r -d:release ci/action.nim
|
||||
|
||||
- name: 'Checkout minimize'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: 'nim-lang/ci_bench'
|
||||
path: minimize
|
||||
|
||||
- name: 'Run minimize benchmarks'
|
||||
shell: bash
|
||||
run: ./minimize/minimize ci-bench
|
||||
|
||||
- name: 'Restore minimize cached database'
|
||||
uses: actions/cache/restore@v3
|
||||
with:
|
||||
path: minimize.csv
|
||||
key: minimize-db-key
|
||||
|
||||
- name: 'Update minimize db'
|
||||
shell: bash
|
||||
run: ./minimize/minimize update-db
|
||||
|
||||
- name: 'Save minimize cached database'
|
||||
if: |
|
||||
github.event_name == 'push' && github.ref == 'refs/heads/devel' &&
|
||||
matrix.target == 'linux'
|
||||
uses: actions/cache/save@v3
|
||||
with:
|
||||
path: minimize.csv
|
||||
key: minimize-db-key
|
||||
|
||||
- name: 'Generate minimize report'
|
||||
shell: bash
|
||||
run: ./minimize/minimize generate-report
|
||||
|
||||
- name: 'Archive minimize report'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: minimize-report
|
||||
path: |
|
||||
minimize/minimize.html
|
||||
minimize/minimize.csv
|
||||
|
||||
# Requires additional permissions, see:
|
||||
# https://github.com/nim-lang/Nim/actions/runs/4778177321/jobs/8494423792?pr=21566
|
||||
# - name: 'Publish HTML report'
|
||||
# uses: rossjrw/pr-preview-action@v1
|
||||
# with:
|
||||
# source-dir: minimize
|
||||
# umbrella-dir: minimize
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract md summary
|
||||
run: |
|
||||
cat minimize/summary.md >> $GITHUB_STEP_SUMMARY
|
||||
5
.github/workflows/ci_packages.yml
vendored
5
.github/workflows/ci_packages.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- 'devel'
|
||||
- 'version-2-0'
|
||||
- 'version-1-6'
|
||||
- 'version-1-2'
|
||||
|
||||
@@ -27,12 +28,12 @@ jobs:
|
||||
NIM_TESTAMENT_BATCH: ${{ matrix.batch }}
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
|
||||
4
.github/workflows/ci_publish.yml
vendored
4
.github/workflows/ci_publish.yml
vendored
@@ -17,12 +17,12 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
|
||||
25
.github/workflows/stale.yml
vendored
Normal file
25
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# https://github.com/actions/stale#usage
|
||||
name: Stale pull requests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # Midnight.
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
with:
|
||||
days-before-pr-stale: 365
|
||||
days-before-pr-close: 30
|
||||
days-before-issue-stale: -1
|
||||
days-before-issue-close: -1
|
||||
exempt-pr-labels: "ARC,bounty,Codegen,Crash,Generics,High Priority,Macros,Next release,Showstopper,Static[T]"
|
||||
exempt-issue-labels: "Showstopper,Severe,bounty,Compiler Crash,Medium Priority"
|
||||
stale-pr-message: >
|
||||
This pull request is stale because it has been open for 1 year with no activity.
|
||||
Contribute more commits on the pull request and rebase it on the latest devel,
|
||||
or it will be closed in 30 days. Thank you for your contributions.
|
||||
close-pr-message: >
|
||||
This pull request has been marked as stale and closed due to inactivity after 395 days.
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -67,6 +67,7 @@ testament.db
|
||||
|
||||
/csources
|
||||
/csources_v1
|
||||
/csources_v2
|
||||
|
||||
/dist/
|
||||
# /lib/fusion # fusion is now unbundled; `git status` should reveal if it's there so users can act on it
|
||||
@@ -109,3 +110,5 @@ htmldocs
|
||||
nimdoc.out.css
|
||||
# except here:
|
||||
!/nimdoc/testproject/expected/*
|
||||
pkgs/
|
||||
/compiler/compiler/
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
# xxx unused, out of date
|
||||
|
||||
image: ubuntu:18.04
|
||||
|
||||
stages:
|
||||
- pre-build
|
||||
- build
|
||||
- deploy
|
||||
- test
|
||||
|
||||
.linux_set_path: &linux_set_path_def
|
||||
before_script:
|
||||
- export PATH=$(pwd)/bin${PATH:+:$PATH}
|
||||
tags:
|
||||
- linux
|
||||
|
||||
.windows_set_path: &win_set_path_def
|
||||
before_script:
|
||||
- set PATH=%CD%\bin;%PATH%
|
||||
tags:
|
||||
- windows
|
||||
|
||||
|
||||
build-windows:
|
||||
stage: build
|
||||
script:
|
||||
- ci\build.bat
|
||||
artifacts:
|
||||
paths:
|
||||
- bin\nim.exe
|
||||
- bin\nimd.exe
|
||||
- compiler\nim.exe
|
||||
- koch.exe
|
||||
expire_in: 1 week
|
||||
tags:
|
||||
- windows
|
||||
|
||||
deploy-windows:
|
||||
stage: deploy
|
||||
script:
|
||||
- koch.exe winrelease
|
||||
artifacts:
|
||||
paths:
|
||||
- build/*.exe
|
||||
- build/*.zip
|
||||
expire_in: 1 week
|
||||
tags:
|
||||
- windows
|
||||
- fast
|
||||
|
||||
|
||||
|
||||
test-windows:
|
||||
stage: test
|
||||
<<: *win_set_path_def
|
||||
script:
|
||||
- call ci\deps.bat
|
||||
- nim c testament\tester
|
||||
- testament\tester.exe all
|
||||
tags:
|
||||
- windows
|
||||
- fast
|
||||
@@ -23,11 +23,11 @@ jobs:
|
||||
vmImage: 'ubuntu-20.04'
|
||||
CPU: amd64
|
||||
# regularly breaks, refs bug #17325
|
||||
Linux_i386:
|
||||
# on 'ubuntu-16.04' (not supported anymore anyways) it errored with:
|
||||
# g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed
|
||||
vmImage: 'ubuntu-18.04'
|
||||
CPU: i386
|
||||
# Linux_i386:
|
||||
# # on 'ubuntu-16.04' (not supported anymore anyways) it errored with:
|
||||
# # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed
|
||||
# vmImage: 'ubuntu-18.04'
|
||||
# CPU: i386
|
||||
OSX_amd64:
|
||||
vmImage: 'macOS-11'
|
||||
CPU: amd64
|
||||
|
||||
@@ -14,7 +14,7 @@ else
|
||||
fi
|
||||
|
||||
# Find out where the pretty printer Python module is
|
||||
GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/nim-gdb.py"
|
||||
GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/debug/nim-gdb.py"
|
||||
|
||||
# Run GDB with the additional arguments that load the pretty printers
|
||||
# Set the environment variable `NIM_GDB` to overwrite the call to a
|
||||
|
||||
@@ -3,7 +3,7 @@ for %%i in (nim.exe) do (set NIM_BIN=%%~dp$PATH:i)
|
||||
|
||||
for %%i in ("%NIM_BIN%\..\") do (set NIM_ROOT=%%~fi)
|
||||
|
||||
set @GDB_PYTHON_MODULE_PATH=%NIM_ROOT%\tools\nim-gdb.py
|
||||
set @GDB_PYTHON_MODULE_PATH=%NIM_ROOT%\tools\debug\nim-gdb.py
|
||||
set @NIM_GDB=gdb.exe
|
||||
|
||||
@echo source %@GDB_PYTHON_MODULE_PATH%> wingdbcommand.txt
|
||||
|
||||
253
changelog.md
253
changelog.md
@@ -1,273 +1,30 @@
|
||||
# v2.0.0 - yyyy-mm-dd
|
||||
# v2.2.0 - yyyy-mm-dd
|
||||
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response, it followed Apache HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behavior. Previously it raised `ValueError`.
|
||||
|
||||
- `addr` is now available for all addressable locations,
|
||||
`unsafeAddr` is now deprecated and an alias for `addr`.
|
||||
|
||||
- Certain definitions from the default `system` module have been moved to
|
||||
the following new modules:
|
||||
|
||||
- `std/syncio`
|
||||
- `std/assertions`
|
||||
- `std/formatfloat`
|
||||
- `std/objectdollar`
|
||||
- `std/widestrs`
|
||||
- `std/typedthreads`
|
||||
- `std/sysatomics`
|
||||
|
||||
In the future, these definitions will be removed from the `system` module,
|
||||
and their respective modules will have to be imported to use them.
|
||||
Currently, to make these imports required, the `-d:nimPreviewSlimSystem` option
|
||||
may be used.
|
||||
|
||||
- Enabling `-d:nimPreviewSlimSystem` also removes the following deprecated
|
||||
symbols in the `system` module:
|
||||
- Aliases with `Error` suffix to exception types that have a `Defect` suffix
|
||||
(see [exceptions](https://nim-lang.org/docs/exceptions.html)):
|
||||
`ArithmeticError`, `DivByZeroError`, `OverflowError`,
|
||||
`AccessViolationError`, `AssertionError`, `OutOfMemError`, `IndexError`,
|
||||
`FieldError`, `RangeError`, `StackOverflowError`, `ReraiseError`,
|
||||
`ObjectAssignmentError`, `ObjectConversionError`, `FloatingPointError`,
|
||||
`FloatOverflowError`, `FloatUnderflowError`, `FloatInexactError`,
|
||||
`DeadThreadError`, `NilAccessError`
|
||||
- `addQuitProc`, replaced by `exitprocs.addExitProc`
|
||||
- Legacy unsigned conversion operations: `ze`, `ze64`, `toU8`, `toU16`, `toU32`
|
||||
- `TaintedString`, formerly a distinct alias to `string`
|
||||
- `PInt32`, `PInt64`, `PFloat32`, `PFloat64`, aliases to
|
||||
`ptr int32`, `ptr int64`, `ptr float32`, `ptr float64`
|
||||
|
||||
- Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in
|
||||
in the `system` module.
|
||||
|
||||
- Enabling `-d:nimPreviewCstringConversion`, `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` don't support conversion to cstring anymore.
|
||||
|
||||
- The `gc:v2` option is removed.
|
||||
|
||||
- The `mainmodule` and `m` options are removed.
|
||||
|
||||
- The `threads:on` option is now the default.
|
||||
|
||||
- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via
|
||||
`experimental:flexibleOptionalParams`.
|
||||
|
||||
- Automatic dereferencing (experimental feature) is removed.
|
||||
|
||||
- The `Math.trunc` polyfill for targeting Internet Explorer was
|
||||
previously included in most JavaScript output files.
|
||||
Now, it is only included with `-d:nimJsMathTruncPolyfill`.
|
||||
If you are targeting Internet Explorer, you may choose to enable this option
|
||||
or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma).
|
||||
Nim uses `Math.trunc` for the division and modulo operators for integers.
|
||||
|
||||
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
|
||||
`sink` for optimization purposes.
|
||||
|
||||
- The `nimPreviewDotLikeOps` define is going to be removed or deprecated.
|
||||
|
||||
- The `{.this.}` pragma, deprecated since 0.19, has been removed.
|
||||
- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead.
|
||||
```nim
|
||||
type Foo = distinct ptr int
|
||||
|
||||
# Before:
|
||||
var x: Foo = nil
|
||||
# After:
|
||||
var x: Foo = Foo(nil)
|
||||
```
|
||||
- Removed two type pragma syntaxes deprecated since 0.20, namely
|
||||
`type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`.
|
||||
|
||||
- [Overloadable enums](https://nim-lang.github.io/Nim/manual.html#overloadable-enum-value-names) and Unicode Operators
|
||||
are no longer experimental.
|
||||
|
||||
- Removed the `nimIncrSeqV3` define.
|
||||
|
||||
- `macros.getImpl` for `const` symbols now returns the full definition node
|
||||
(as `nnkConstDef`) rather than the AST of the constant value.
|
||||
|
||||
- Lock levels are deprecated, now a noop.
|
||||
|
||||
- ORC is now the default memory management strategy. Use
|
||||
`--mm:refc` for a transition period.
|
||||
|
||||
- `strictEffects` are no longer experimental.
|
||||
Use `legacy:laxEffects` to keep backward compatibility.
|
||||
|
||||
- The `gorge`/`staticExec` calls will now return a descriptive message in the output
|
||||
if the execution fails for whatever reason. To get back legacy behaviour use `-d:nimLegacyGorgeErrors`.
|
||||
|
||||
- Pointer to `cstring` conversion now triggers a `[PtrToCstringConv]` warning.
|
||||
This warning will become an error in future versions! Use a `cast` operation
|
||||
like `cast[cstring](x)` instead.
|
||||
|
||||
- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`.
|
||||
|
||||
- Object fields now support default values, see https://nim-lang.github.io/Nim/manual.html#types-default-values-for-object-fields for details.
|
||||
|
||||
- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead.
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
[//]: # "Changes:"
|
||||
- OpenSSL 3 is now supported.
|
||||
- `macros.parseExpr` and `macros.parseStmt` now accept an optional
|
||||
filename argument for more informative errors.
|
||||
- Module `colors` expanded with missing colors from the CSS color standard.
|
||||
`colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard.
|
||||
- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)).
|
||||
- The `md5` module now works at compile time and in JavaScript.
|
||||
- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef` to support `const` tables.
|
||||
- `strutils.find` now uses and defaults to `last = -1` for whole string searches,
|
||||
making limiting it to just the first char (`last = 0`) valid.
|
||||
- `random.rand` now works with `Ordinal`s.
|
||||
- Undeprecated `os.isvalidfilename`.
|
||||
- `std/oids` now uses `int64` to store time internally (before it was int32).
|
||||
- `std/uri.Uri` dollar `$` improved, precalculates the `string` result length from the `Uri`.
|
||||
- `std/uri.Uri.isIpv6` is now exported.
|
||||
- `std/logging.ConsoleLogger` and `FileLogger` now have a `flushThreshold` attribute to set what log message levels are automatically flushed. For Nim v1 use `-d:nimFlushAllLogs` to automatically flush all message levels. Flushing all logs is the default behavior for Nim v2.
|
||||
|
||||
|
||||
- `std/net.IpAddress` dollar `$` improved, uses a fixed capacity for the `string` result based from the `IpAddressFamily`.
|
||||
- `std/jsfetch.newFetchOptions` now has default values for all parameters
|
||||
- `std/jsformdata` now accepts `Blob` data type.
|
||||
|
||||
|
||||
[//]: # "Additions:"
|
||||
- Added ISO 8601 week date utilities in `times`:
|
||||
- Added `IsoWeekRange`, a range type for weeks in a week-based year.
|
||||
- Added `IsoYear`, a distinct type for a week-based year in contrast to a regular year.
|
||||
- Added a `initDateTime` overload to create a datetime from an ISO week date.
|
||||
- Added `getIsoWeekAndYear` to get an ISO week number and week-based year from a datetime.
|
||||
- Added `getIsoWeeksInYear` to return the number of weeks in a week-based year.
|
||||
- Added new modules which were part of `std/os`:
|
||||
- Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling.
|
||||
- Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`.
|
||||
- Added `sep` parameter in `std/uri` to specify the query separator.
|
||||
- Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift)
|
||||
and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask)
|
||||
in `jscore` for JavaScript targets.
|
||||
- Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`.
|
||||
- Added `complex.sgn` for obtaining the phase of complex numbers.
|
||||
- Added `insertAdjacentText`, `insertAdjacentElement`, `insertAdjacentHTML`,
|
||||
`after`, `before`, `closest`, `append`, `hasAttributeNS`, `removeAttributeNS`,
|
||||
`hasPointerCapture`, `releasePointerCapture`, `requestPointerLock`,
|
||||
`replaceChildren`, `replaceWith`, `scrollIntoViewIfNeeded`, `setHTML`,
|
||||
`toggleAttribute`, and `matches` to `std/dom`.
|
||||
- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices)
|
||||
- Added `capacity` for `string` and `seq` to return the current capacity, see https://github.com/nim-lang/RFCs/issues/460
|
||||
- Added `openArray[char]` overloads for `std/parseutils` allowing more code reuse.
|
||||
- Added `openArray[char]` overloads for `std/unicode` allowing more code reuse.
|
||||
- Added `safe` parameter to `base64.encodeMime`.
|
||||
|
||||
[//]: # "Deprecations:"
|
||||
- Deprecated `selfExe` for Nimscript.
|
||||
- Deprecated `std/sums`.
|
||||
- Deprecated `std/base64.encode` for collections of arbitrary integer element type.
|
||||
Now only `byte` and `char` are supported.
|
||||
|
||||
|
||||
[//]: # "Removals:"
|
||||
- Removed deprecated module `parseopt2`.
|
||||
- Removed deprecated module `sharedstrings`.
|
||||
- Removed deprecated module `dom_extensions`.
|
||||
- Removed deprecated module `LockFreeHash`.
|
||||
- Removed deprecated module `events`.
|
||||
- Removed deprecated `oids.oidToString`.
|
||||
- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`.
|
||||
- Removed deprecated `jsre.test` and `jsre.toString`.
|
||||
- Removed deprecated `math.c_frexp`.
|
||||
- Removed deprecated `` httpcore.`==` ``.
|
||||
- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types.
|
||||
- Removed deprecated `osproc.poDemon`, symbol with typo.
|
||||
|
||||
|
||||
## Language changes
|
||||
|
||||
- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) supports the definition of forbidden tags by the `.forbids` pragma
|
||||
which can be used to disable certain effects in proc types.
|
||||
- [Case statement macros](https://nim-lang.github.io/Nim/manual.html#macros-case-statement-macros) are no longer experimental,
|
||||
meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them.
|
||||
- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed
|
||||
for the right-hand side of type definitions in type sections. Previously
|
||||
they would error with "invalid indentation".
|
||||
- `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`.
|
||||
In the command line, this is defined as `-d:a.b.c`. Older versions can
|
||||
use accents as in ``defined(`a.b.c`)`` to access such defines.
|
||||
- [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes:
|
||||
- Templates now accept macro pragmas.
|
||||
- Macro pragmas for var/let/const sections have been redesigned in a way that works
|
||||
similarly to routine macro pragmas. The new behavior is documented in the
|
||||
[experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#extended-macro-pragmas).
|
||||
- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`,
|
||||
allowing multiple type definitions to be injected in place of the original type definition.
|
||||
|
||||
```nim
|
||||
import macros
|
||||
macro multiply(amount: static int, s: untyped): untyped =
|
||||
let name = $s[0].basename
|
||||
result = newNimNode(nnkTypeSection)
|
||||
for i in 1 .. amount:
|
||||
result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2]))
|
||||
type
|
||||
Foo = object
|
||||
Bar {.multiply: 3.} = object
|
||||
x, y, z: int
|
||||
Baz = object
|
||||
# becomes
|
||||
type
|
||||
Foo = object
|
||||
Bar1 = object
|
||||
x, y, z: int
|
||||
Bar2 = object
|
||||
x, y, z: int
|
||||
Bar3 = object
|
||||
x, y, z: int
|
||||
Baz = object
|
||||
```
|
||||
|
||||
- Redefining templates with the same signature implicitly was previously
|
||||
allowed to support certain macro code. A `{.redefine.}` pragma has been
|
||||
added to make this work explicitly, and a warning is generated in the case
|
||||
where it is implicit. This behavior only applies to templates, redefinition
|
||||
is generally disallowed for other symbols.
|
||||
|
||||
- A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference)
|
||||
has been implemented for a variety of basic cases. For example, code like the following now compiles:
|
||||
|
||||
```nim
|
||||
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
|
||||
```
|
||||
|
||||
- `cstring` is now accepted as a selector in `case` statements, removing the
|
||||
need to convert to `string`. On the JS backend, this is translated directly
|
||||
to a `switch` statement.
|
||||
|
||||
- Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters).
|
||||
- Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`.
|
||||
|
||||
|
||||
## Compiler changes
|
||||
|
||||
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
|
||||
reality better. (Nim moved away from all techniques based on "tracing".)
|
||||
|
||||
- Defines the `gcRefc` symbol which allows writing specific code for the refc GC.
|
||||
|
||||
- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`,
|
||||
without requiring `-d:nimVersion140` which is now a noop.
|
||||
|
||||
- `--styleCheck`, `--hintAsError` and `--warningAsError` now only apply to the current package.
|
||||
|
||||
- The switch `--nimMainPrefix:prefix` has been added to add a prefix to the names of `NimMain` and
|
||||
related functions produced on the backend. This prevents conflicts with other Nim
|
||||
static libraries.
|
||||
|
||||
- When compiling for Release the flag `-fno-math-errno` is used for GCC.
|
||||
|
||||
|
||||
## Tool changes
|
||||
|
||||
- Nim now supports Nimble version 0.14 which added support for lock-files. This is done by
|
||||
a simple configuration change setting that you can do yourself too. In `$nim/config/nim.cfg`
|
||||
replace `pkgs` by `pkgs2`.
|
||||
- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package in tow.
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
# v1.xx.x - yyyy-mm-dd
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
- `std/sharedlist` and `std/sharedtables` are now deprecated, see RFC [#433](https://github.com/nim-lang/RFCs/issues/433).
|
||||
|
||||
### New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall
|
||||
|
||||
This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17.
|
||||
|
||||
On linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall.
|
||||
|
||||
When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be:
|
||||
```sh
|
||||
$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details
|
||||
$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8
|
||||
$ sh build.sh # per unix install instructions
|
||||
$ bin/nim c koch # per unix install instructions
|
||||
$ ./koch boot -d:release # per unix install instructions
|
||||
$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall
|
||||
```
|
||||
|
||||
This is necessary to pass when building nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for stdlib (sysrand in particular).
|
||||
|
||||
## Language changes
|
||||
|
||||
|
||||
## Compiler changes
|
||||
|
||||
|
||||
## Tool changes
|
||||
330
changelogs/changelog_2_0_0.md
Normal file
330
changelogs/changelog_2_0_0.md
Normal file
@@ -0,0 +1,330 @@
|
||||
# v2.0.0 - 2023-08-01
|
||||
|
||||
Version 2.0 is a big milestone with too many changes to list them all here.
|
||||
|
||||
For a full list see [details](changelog_2_0_0_details.html).
|
||||
|
||||
|
||||
## New features
|
||||
|
||||
### Better tuple unpacking
|
||||
|
||||
Tuple unpacking for variables is now treated as syntax sugar that directly
|
||||
expands into multiple assignments. Along with this, tuple unpacking for
|
||||
variables can now be nested.
|
||||
|
||||
```nim
|
||||
proc returnsNestedTuple(): (int, (int, int), int, int) = (4, (5, 7), 2, 3)
|
||||
|
||||
# Now nesting is supported!
|
||||
let (x, (_, y), _, z) = returnsNestedTuple()
|
||||
|
||||
```
|
||||
|
||||
### Improved type inference
|
||||
|
||||
A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference) has been implemented for a variety of basic cases.
|
||||
|
||||
For example, code like the following now compiles:
|
||||
|
||||
```nim
|
||||
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
|
||||
```
|
||||
|
||||
### Forbidden Tags
|
||||
|
||||
[Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) now supports the definition
|
||||
of forbidden tags by the `.forbids` pragma which can be used to disable certain effects in proc types.
|
||||
|
||||
For example:
|
||||
|
||||
```nim
|
||||
|
||||
type IO = object ## input/output effect
|
||||
proc readLine(): string {.tags: [IO].} = discard
|
||||
proc echoLine(): void = discard
|
||||
|
||||
proc no_IO_please() {.forbids: [IO].} =
|
||||
# this is OK because it didn't define any tag:
|
||||
echoLine()
|
||||
# the compiler prevents this:
|
||||
let y = readLine()
|
||||
|
||||
```
|
||||
|
||||
### New standard library modules
|
||||
|
||||
The famous `os` module got an overhaul. Several of its features are available
|
||||
under a new interface that introduces a `Path` abstraction. A `Path` is
|
||||
a `distinct string`, which improves the type safety when dealing with paths, files
|
||||
and directories.
|
||||
|
||||
Use:
|
||||
|
||||
- `std/oserrors` for OS error reporting.
|
||||
- `std/envvars` for environment variables handling.
|
||||
- `std/paths` for path handling.
|
||||
- `std/dirs` for directory creation/deletion/traversal.
|
||||
- `std/files` for file existence checking, file deletions and moves.
|
||||
- `std/symlinks` for symlink handling.
|
||||
- `std/appdirs` for accessing configuration/home/temp directories.
|
||||
- `std/cmdline` for reading command line parameters.
|
||||
|
||||
### Consistent underscore handling
|
||||
|
||||
The underscore identifier (`_`) is now generally not added to scope when
|
||||
used as the name of a definition. While this was already the case for
|
||||
variables, it is now also the case for routine parameters, generic
|
||||
parameters, routine declarations, type declarations, etc. This means that the following code now does not compile:
|
||||
|
||||
```nim
|
||||
proc foo(_: int): int = _ + 1
|
||||
echo foo(1)
|
||||
|
||||
proc foo[_](t: typedesc[_]): seq[_] = @[default(_)]
|
||||
echo foo[int]()
|
||||
|
||||
proc _() = echo "_"
|
||||
_()
|
||||
|
||||
type _ = int
|
||||
let x: _ = 3
|
||||
```
|
||||
|
||||
Whereas the following code now compiles:
|
||||
|
||||
```nim
|
||||
proc foo(_, _: int): int = 123
|
||||
echo foo(1, 2)
|
||||
|
||||
proc foo[_, _](): int = 123
|
||||
echo foo[int, bool]()
|
||||
|
||||
proc foo[T, U](_: typedesc[T], _: typedesc[U]): (T, U) = (default(T), default(U))
|
||||
echo foo(int, bool)
|
||||
|
||||
proc _() = echo "one"
|
||||
proc _() = echo "two"
|
||||
|
||||
type _ = int
|
||||
type _ = float
|
||||
```
|
||||
|
||||
### JavaScript codegen improvement
|
||||
|
||||
The JavaScript backend now uses [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
|
||||
for 64-bit integer types (`int64` and `uint64`) by default. As this affects
|
||||
JS code generation, code using these types to interface with the JS backend
|
||||
may need to be updated. Note that `int` and `uint` are not affected.
|
||||
|
||||
For compatibility with [platforms that do not support BigInt](https://caniuse.com/bigint)
|
||||
and in the case of potential bugs with the new implementation, the
|
||||
old behavior is currently still supported with the command line option
|
||||
`--jsbigint64:off`.
|
||||
|
||||
|
||||
## Docgen improvements
|
||||
|
||||
`Markdown` is now the default markup language of doc comments (instead
|
||||
of the legacy `RstMarkdown` mode). In this release we begin to separate
|
||||
RST and Markdown features to better follow specification of each
|
||||
language, with the focus on Markdown development.
|
||||
See also [the docs](https://nim-lang.github.io/Nim/markdown_rst.html).
|
||||
|
||||
* Added a `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to
|
||||
select the markup language mode in the doc comments of the current `.nim`
|
||||
file for processing by `nim doc`:
|
||||
|
||||
1. `Markdown` (default) is basically CommonMark (standard Markdown) +
|
||||
some Pandoc Markdown features + some RST features that are missing
|
||||
in our current implementation of CommonMark and Pandoc Markdown.
|
||||
2. `RST` closely follows the RST spec with few additional Nim features.
|
||||
3. `RstMarkdown` is a maximum mix of RST and Markdown features, which
|
||||
is kept for the sake of compatibility and ease of migration.
|
||||
|
||||
* Added separate `md2html` and `rst2html` commands for processing
|
||||
standalone `.md` and `.rst` files respectively (and also `md2tex`/`rst2tex`).
|
||||
|
||||
* Added Pandoc Markdown bracket syntax `[...]` for making anchor-less links.
|
||||
* Docgen now supports concise syntax for referencing Nim symbols:
|
||||
instead of specifying HTML anchors directly one can use original
|
||||
Nim symbol declarations (adding the aforementioned link brackets
|
||||
`[...]` around them).
|
||||
* To use this feature across modules, a new `importdoc` directive was added.
|
||||
Using this feature for referencing also helps to ensure that links
|
||||
(inside one module or the whole project) are not broken.
|
||||
* Added support for RST & Markdown quote blocks (blocks starting with `>`).
|
||||
* Added a popular Markdown definition lists extension.
|
||||
* Added Markdown indented code blocks (blocks indented by >= 4 spaces).
|
||||
* Added syntax for additional parameters to Markdown code blocks:
|
||||
|
||||
```nim test="nim c $1"
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
## C++ interop enhancements
|
||||
|
||||
Nim 2.0 takes C++ interop to the next level. With the new [virtual](https://nim-lang.github.io/Nim/manual_experimental.html#virtual-pragma) pragma and the extended [constructor](https://nim-lang.github.io/Nim/manual_experimental.html#constructor-pragma) pragma.
|
||||
Now one can define constructors and virtual procs that maps to C++ constructors and virtual methods, allowing one to further customize
|
||||
the interoperability. There is also extended support for the [codeGenDecl](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-codegendecl-pragma) pragma, so that it works on types.
|
||||
|
||||
It's a common pattern in C++ to use inheritance to extend a library. Some even use multiple inheritance as a mechanism to make interfaces.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
```cpp
|
||||
|
||||
struct Base {
|
||||
int someValue;
|
||||
Base(int inValue) {
|
||||
someValue = inValue;
|
||||
};
|
||||
};
|
||||
|
||||
class IPrinter {
|
||||
public:
|
||||
virtual void print() = 0;
|
||||
};
|
||||
```
|
||||
|
||||
```nim
|
||||
|
||||
type
|
||||
Base* {.importcpp, inheritable.} = object
|
||||
someValue*: int32
|
||||
IPrinter* {.importcpp.} = object
|
||||
|
||||
const objTemplate = """
|
||||
struct $1 : public $3, public IPrinter {
|
||||
$2
|
||||
};
|
||||
""";
|
||||
|
||||
type NimChild {.codegenDecl: objTemplate .} = object of Base
|
||||
|
||||
proc makeNimChild(val: int32): NimChild {.constructor: "NimClass('1 #1) : Base(#1)".} =
|
||||
echo "It calls the base constructor passing " & $this.someValue
|
||||
this.someValue = val * 2 # Notice how we can access `this` inside the constructor. It's of the type `ptr NimChild`.
|
||||
|
||||
proc print*(self: NimChild) {.virtual.} =
|
||||
echo "Some value is " & $self.someValue
|
||||
|
||||
let child = makeNimChild(10)
|
||||
child.print()
|
||||
```
|
||||
|
||||
It outputs:
|
||||
|
||||
```
|
||||
It calls the base constructor passing 10
|
||||
Some value is 20
|
||||
```
|
||||
|
||||
|
||||
## ARC/ORC refinements
|
||||
|
||||
With the 2.0 release, the ARC/ORC model got refined once again and is now finally complete:
|
||||
|
||||
1. Programmers now have control over the "item was moved from" state as `=wasMoved` is overridable.
|
||||
2. There is a new `=dup` hook which is more efficient than the old combination of `=wasMoved(tmp); =copy(tmp, x)` operations.
|
||||
3. Destructors now take a parameter of the attached object type `T` directly and don't have to take a `var T` parameter.
|
||||
|
||||
With these important optimizations we improved the runtime of the compiler and important benchmarks by 0%! Wait ... what?
|
||||
Yes, unfortunately it turns out that for a modern optimizer like in GCC or LLVM there is no difference.
|
||||
|
||||
But! This refined model is more efficient once separate compilation enters the picture. In other words, as we think of
|
||||
providing a stable ABI it is important not to lose any efficiency in the calling conventions.
|
||||
|
||||
|
||||
## Tool changes
|
||||
|
||||
- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs` before). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop.
|
||||
- nimgrep now offers the option `--inContext` (and `--notInContext`), which
|
||||
allows to filter only matches with the context block containing a given pattern.
|
||||
- nimgrep: names of options containing "include/exclude" are deprecated,
|
||||
e.g. instead of `--includeFile` and `--excludeFile` we have
|
||||
`--filename` and `--notFilename` respectively.
|
||||
Also, the semantics are now consistent for such positive/negative filters.
|
||||
- Nim now ships with an alternative package manager called Atlas. More on this in upcoming versions.
|
||||
|
||||
|
||||
## Porting guide
|
||||
|
||||
### Block and Break
|
||||
|
||||
Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead. In other words, turn:
|
||||
|
||||
```nim
|
||||
|
||||
block:
|
||||
a()
|
||||
if cond:
|
||||
break
|
||||
b()
|
||||
|
||||
```
|
||||
|
||||
Into:
|
||||
|
||||
```nim
|
||||
|
||||
block maybePerformB:
|
||||
a()
|
||||
if cond:
|
||||
break maybePerformB
|
||||
b()
|
||||
|
||||
```
|
||||
|
||||
### Strict funcs
|
||||
|
||||
The definition of `"strictFuncs"` was changed.
|
||||
The old definition was roughly: "A store to a ref/ptr deref is forbidden unless it's coming from a `var T` parameter".
|
||||
The new definition is: "A store to a ref/ptr deref is forbidden."
|
||||
|
||||
This new definition is much easier to understand, the price is some expressitivity. The following code used to be
|
||||
accepted:
|
||||
|
||||
```nim
|
||||
|
||||
{.experimental: "strictFuncs".}
|
||||
|
||||
type Node = ref object
|
||||
s: string
|
||||
|
||||
func create(s: string): Node =
|
||||
result = Node()
|
||||
result.s = s # store to result[]
|
||||
|
||||
```
|
||||
|
||||
Now it has to be rewritten to:
|
||||
|
||||
```nim
|
||||
|
||||
{.experimental: "strictFuncs".}
|
||||
|
||||
type Node = ref object
|
||||
s: string
|
||||
|
||||
func create(s: string): Node =
|
||||
result = Node(s: s)
|
||||
|
||||
```
|
||||
|
||||
### Standard library
|
||||
|
||||
Several standard library modules have been moved to nimble packages, use `nimble` or `atlas` to install them:
|
||||
|
||||
- `std/punycode` => `punycode`
|
||||
- `std/asyncftpclient` => `asyncftpclient`
|
||||
- `std/smtp` => `smtp`
|
||||
- `std/db_common` => `db_connector/db_common`
|
||||
- `std/db_sqlite` => `db_connector/db_sqlite`
|
||||
- `std/db_mysql` => `db_connector/db_mysql`
|
||||
- `std/db_postgres` => `db_connector/db_postgres`
|
||||
- `std/db_odbc` => `db_connector/db_odbc`
|
||||
- `std/md5` => `checksums/md5`
|
||||
- `std/sha1` => `checksums/sha1`
|
||||
- `std/sums` => `sums`
|
||||
560
changelogs/changelog_2_0_0_details.md
Normal file
560
changelogs/changelog_2_0_0_details.md
Normal file
@@ -0,0 +1,560 @@
|
||||
# v2.0.0 - 2023-08-01
|
||||
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
|
||||
- ORC is now the default memory management strategy. Use
|
||||
`--mm:refc` for a transition period.
|
||||
|
||||
- The `threads:on` option is now the default.
|
||||
|
||||
- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response. It follows Apache's `HttpClient` (Java), `http` (go) and .NET `HttpWebResponse` (C#) behaviors. Previously it raised a `ValueError`.
|
||||
|
||||
- `addr` is now available for all addressable locations,
|
||||
`unsafeAddr` is now deprecated and an alias for `addr`.
|
||||
|
||||
- Certain definitions from the default `system` module have been moved to
|
||||
the following new modules:
|
||||
|
||||
- `std/syncio`
|
||||
- `std/assertions`
|
||||
- `std/formatfloat`
|
||||
- `std/objectdollar`
|
||||
- `std/widestrs`
|
||||
- `std/typedthreads`
|
||||
- `std/sysatomics`
|
||||
|
||||
In the future, these definitions will be removed from the `system` module,
|
||||
and their respective modules will have to be imported to use them.
|
||||
Currently, to make these imports required, the `-d:nimPreviewSlimSystem` option
|
||||
may be used.
|
||||
|
||||
- Enabling `-d:nimPreviewSlimSystem` also removes the following deprecated
|
||||
symbols in the `system` module:
|
||||
- Aliases with an `Error` suffix to exception types that have a `Defect` suffix
|
||||
(see [exceptions](https://nim-lang.github.io/Nim/exceptions.html)):
|
||||
`ArithmeticError`, `DivByZeroError`, `OverflowError`,
|
||||
`AccessViolationError`, `AssertionError`, `OutOfMemError`, `IndexError`,
|
||||
`FieldError`, `RangeError`, `StackOverflowError`, `ReraiseError`,
|
||||
`ObjectAssignmentError`, `ObjectConversionError`, `FloatingPointError`,
|
||||
`FloatOverflowError`, `FloatUnderflowError`, `FloatInexactError`,
|
||||
`DeadThreadError`, `NilAccessError`
|
||||
- `addQuitProc`, replaced by `exitprocs.addExitProc`
|
||||
- Legacy unsigned conversion operations: `ze`, `ze64`, `toU8`, `toU16`, `toU32`
|
||||
- `TaintedString`, formerly a distinct alias to `string`
|
||||
- `PInt32`, `PInt64`, `PFloat32`, `PFloat64`, aliases to
|
||||
`ptr int32`, `ptr int64`, `ptr float32`, `ptr float64`
|
||||
|
||||
- Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in
|
||||
in the `system` module, which is replaced by [threading/channels](https://github.com/nim-lang/threading/blob/master/threading/channels.nim). Use the command `nimble install threading` and import `threading/channels`.
|
||||
|
||||
- Enabling `-d:nimPreviewCstringConversion` causes `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` to not support conversion to `cstring` anymore.
|
||||
|
||||
- Enabling `-d:nimPreviewProcConversion` causes `proc` to not support conversion to
|
||||
`pointer` anymore. `cast` may be used instead.
|
||||
|
||||
- The `gc:v2` option is removed.
|
||||
|
||||
- The `mainmodule` and `m` options are removed.
|
||||
|
||||
- Optional parameters in combination with `: body` syntax ([RFC #405](https://github.com/nim-lang/RFCs/issues/405))
|
||||
are now opt-in via `experimental:flexibleOptionalParams`.
|
||||
|
||||
- Automatic dereferencing (experimental feature) is removed.
|
||||
|
||||
- The `Math.trunc` polyfill for targeting Internet Explorer was
|
||||
previously included in most JavaScript output files.
|
||||
Now, it is only included with `-d:nimJsMathTruncPolyfill`.
|
||||
If you are targeting Internet Explorer, you may choose to enable this option
|
||||
or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma).
|
||||
Nim uses `Math.trunc` for the division and modulo operators for integers.
|
||||
|
||||
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
|
||||
`sink` for optimization purposes.
|
||||
|
||||
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fullfill its promises.
|
||||
|
||||
- The `{.this.}` pragma, deprecated since 0.19, has been removed.
|
||||
- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead.
|
||||
```nim
|
||||
type Foo = distinct ptr int
|
||||
|
||||
# Before:
|
||||
var x: Foo = nil
|
||||
# After:
|
||||
var x: Foo = Foo(nil)
|
||||
```
|
||||
- Removed two type pragma syntaxes deprecated since 0.20, namely
|
||||
`type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`. Instead,
|
||||
use `type Foo[T] {.final.} = object`.
|
||||
|
||||
- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent
|
||||
with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`.
|
||||
This decision was made with the assumption that the old syntax was used rarely;
|
||||
if your code used the old syntax, please be aware of this change.
|
||||
|
||||
- [Overloadable enums](https://nim-lang.github.io/Nim/manual.html#overloadable-enum-value-names) and Unicode Operators
|
||||
are no longer experimental.
|
||||
|
||||
- `macros.getImpl` for `const` symbols now returns the full definition node
|
||||
(as `nnkConstDef`) rather than the AST of the constant value.
|
||||
|
||||
- Lock levels are deprecated, now a noop.
|
||||
|
||||
- `strictEffects` are no longer experimental.
|
||||
Use `legacy:laxEffects` to keep backward compatibility.
|
||||
|
||||
- The `gorge`/`staticExec` calls will now return a descriptive message in the output
|
||||
if the execution fails for whatever reason. To get back legacy behaviour, use `-d:nimLegacyGorgeErrors`.
|
||||
|
||||
- Pointer to `cstring` conversions now trigger a `[PtrToCstringConv]` warning.
|
||||
This warning will become an error in future versions! Use a `cast` operation
|
||||
like `cast[cstring](x)` instead.
|
||||
|
||||
- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`.
|
||||
|
||||
- Redefining templates with the same signature was previously
|
||||
allowed to support certain macro code. To do this explicitly, the
|
||||
`{.redefine.}` pragma has been added. Note that this is only for templates.
|
||||
Implicit redefinition of templates is now deprecated and will give an error in the future.
|
||||
|
||||
- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead.
|
||||
|
||||
- Several Standard libraries have been moved to nimble packages, use `nimble` to install them:
|
||||
- `std/punycode` => `punycode`
|
||||
- `std/asyncftpclient` => `asyncftpclient`
|
||||
- `std/smtp` => `smtp`
|
||||
- `std/db_common` => `db_connector/db_common`
|
||||
- `std/db_sqlite` => `db_connector/db_sqlite`
|
||||
- `std/db_mysql` => `db_connector/db_mysql`
|
||||
- `std/db_postgres` => `db_connector/db_postgres`
|
||||
- `std/db_odbc` => `db_connector/db_odbc`
|
||||
- `std/md5` => `checksums/md5`
|
||||
- `std/sha1` => `checksums/sha1`
|
||||
- `std/sums` => `std/sums`
|
||||
|
||||
- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of
|
||||
`foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`.
|
||||
This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead.
|
||||
|
||||
- When `--warning[BareExcept]:on` is enabled, if an `except` specifies no exception or any exception not inheriting from `Defect` or `CatchableError`, a `warnBareExcept` warning will be triggered. For example, the following code will emit a warning:
|
||||
```nim
|
||||
try:
|
||||
discard
|
||||
except: # Warning: The bare except clause is deprecated; use `except CatchableError:` instead [BareExcept]
|
||||
discard
|
||||
```
|
||||
|
||||
- The experimental `strictFuncs` feature now disallows a store to the heap via a `ref` or `ptr` indirection.
|
||||
|
||||
- The underscore identifier (`_`) is now generally not added to scope when
|
||||
used as the name of a definition. While this was already the case for
|
||||
variables, it is now also the case for routine parameters, generic
|
||||
parameters, routine declarations, type declarations, etc. This means that the following code now does not compile:
|
||||
|
||||
```nim
|
||||
proc foo(_: int): int = _ + 1
|
||||
echo foo(1)
|
||||
|
||||
proc foo[_](t: typedesc[_]): seq[_] = @[default(_)]
|
||||
echo foo[int]()
|
||||
|
||||
proc _() = echo "_"
|
||||
_()
|
||||
|
||||
type _ = int
|
||||
let x: _ = 3
|
||||
```
|
||||
|
||||
Whereas the following code now compiles:
|
||||
|
||||
```nim
|
||||
proc foo(_, _: int): int = 123
|
||||
echo foo(1, 2)
|
||||
|
||||
proc foo[_, _](): int = 123
|
||||
echo foo[int, bool]()
|
||||
|
||||
proc foo[T, U](_: typedesc[T], _: typedesc[U]): (T, U) = (default(T), default(U))
|
||||
echo foo(int, bool)
|
||||
|
||||
proc _() = echo "one"
|
||||
proc _() = echo "two"
|
||||
|
||||
type _ = int
|
||||
type _ = float
|
||||
```
|
||||
|
||||
- Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages.
|
||||
|
||||
- The JavaScript backend now uses [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
|
||||
for 64-bit integer types (`int64` and `uint64`) by default. As this affects
|
||||
JS code generation, code using these types to interface with the JS backend
|
||||
may need to be updated. Note that `int` and `uint` are not affected.
|
||||
|
||||
For compatibility with [platforms that do not support BigInt](https://caniuse.com/bigint)
|
||||
and in the case of potential bugs with the new implementation, the
|
||||
old behavior is currently still supported with the command line option
|
||||
`--jsbigint64:off`.
|
||||
|
||||
- The `proc` and `iterator` type classes now respectively only match
|
||||
procs and iterators. Previously both type classes matched any of
|
||||
procs or iterators.
|
||||
|
||||
```nim
|
||||
proc prc(): int =
|
||||
123
|
||||
|
||||
iterator iter(): int =
|
||||
yield 123
|
||||
|
||||
proc takesProc[T: proc](x: T) = discard
|
||||
proc takesIter[T: iterator](x: T) = discard
|
||||
|
||||
# always compiled:
|
||||
takesProc(prc)
|
||||
takesIter(iter)
|
||||
# no longer compiles:
|
||||
takesProc(iter)
|
||||
takesIter(prc)
|
||||
```
|
||||
|
||||
- The `proc` and `iterator` type classes now accept a calling convention pragma
|
||||
(i.e. `proc {.closure.}`) that must be shared by matching proc or iterator
|
||||
types. Previously, pragmas were parsed but discarded if no parameter list
|
||||
was given.
|
||||
|
||||
This is represented in the AST by an `nnkProcTy`/`nnkIteratorTy` node with
|
||||
an `nnkEmpty` node in the place of the `nnkFormalParams` node, and the pragma
|
||||
node in the same place as in a concrete `proc` or `iterator` type node. This
|
||||
state of the AST may be unexpected to existing code, both due to the
|
||||
replacement of the `nnkFormalParams` node as well as having child nodes
|
||||
unlike other type class AST.
|
||||
|
||||
- Signed integer literals in `set` literals now default to a range type of
|
||||
`0..255` instead of `0..65535` (the maximum size of sets).
|
||||
|
||||
- `case` statements with `else` branches put before `elif`/`of` branches in macros
|
||||
are rejected with "invalid order of case branches".
|
||||
|
||||
- Destructors now default to `.raises: []` (i.e. destructors must not raise
|
||||
unlisted exceptions) and explicitly raising destructors are implementation
|
||||
defined behavior.
|
||||
|
||||
- The very old, undocumented `deprecated` pragma statement syntax for
|
||||
deprecated aliases is now a no-op. The regular deprecated pragma syntax is
|
||||
generally sufficient instead.
|
||||
|
||||
```nim
|
||||
# now does nothing:
|
||||
{.deprecated: [OldName: NewName].}
|
||||
|
||||
# instead use:
|
||||
type OldName* {.deprecated: "use NewName instead".} = NewName
|
||||
const oldName* {.deprecated: "use newName instead".} = newName
|
||||
```
|
||||
|
||||
`defined(nimalias)` can be used to check for versions when this syntax was
|
||||
available; however since code that used this syntax is usually very old,
|
||||
these deprecated aliases are likely not used anymore and it may make sense
|
||||
to simply remove these statements.
|
||||
|
||||
- `getProgramResult` and `setProgramResult` in `std/exitprocs` are no longer
|
||||
declared when they are not available on the backend. Previously it would call
|
||||
`doAssert false` at runtime despite the condition being checkable at compile-time.
|
||||
|
||||
- Custom destructors now supports non-var parameters, e.g. ``proc `=destroy`[T: object](x: T)`` is valid. ``proc `=destroy`[T: object](x: var T)`` is deprecated.
|
||||
|
||||
- Relative imports will not resolve to searched paths anymore, e.g. `import ./tables` now reports an error properly.
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
[//]: # "Changes:"
|
||||
- OpenSSL 3 is now supported.
|
||||
- `macros.parseExpr` and `macros.parseStmt` now accept an optional
|
||||
`filename` argument for more informative errors.
|
||||
- The `colors` module is expanded with missing colors from the CSS color standard.
|
||||
`colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard.
|
||||
- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)).
|
||||
- The `md5` module now works at compile time and in JavaScript.
|
||||
- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef`, to support `const` tables.
|
||||
- `strutils.find` now uses and defaults to `last = -1` for whole string searches,
|
||||
making limiting it to just the first char (`last = 0`) valid.
|
||||
- `strutils.split` and `strutils.rsplit` now return the source string as a single element for an empty separator.
|
||||
- `random.rand` now works with `Ordinal`s.
|
||||
- Undeprecated `os.isvalidfilename`.
|
||||
- `std/oids` now uses `int64` to store time internally (before, it was int32).
|
||||
- `std/uri.Uri` dollar (`$`) improved, precalculates the `string` result length from the `Uri`.
|
||||
- `std/uri.Uri.isIpv6` is now exported.
|
||||
- `std/logging.ConsoleLogger` and `FileLogger` now have a `flushThreshold` attribute to set what log message levels are automatically flushed. For Nim v1 use `-d:nimFlushAllLogs` to automatically flush all message levels. Flushing all logs is the default behavior for Nim v2.
|
||||
|
||||
|
||||
- `std/jsfetch.newFetchOptions` now has default values for all parameters.
|
||||
- `std/jsformdata` now accepts the `Blob` data type.
|
||||
|
||||
- `std/sharedlist` and `std/sharedtables` are now deprecated, see [RFC #433](https://github.com/nim-lang/RFCs/issues/433).
|
||||
|
||||
- There is a new compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove the dependency on the Linux `getrandom` syscall.
|
||||
|
||||
This compile flag only affects Linux builds and is necessary if either compiling on a Linux kernel version < 3.17, or if code built will be executing on kernel < 3.17.
|
||||
|
||||
On Linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since Linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall.
|
||||
|
||||
When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be:
|
||||
```sh
|
||||
$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details
|
||||
$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8
|
||||
$ sh build.sh # per unix install instructions
|
||||
$ bin/nim c koch # per unix install instructions
|
||||
$ ./koch boot -d:release # per unix install instructions
|
||||
$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall
|
||||
```
|
||||
|
||||
This is necessary to pass when building Nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for the stdlib (`sysrand` in particular).
|
||||
|
||||
[//]: # "Additions:"
|
||||
- Added ISO 8601 week date utilities in `times`:
|
||||
- Added `IsoWeekRange`, a range type for weeks in a week-based year.
|
||||
- Added `IsoYear`, a distinct type for a week-based year in contrast to a regular year.
|
||||
- Added an `initDateTime` overload to create a `DateTime` from an ISO week date.
|
||||
- Added `getIsoWeekAndYear` to get an ISO week number and week-based year from a datetime.
|
||||
- Added `getIsoWeeksInYear` to return the number of weeks in a week-based year.
|
||||
- Added new modules which were previously part of `std/os`:
|
||||
- Added `std/oserrors` for OS error reporting.
|
||||
- Added `std/envvars` for environment variables handling.
|
||||
- Added `std/cmdline` for reading command line parameters.
|
||||
- Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`.
|
||||
- Added `sep` parameter in `std/uri` to specify the query separator.
|
||||
- Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`.
|
||||
- Added `complex.sgn` for obtaining the phase of complex numbers.
|
||||
- Added `insertAdjacentText`, `insertAdjacentElement`, `insertAdjacentHTML`,
|
||||
`after`, `before`, `closest`, `append`, `hasAttributeNS`, `removeAttributeNS`,
|
||||
`hasPointerCapture`, `releasePointerCapture`, `requestPointerLock`,
|
||||
`replaceChildren`, `replaceWith`, `scrollIntoViewIfNeeded`, `setHTML`,
|
||||
`toggleAttribute`, and `matches` to `std/dom`.
|
||||
- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices).
|
||||
- Added `capacity` for `string` and `seq` to return the current capacity, see [RFC #460](https://github.com/nim-lang/RFCs/issues/460).
|
||||
- Added `openArray[char]` overloads for `std/parseutils` and `std/unicode`, allowing for more code reuse.
|
||||
- Added a `safe` parameter to `base64.encodeMime`.
|
||||
- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes.
|
||||
- Added `minmax` to `sequtils`, as a more efficient `(min(_), max(_))` over sequences.
|
||||
- `std/jscore` for the JavaScript target:
|
||||
+ Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift)
|
||||
and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask).
|
||||
+ Added `toDateString`, `toISOString`, `toJSON`, `toTimeString`, `toUTCString` converters for `DateTime`.
|
||||
- Added `BackwardsIndex` overload for `CacheSeq`.
|
||||
- Added support for nested `with` blocks in `std/with`.
|
||||
- Added `ensureMove` to the system module. It ensures that the passed argument is moved, otherwise an error is given at the compile time.
|
||||
|
||||
|
||||
[//]: # "Deprecations:"
|
||||
- Deprecated `selfExe` for Nimscript.
|
||||
- Deprecated `std/base64.encode` for collections of arbitrary integer element type.
|
||||
Now only `byte` and `char` are supported.
|
||||
|
||||
[//]: # "Removals:"
|
||||
- Removed deprecated module `parseopt2`.
|
||||
- Removed deprecated module `sharedstrings`.
|
||||
- Removed deprecated module `dom_extensions`.
|
||||
- Removed deprecated module `LockFreeHash`.
|
||||
- Removed deprecated module `events`.
|
||||
- Removed deprecated `oids.oidToString`.
|
||||
- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`.
|
||||
- Removed deprecated `jsre.test` and `jsre.toString`.
|
||||
- Removed deprecated `math.c_frexp`.
|
||||
- Removed deprecated `` httpcore.`==` ``.
|
||||
- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that take wrong argument types.
|
||||
- Removed deprecated `osproc.poDemon`, symbol with typo.
|
||||
- Removed deprecated `tables.rightSize`.
|
||||
|
||||
|
||||
- Removed deprecated `posix.CLONE_STOPPED`.
|
||||
|
||||
|
||||
## Language changes
|
||||
|
||||
- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) now supports the definition of forbidden tags by the `.forbids` pragma
|
||||
which can be used to disable certain effects in proc types.
|
||||
- [Case statement macros](https://nim-lang.github.io/Nim/manual.html#macros-case-statement-macros) are no longer experimental,
|
||||
meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them.
|
||||
- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed
|
||||
for the right-hand side of type definitions in type sections. Previously
|
||||
they would error with "invalid indentation".
|
||||
|
||||
- Compile-time define changes:
|
||||
- `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`.
|
||||
In the command line, this is defined as `-d:a.b.c`. Older versions can
|
||||
use backticks as in ``defined(`a.b.c`)`` to access such defines.
|
||||
- [Define pragmas for constants](https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-compileminustime-define-pragmas)
|
||||
now support a string argument for qualified define names.
|
||||
|
||||
```nim
|
||||
# -d:package.FooBar=42
|
||||
const FooBar {.intdefine: "package.FooBar".}: int = 5
|
||||
echo FooBar # 42
|
||||
```
|
||||
|
||||
This was added to help disambiguate similar define names for different packages.
|
||||
In older versions, this could only be achieved with something like the following:
|
||||
|
||||
```nim
|
||||
const FooBar = block:
|
||||
const `package.FooBar` {.intdefine.}: int = 5
|
||||
`package.FooBar`
|
||||
```
|
||||
- A generic `define` pragma for constants has been added that interprets
|
||||
the value of the define based on the type of the constant value.
|
||||
See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-nimdefine-pragma)
|
||||
for a list of supported types.
|
||||
|
||||
- [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes:
|
||||
- Templates now accept macro pragmas.
|
||||
- Macro pragmas for var/let/const sections have been redesigned in a way that works
|
||||
similarly to routine macro pragmas. The new behavior is documented in the
|
||||
[experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#extended-macro-pragmas).
|
||||
- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`,
|
||||
allowing multiple type definitions to be injected in place of the original type definition.
|
||||
|
||||
```nim
|
||||
import macros
|
||||
|
||||
macro multiply(amount: static int, s: untyped): untyped =
|
||||
let name = $s[0].basename
|
||||
result = newNimNode(nnkTypeSection)
|
||||
for i in 1 .. amount:
|
||||
result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2]))
|
||||
|
||||
type
|
||||
Foo = object
|
||||
Bar {.multiply: 3.} = object
|
||||
x, y, z: int
|
||||
Baz = object
|
||||
# becomes
|
||||
type
|
||||
Foo = object
|
||||
Bar1 = object
|
||||
x, y, z: int
|
||||
Bar2 = object
|
||||
x, y, z: int
|
||||
Bar3 = object
|
||||
x, y, z: int
|
||||
Baz = object
|
||||
```
|
||||
|
||||
- A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference)
|
||||
has been implemented for a variety of basic cases. For example, code like the following now compiles:
|
||||
|
||||
```nim
|
||||
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
|
||||
```
|
||||
|
||||
- `cstring` is now accepted as a selector in `case` statements, removing the
|
||||
need to convert to `string`. On the JS backend, this is translated directly
|
||||
to a `switch` statement.
|
||||
|
||||
- Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters).
|
||||
- Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`.
|
||||
|
||||
- IBM Z architecture and macOS m1 arm64 architecture are supported.
|
||||
|
||||
- `=wasMoved` can now be overridden by users.
|
||||
|
||||
- There is a new pragma called [quirky](https://nim-lang.github.io/Nim/manual_experimental.html#quirky-routines) that can be used to affect the code
|
||||
generation of goto based exception handling. It can improve the produced code size but its effects can be subtle so use it with care.
|
||||
|
||||
- Tuple unpacking for variables is now treated as syntax sugar that directly
|
||||
expands into multiple assignments. Along with this, tuple unpacking for
|
||||
variables can now be nested.
|
||||
|
||||
```nim
|
||||
proc returnsNestedTuple(): (int, (int, int), int, int) = (4, (5, 7), 2, 3)
|
||||
|
||||
let (x, (_, y), _, z) = returnsNestedTuple()
|
||||
# roughly becomes
|
||||
let
|
||||
tmpTup1 = returnsNestedTuple()
|
||||
x = tmpTup1[0]
|
||||
tmpTup2 = tmpTup1[1]
|
||||
y = tmpTup2[1]
|
||||
z = tmpTup1[3]
|
||||
```
|
||||
|
||||
As a result `nnkVarTuple` nodes in variable sections will no longer be
|
||||
reflected in `typed` AST.
|
||||
|
||||
- C++ interoperability:
|
||||
- New [`virtual`](https://nim-lang.github.io/Nim/manual_experimental.html#virtual-pragma) pragma added.
|
||||
- Improvements to [`constructor`](https://nim-lang.github.io/Nim/manual_experimental.html#constructor-pragma) pragma.
|
||||
|
||||
## Compiler changes
|
||||
|
||||
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
|
||||
reality better. (Nim moved away from all techniques based on "tracing".)
|
||||
|
||||
- Defines the `gcRefc` symbol which allows writing specific code for the refc GC.
|
||||
|
||||
- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`,
|
||||
without requiring `-d:nimVersion140` which is now a noop.
|
||||
|
||||
- `--styleCheck`, `--hintAsError` and `--warningAsError` now only apply to the current package.
|
||||
|
||||
- The switch `--nimMainPrefix:prefix` has been added to add a prefix to the names of `NimMain` and
|
||||
related functions produced on the backend. This prevents conflicts with other Nim
|
||||
static libraries.
|
||||
|
||||
- When compiling for release, the flag `-fno-math-errno` is used for GCC.
|
||||
- Removed deprecated `LineTooLong` hint.
|
||||
- Line numbers and file names of source files work correctly inside templates for JavaScript targets.
|
||||
|
||||
- Removed support for LCC (Local C), Pelles C, Digital Mars and Watcom compilers.
|
||||
|
||||
|
||||
## Docgen
|
||||
|
||||
- `Markdown` is now the default markup language of doc comments (instead
|
||||
of the legacy `RstMarkdown` mode). In this release we begin to separate
|
||||
RST and Markdown features to better follow specification of each
|
||||
language, with the focus on Markdown development.
|
||||
See also [the docs](https://nim-lang.github.io/Nim/markdown_rst.html).
|
||||
|
||||
* Added a `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to
|
||||
select the markup language mode in the doc comments of the current `.nim`
|
||||
file for processing by `nim doc`:
|
||||
|
||||
1. `Markdown` (default) is basically CommonMark (standard Markdown) +
|
||||
some Pandoc Markdown features + some RST features that are missing
|
||||
in our current implementation of CommonMark and Pandoc Markdown.
|
||||
2. `RST` closely follows the RST spec with few additional Nim features.
|
||||
3. `RstMarkdown` is a maximum mix of RST and Markdown features, which
|
||||
is kept for the sake of compatibility and ease of migration.
|
||||
|
||||
* Added separate `md2html` and `rst2html` commands for processing
|
||||
standalone `.md` and `.rst` files respectively (and also `md2tex`/`rst2tex`).
|
||||
|
||||
- Added Pandoc Markdown bracket syntax `[...]` for making anchor-less links.
|
||||
- Docgen now supports concise syntax for referencing Nim symbols:
|
||||
instead of specifying HTML anchors directly one can use original
|
||||
Nim symbol declarations (adding the aforementioned link brackets
|
||||
`[...]` around them).
|
||||
* To use this feature across modules, a new `importdoc` directive was added.
|
||||
Using this feature for referencing also helps to ensure that links
|
||||
(inside one module or the whole project) are not broken.
|
||||
- Added support for RST & Markdown quote blocks (blocks starting with `>`).
|
||||
- Added a popular Markdown definition lists extension.
|
||||
- Added Markdown indented code blocks (blocks indented by >= 4 spaces).
|
||||
- Added syntax for additional parameters to Markdown code blocks:
|
||||
|
||||
```nim test="nim c $1"
|
||||
...
|
||||
```
|
||||
|
||||
## Tool changes
|
||||
|
||||
- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs` before). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop.
|
||||
- nimgrep added the option `--inContext` (and `--notInContext`), which
|
||||
allows to filter only matches with the context block containing a given pattern.
|
||||
- nimgrep: names of options containing "include/exclude" are deprecated,
|
||||
e.g. instead of `--includeFile` and `--excludeFile` we have
|
||||
`--filename` and `--notFilename` respectively.
|
||||
Also the semantics are now consistent for such positive/negative filters.
|
||||
- koch now supports the `--skipIntegrityCheck` option. The command `koch --skipIntegrityCheck boot -d:release` always builds the compiler twice.
|
||||
12
changelogs/changelog_2_2_0.md
Normal file
12
changelogs/changelog_2_2_0.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# v2.2.0 - 2023-mm-dd
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
## Language changes
|
||||
|
||||
## Compiler changes
|
||||
|
||||
## Tool changes
|
||||
|
||||
@@ -3,7 +3,7 @@ import std/[strutils, os, osproc, parseutils, strformat]
|
||||
|
||||
proc main() =
|
||||
var msg = ""
|
||||
const cmd = "./koch boot --gc:orc -d:release"
|
||||
const cmd = "./koch boot --mm:orc -d:release"
|
||||
|
||||
let (output, exitCode) = execCmdEx(cmd)
|
||||
|
||||
|
||||
@@ -58,7 +58,11 @@ _nimNumCpu(){
|
||||
# FreeBSD | macOS: $(sysctl -n hw.ncpu)
|
||||
# OpenBSD: $(sysctl -n hw.ncpuonline)
|
||||
# windows: $NUMBER_OF_PROCESSORS ?
|
||||
echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1)
|
||||
if env | grep -q '^NIMCORES='; then
|
||||
echo $NIMCORES
|
||||
else
|
||||
echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1)
|
||||
fi
|
||||
}
|
||||
|
||||
_nimBuildCsourcesIfNeeded(){
|
||||
|
||||
@@ -74,7 +74,7 @@ proc aliases*(obj, field: PNode): AliasKind =
|
||||
# x[i] -> x[i]: maybe; Further analysis could make this return true when i is a runtime-constant
|
||||
# x[i] -> x[j]: maybe; also returns maybe if only one of i or j is a compiletime-constant
|
||||
template collectImportantNodes(result, n) =
|
||||
var result: seq[PNode]
|
||||
var result: seq[PNode] = @[]
|
||||
var n = n
|
||||
while true:
|
||||
case n.kind
|
||||
|
||||
@@ -114,6 +114,8 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
# use expensive type check:
|
||||
if isPartOf(a.sym.typ, b.sym.typ) != arNo:
|
||||
result = arMaybe
|
||||
else:
|
||||
result = arNo
|
||||
of nkBracketExpr:
|
||||
result = isPartOf(a[0], b[0])
|
||||
if a.len >= 2 and b.len >= 2:
|
||||
@@ -149,7 +151,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
result = isPartOf(a[1], b[1])
|
||||
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
||||
result = isPartOf(a[0], b[0])
|
||||
else: discard
|
||||
else: result = arNo
|
||||
# Calls return a new location, so a default of ``arNo`` is fine.
|
||||
else:
|
||||
# go down recursively; this is quite demanding:
|
||||
@@ -165,6 +167,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
|
||||
of DerefKinds:
|
||||
# a* !<| b[] iff
|
||||
result = arNo
|
||||
if isPartOf(a.typ, b.typ) != arNo:
|
||||
result = isPartOf(a, b[0])
|
||||
if result == arNo: result = arMaybe
|
||||
@@ -186,7 +189,9 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
if isPartOf(a.typ, b.typ) != arNo:
|
||||
result = isPartOf(a[0], b)
|
||||
if result == arNo: result = arMaybe
|
||||
else: discard
|
||||
else:
|
||||
result = arNo
|
||||
else: result = arNo
|
||||
of nkObjConstr:
|
||||
result = arNo
|
||||
for i in 1..<b.len:
|
||||
@@ -204,4 +209,6 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
of nkBracket:
|
||||
if b.len > 0:
|
||||
result = isPartOf(a, b[0])
|
||||
else: discard
|
||||
else:
|
||||
result = arNo
|
||||
else: result = arNo
|
||||
|
||||
188
compiler/ast.nim
188
compiler/ast.nim
@@ -231,7 +231,7 @@ type
|
||||
TNodeKinds* = set[TNodeKind]
|
||||
|
||||
type
|
||||
TSymFlag* = enum # 49 flags!
|
||||
TSymFlag* = enum # 52 flags!
|
||||
sfUsed, # read access of sym (for warnings) or simply used
|
||||
sfExported, # symbol is exported from module
|
||||
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
||||
@@ -283,7 +283,7 @@ type
|
||||
sfNamedParamCall, # symbol needs named parameter call syntax in target
|
||||
# language; for interfacing with Objective C
|
||||
sfDiscardable, # returned value may be discarded implicitly
|
||||
sfOverriden, # proc is overridden
|
||||
sfOverridden, # proc is overridden
|
||||
sfCallsite # A flag for template symbols to tell the
|
||||
# compiler it should use line information from
|
||||
# the calling side of the macro, not from the
|
||||
@@ -303,6 +303,8 @@ type
|
||||
sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally'
|
||||
sfSingleUsedTemp # For temporaries that we know will only be used once
|
||||
sfNoalias # 'noalias' annotation, means C's 'restrict'
|
||||
# for templates and macros, means cannot be called
|
||||
# as a lone symbol (cannot use alias syntax)
|
||||
sfEffectsDelayed # an 'effectsDelayed' parameter
|
||||
sfGeneratedType # A anonymous generic type that is generated by the compiler for
|
||||
# objects that do not have generic parameters in case one of the
|
||||
@@ -310,6 +312,11 @@ type
|
||||
#
|
||||
# This is disallowed but can cause the typechecking to go into
|
||||
# an infinite loop, this flag is used as a sentinel to stop it.
|
||||
sfVirtual # proc is a C++ virtual function
|
||||
sfByCopy # param is marked as pass bycopy
|
||||
sfMember # proc is a C++ member of a type
|
||||
sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl
|
||||
sfToplevelDecl
|
||||
|
||||
TSymFlags* = set[TSymFlag]
|
||||
|
||||
@@ -335,13 +342,14 @@ const
|
||||
|
||||
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
|
||||
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
|
||||
sfExperimental* = sfOverriden # module uses the .experimental switch
|
||||
sfGoto* = sfOverriden # var is used for 'goto' code generation
|
||||
sfExperimental* = sfOverridden # module uses the .experimental switch
|
||||
sfGoto* = sfOverridden # var is used for 'goto' code generation
|
||||
sfWrittenTo* = sfBorrow # param is assigned to
|
||||
# currently unimplemented
|
||||
sfBase* = sfDiscriminant
|
||||
sfCustomPragma* = sfRegister # symbol is custom pragma template
|
||||
sfTemplateRedefinition* = sfExportc # symbol is a redefinition of an earlier template
|
||||
sfCppMember* = { sfVirtual, sfMember, sfConstructor } # proc is a C++ member, meaning it will be attached to the type definition
|
||||
|
||||
const
|
||||
# getting ready for the future expr/stmt merge
|
||||
@@ -510,10 +518,10 @@ type
|
||||
nfLastRead # this node is a last read
|
||||
nfFirstWrite # this node is a first write
|
||||
nfHasComment # node has a comment
|
||||
nfUseDefaultField # node has a default value (object constructor)
|
||||
nfSkipFieldChecking # node skips field visable checking
|
||||
|
||||
TNodeFlags* = set[TNodeFlag]
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 46)
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47)
|
||||
tfVarargs, # procedure has C styled varargs
|
||||
# tyArray type represeting a varargs list
|
||||
tfNoSideEffect, # procedure type does not allow side effects
|
||||
@@ -583,6 +591,8 @@ type
|
||||
tfIsConstructor
|
||||
tfEffectSystemWorkaround
|
||||
tfIsOutParam
|
||||
tfSendable
|
||||
tfImplicitStatic
|
||||
|
||||
TTypeFlags* = set[TTypeFlag]
|
||||
|
||||
@@ -618,13 +628,12 @@ type
|
||||
# file (it is loaded on demand, which may
|
||||
# mean: never)
|
||||
skPackage, # symbol is a package (used for canonicalization)
|
||||
skAlias # an alias (needs to be resolved immediately)
|
||||
TSymKinds* = set[TSymKind]
|
||||
|
||||
const
|
||||
routineKinds* = {skProc, skFunc, skMethod, skIterator,
|
||||
skConverter, skMacro, skTemplate}
|
||||
ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub, skAlias} + routineKinds
|
||||
ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub} + routineKinds
|
||||
|
||||
tfUnion* = tfNoSideEffect
|
||||
tfGcSafe* = tfThread
|
||||
@@ -633,7 +642,7 @@ const
|
||||
skError* = skUnknown
|
||||
|
||||
var
|
||||
eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr, tfGcSafe, tfNoSideEffect, tfIsOutParam}
|
||||
eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr, tfGcSafe, tfNoSideEffect, tfIsOutParam, tfSendable}
|
||||
## type flags that are essential for type equality.
|
||||
## This is now a variable because for emulation of version:1.0 we
|
||||
## might exclude {tfGcSafe, tfNoSideEffect}.
|
||||
@@ -685,7 +694,7 @@ type
|
||||
mIsPartOf, mAstToStr, mParallel,
|
||||
mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
|
||||
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
||||
mMove, mWasMoved, mDestroy, mTrace,
|
||||
mMove, mEnsureMove, mWasMoved, mDup, mDestroy, mTrace,
|
||||
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
|
||||
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
|
||||
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
|
||||
@@ -706,13 +715,13 @@ type
|
||||
mNctPut, mNctLen, mNctGet, mNctHasNext, mNctNext,
|
||||
|
||||
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
|
||||
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
|
||||
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetStrVal, mNLineInfo,
|
||||
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mNSigHash, mNSizeOf,
|
||||
mNBindSym, mNCallSite,
|
||||
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym,
|
||||
mNHint, mNWarning, mNError,
|
||||
mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2,
|
||||
mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples,
|
||||
mNimvm, mIntDefine, mStrDefine, mBoolDefine, mGenericDefine, mRunnableExamples,
|
||||
mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
|
||||
mSymIsInstantiationOf, mNodeId, mPrivateAccess, mZeroDefault
|
||||
|
||||
@@ -796,6 +805,8 @@ type
|
||||
ident*: PIdent
|
||||
else:
|
||||
sons*: TNodeSeq
|
||||
when defined(nimsuggest):
|
||||
endInfo*: TLineInfo
|
||||
|
||||
TStrTable* = object # a table[PIdent] of PSym
|
||||
counter*: int
|
||||
@@ -816,9 +827,6 @@ type
|
||||
locOther # location is something other
|
||||
TLocFlag* = enum
|
||||
lfIndirect, # backend introduced a pointer
|
||||
lfFullExternalName, # only used when 'conf.cmd == cmdNimfix': Indicates
|
||||
# that the symbol has been imported via 'importc: "fullname"' and
|
||||
# no format string.
|
||||
lfNoDeepCopy, # no need for a deep copy
|
||||
lfNoDecl, # do not declare it in C
|
||||
lfDynamicLib, # link symbol to dynamic library
|
||||
@@ -853,7 +861,7 @@ type
|
||||
# keep in sync with PackedLib
|
||||
kind*: TLibKind
|
||||
generated*: bool # needed for the backends:
|
||||
isOverriden*: bool
|
||||
isOverridden*: bool
|
||||
name*: Rope
|
||||
path*: PNode # can be a string literal!
|
||||
|
||||
@@ -892,6 +900,8 @@ type
|
||||
typ*: PType
|
||||
name*: PIdent
|
||||
info*: TLineInfo
|
||||
when defined(nimsuggest):
|
||||
endInfo*: TLineInfo
|
||||
owner*: PSym
|
||||
flags*: TSymFlags
|
||||
ast*: PNode # syntax tree of proc, iterator, etc.:
|
||||
@@ -913,7 +923,9 @@ type
|
||||
# for modules, an unique index corresponding
|
||||
# to the module's fileIdx
|
||||
# for variables a slot index for the evaluator
|
||||
offset*: int # offset of record field
|
||||
offset*: int32 # offset of record field
|
||||
disamb*: int32 # disambiguation number; the basic idea is that
|
||||
# `<procname>__<module>_<disamb>`
|
||||
loc*: TLoc
|
||||
annex*: PLib # additional fields (seldom used, so we use a
|
||||
# reference to another object to save space)
|
||||
@@ -921,7 +933,7 @@ type
|
||||
cname*: string # resolved C declaration name in importc decl, e.g.:
|
||||
# proc fun() {.importc: "$1aux".} => cname = funaux
|
||||
constraint*: PNode # additional constraints like 'lit|result'; also
|
||||
# misused for the codegenDecl pragma in the hope
|
||||
# misused for the codegenDecl and virtual pragmas in the hope
|
||||
# it won't cause problems
|
||||
# for skModule the string literal to output for
|
||||
# deprecated modules.
|
||||
@@ -931,8 +943,10 @@ type
|
||||
TTypeSeq* = seq[PType]
|
||||
|
||||
TTypeAttachedOp* = enum ## as usual, order is important here
|
||||
attachedWasMoved,
|
||||
attachedDestructor,
|
||||
attachedAsgn,
|
||||
attachedDup,
|
||||
attachedSink,
|
||||
attachedTrace,
|
||||
attachedDeepCopy
|
||||
@@ -945,7 +959,7 @@ type
|
||||
kind*: TTypeKind # kind of type
|
||||
callConv*: TCallingConvention # for procs
|
||||
flags*: TTypeFlags # flags of the type
|
||||
sons*: TTypeSeq # base types, etc.
|
||||
sons: TTypeSeq # base types, etc.
|
||||
n*: PNode # node for types:
|
||||
# for range types a nkRange node
|
||||
# for record types a nkRecord node
|
||||
@@ -1026,6 +1040,8 @@ proc comment*(n: PNode): string =
|
||||
if nfHasComment in n.flags and not gconfig.useIc:
|
||||
# IC doesn't track comments, see `packed_ast`, so this could fail
|
||||
result = gconfig.comments[n.nodeId]
|
||||
else:
|
||||
result = ""
|
||||
|
||||
proc `comment=`*(n: PNode, a: string) =
|
||||
let id = n.nodeId
|
||||
@@ -1076,7 +1092,7 @@ const
|
||||
nfIsRef, nfIsPtr, nfPreventCg, nfLL,
|
||||
nfFromTemplate, nfDefaultRefsParam,
|
||||
nfExecuteOnReload, nfLastRead,
|
||||
nfFirstWrite, nfUseDefaultField}
|
||||
nfFirstWrite, nfSkipFieldChecking}
|
||||
namePos* = 0
|
||||
patternPos* = 1 # empty except for term rewriting macros
|
||||
genericParamsPos* = 2
|
||||
@@ -1116,11 +1132,10 @@ const
|
||||
|
||||
proc getPIdent*(a: PNode): PIdent {.inline.} =
|
||||
## Returns underlying `PIdent` for `{nkSym, nkIdent}`, or `nil`.
|
||||
# xxx consider whether also returning the 1st ident for {nkOpenSymChoice, nkClosedSymChoice}
|
||||
# which may simplify code.
|
||||
case a.kind
|
||||
of nkSym: a.sym.name
|
||||
of nkIdent: a.ident
|
||||
of nkOpenSymChoice, nkClosedSymChoice: a.sons[0].sym.name
|
||||
else: nil
|
||||
|
||||
const
|
||||
@@ -1136,13 +1151,17 @@ type
|
||||
symId*: int32
|
||||
typeId*: int32
|
||||
sealed*: bool
|
||||
disambTable*: CountTable[PIdent]
|
||||
|
||||
const
|
||||
PackageModuleId* = -3'i32
|
||||
|
||||
proc idGeneratorFromModule*(m: PSym): IdGenerator =
|
||||
assert m.kind == skModule
|
||||
result = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0)
|
||||
result = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0, disambTable: initCountTable[PIdent]())
|
||||
|
||||
proc idGeneratorForPackage*(nextIdWillBe: int32): IdGenerator =
|
||||
result = IdGenerator(module: PackageModuleId, symId: nextIdWillBe - 1'i32, typeId: 0, disambTable: initCountTable[PIdent]())
|
||||
|
||||
proc nextSymId*(x: IdGenerator): ItemId {.inline.} =
|
||||
assert(not x.sealed)
|
||||
@@ -1209,6 +1228,7 @@ proc getDeclPragma*(n: PNode): PNode =
|
||||
case n.kind
|
||||
of routineDefs:
|
||||
if n[pragmasPos].kind != nkEmpty: result = n[pragmasPos]
|
||||
else: result = nil
|
||||
of nkTypeDef:
|
||||
#[
|
||||
type F3*{.deprecated: "x3".} = int
|
||||
@@ -1228,6 +1248,8 @@ proc getDeclPragma*(n: PNode): PNode =
|
||||
]#
|
||||
if n[0].kind == nkPragmaExpr:
|
||||
result = n[0][1]
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
# support as needed for `nkIdentDefs` etc.
|
||||
result = nil
|
||||
@@ -1243,6 +1265,12 @@ proc extractPragma*(s: PSym): PNode =
|
||||
if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1:
|
||||
# s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma]
|
||||
result = s.ast[0][1]
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
result = nil
|
||||
assert result == nil or result.kind == nkPragma
|
||||
|
||||
proc skipPragmaExpr*(n: PNode): PNode =
|
||||
@@ -1334,11 +1362,15 @@ when false:
|
||||
echo k
|
||||
echo v
|
||||
|
||||
proc newSym*(symKind: TSymKind, name: PIdent, id: ItemId, owner: PSym,
|
||||
proc newSym*(symKind: TSymKind, name: PIdent, idgen: IdGenerator; owner: PSym,
|
||||
info: TLineInfo; options: TOptions = {}): PSym =
|
||||
# generates a symbol and initializes the hash field too
|
||||
assert not name.isNil
|
||||
let id = nextSymId idgen
|
||||
result = PSym(name: name, kind: symKind, flags: {}, info: info, itemId: id,
|
||||
options: options, owner: owner, offset: defaultOffset)
|
||||
options: options, owner: owner, offset: defaultOffset,
|
||||
disamb: getOrDefault(idgen.disambTable, name).int32)
|
||||
idgen.disambTable.inc name
|
||||
when false:
|
||||
if id.module == 48 and id.item == 39:
|
||||
writeStackTrace()
|
||||
@@ -1468,7 +1500,7 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
|
||||
result = newNode(nkIntLit)
|
||||
of tyStatic: # that's a pre-existing bug, will fix in another PR
|
||||
result = newNode(nkIntLit)
|
||||
else: doAssert false, $kind
|
||||
else: raiseAssert $kind
|
||||
result.intVal = intVal
|
||||
result.typ = typ
|
||||
|
||||
@@ -1498,7 +1530,7 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
|
||||
|
||||
const
|
||||
AttachedOpToStr*: array[TTypeAttachedOp, string] = [
|
||||
"=destroy", "=copy", "=sink", "=trace", "=deepcopy"]
|
||||
"=wasMoved", "=destroy", "=copy", "=dup", "=sink", "=trace", "=deepcopy"]
|
||||
|
||||
proc `$`*(s: PSym): string =
|
||||
if s != nil:
|
||||
@@ -1506,15 +1538,31 @@ proc `$`*(s: PSym): string =
|
||||
else:
|
||||
result = "<nil>"
|
||||
|
||||
proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType =
|
||||
iterator items*(t: PType): PType =
|
||||
for i in 0..<t.sons.len: yield t.sons[i]
|
||||
|
||||
iterator pairs*(n: PType): tuple[i: int, n: PType] =
|
||||
for i in 0..<n.sons.len: yield (i, n.sons[i])
|
||||
|
||||
proc newType*(kind: TTypeKind, id: ItemId; owner: PSym, sons: seq[PType] = @[]): PType =
|
||||
result = PType(kind: kind, owner: owner, size: defaultSize,
|
||||
align: defaultAlignment, itemId: id,
|
||||
uniqueId: id)
|
||||
uniqueId: id, sons: sons)
|
||||
when false:
|
||||
if result.itemId.module == 55 and result.itemId.item == 2:
|
||||
echo "KNID ", kind
|
||||
writeStackTrace()
|
||||
|
||||
template newType*(kind: TTypeKind, id: ItemId; owner: PSym, parent: PType): PType =
|
||||
newType(kind, id, owner, parent.sons)
|
||||
|
||||
proc newType*(prev: PType, sons: seq[PType]): PType =
|
||||
result = prev
|
||||
result.sons = sons
|
||||
|
||||
proc addSon*(father, son: PType) =
|
||||
# todo fixme: in IC, `son` might be nil
|
||||
father.sons.add(son)
|
||||
|
||||
proc mergeLoc(a: var TLoc, b: TLoc) =
|
||||
if a.k == low(typeof(a.k)): a.k = b.k
|
||||
@@ -1552,8 +1600,8 @@ proc copyType*(t: PType, id: ItemId, owner: PSym): PType =
|
||||
proc exactReplica*(t: PType): PType =
|
||||
result = copyType(t, t.itemId, t.owner)
|
||||
|
||||
proc copySym*(s: PSym; id: ItemId): PSym =
|
||||
result = newSym(s.kind, s.name, id, s.owner, s.info, s.options)
|
||||
proc copySym*(s: PSym; idgen: IdGenerator): PSym =
|
||||
result = newSym(s.kind, s.name, idgen, s.owner, s.info, s.options)
|
||||
#result.ast = nil # BUGFIX; was: s.ast which made problems
|
||||
result.typ = s.typ
|
||||
result.flags = s.flags
|
||||
@@ -1568,9 +1616,9 @@ proc copySym*(s: PSym; id: ItemId): PSym =
|
||||
result.bitsize = s.bitsize
|
||||
result.alignment = s.alignment
|
||||
|
||||
proc createModuleAlias*(s: PSym, id: ItemId, newIdent: PIdent, info: TLineInfo;
|
||||
proc createModuleAlias*(s: PSym, idgen: IdGenerator, newIdent: PIdent, info: TLineInfo;
|
||||
options: TOptions): PSym =
|
||||
result = newSym(s.kind, newIdent, id, s.owner, info, options)
|
||||
result = newSym(s.kind, newIdent, idgen, s.owner, info, options)
|
||||
# keep ID!
|
||||
result.ast = s.ast
|
||||
#result.id = s.id # XXX figure out what to do with the ID.
|
||||
@@ -1580,19 +1628,13 @@ proc createModuleAlias*(s: PSym, id: ItemId, newIdent: PIdent, info: TLineInfo;
|
||||
result.loc = s.loc
|
||||
result.annex = s.annex
|
||||
|
||||
proc initStrTable*(x: var TStrTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
proc initStrTable*(): TStrTable =
|
||||
result = TStrTable(counter: 0)
|
||||
newSeq(result.data, StartSize)
|
||||
|
||||
proc newStrTable*: TStrTable =
|
||||
initStrTable(result)
|
||||
|
||||
proc initIdTable*(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc newIdTable*: TIdTable =
|
||||
initIdTable(result)
|
||||
proc initIdTable*(): TIdTable =
|
||||
result = TIdTable(counter: 0)
|
||||
newSeq(result.data, StartSize)
|
||||
|
||||
proc resetIdTable*(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
@@ -1600,17 +1642,17 @@ proc resetIdTable*(x: var TIdTable) =
|
||||
setLen(x.data, 0)
|
||||
setLen(x.data, StartSize)
|
||||
|
||||
proc initObjectSet*(x: var TObjectSet) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
proc initObjectSet*(): TObjectSet =
|
||||
result = TObjectSet(counter: 0)
|
||||
newSeq(result.data, StartSize)
|
||||
|
||||
proc initIdNodeTable*(x: var TIdNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
proc initIdNodeTable*(): TIdNodeTable =
|
||||
result = TIdNodeTable(counter: 0)
|
||||
newSeq(result.data, StartSize)
|
||||
|
||||
proc initNodeTable*(x: var TNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
proc initNodeTable*(): TNodeTable =
|
||||
result = TNodeTable(counter: 0)
|
||||
newSeq(result.data, StartSize)
|
||||
|
||||
proc skipTypes*(t: PType, kinds: TTypeKinds; maxIters: int): PType =
|
||||
result = t
|
||||
@@ -1690,6 +1732,8 @@ proc copyNode*(src: PNode): PNode =
|
||||
of nkIdent: result.ident = src.ident
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else: discard
|
||||
when defined(nimsuggest):
|
||||
result.endInfo = src.endInfo
|
||||
|
||||
template transitionNodeKindCommon(k: TNodeKind) =
|
||||
let obj {.inject.} = n[]
|
||||
@@ -1742,6 +1786,8 @@ template copyNodeImpl(dst, src, processSonsStmt) =
|
||||
if src == nil: return
|
||||
dst = newNode(src.kind)
|
||||
dst.info = src.info
|
||||
when defined(nimsuggest):
|
||||
result.endInfo = src.endInfo
|
||||
dst.typ = src.typ
|
||||
dst.flags = src.flags * PersistentNodeFlags
|
||||
dst.comment = src.comment
|
||||
@@ -1790,6 +1836,7 @@ proc hasNilSon*(n: PNode): bool =
|
||||
result = false
|
||||
|
||||
proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
|
||||
result = false
|
||||
if n == nil: return
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit: result = n.kind in kinds
|
||||
@@ -1906,20 +1953,6 @@ proc isCompileTimeProc*(s: PSym): bool {.inline.} =
|
||||
result = s.kind == skMacro or
|
||||
s.kind in {skProc, skFunc} and sfCompileTime in s.flags
|
||||
|
||||
proc isRunnableExamples*(n: PNode): bool =
|
||||
# Templates and generics don't perform symbol lookups.
|
||||
result = n.kind == nkSym and n.sym.magic == mRunnableExamples or
|
||||
n.kind == nkIdent and n.ident.s == "runnableExamples"
|
||||
|
||||
proc requiredParams*(s: PSym): int =
|
||||
# Returns the number of required params (without default values)
|
||||
# XXX: Perhaps we can store this in the `offset` field of the
|
||||
# symbol instead?
|
||||
for i in 1..<s.typ.len:
|
||||
if s.typ.n[i].sym.ast != nil:
|
||||
return i - 1
|
||||
return s.typ.len - 1
|
||||
|
||||
proc hasPattern*(s: PSym): bool {.inline.} =
|
||||
result = isRoutine(s) and s.ast[patternPos].kind != nkEmpty
|
||||
|
||||
@@ -1993,7 +2026,7 @@ proc toObjectFromRefPtrGeneric*(typ: PType): PType =
|
||||
of tyRef, tyPtr, tyGenericInst, tyGenericInvocation, tyAlias: result = result[0]
|
||||
# automatic dereferencing is deep, refs #18298.
|
||||
else: break
|
||||
assert result.sym != nil
|
||||
# result does not have to be object type
|
||||
|
||||
proc isImportedException*(t: PType; conf: ConfigRef): bool =
|
||||
assert t != nil
|
||||
@@ -2005,6 +2038,8 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
|
||||
|
||||
if base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {}:
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc isInfixAs*(n: PNode): bool =
|
||||
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as"
|
||||
@@ -2015,10 +2050,12 @@ proc skipColon*(n: PNode): PNode =
|
||||
result = n[1]
|
||||
|
||||
proc findUnresolvedStatic*(n: PNode): PNode =
|
||||
# n.typ == nil: see issue #14802
|
||||
if n.kind == nkSym and n.typ != nil and n.typ.kind == tyStatic and n.typ.n == nil:
|
||||
return n
|
||||
|
||||
if n.typ != nil and n.typ.kind == tyTypeDesc:
|
||||
let t = skipTypes(n.typ, {tyTypeDesc})
|
||||
if t.kind == tyGenericParam and t.len == 0:
|
||||
return n
|
||||
for son in n:
|
||||
let n = son.findUnresolvedStatic
|
||||
if n != nil: return n
|
||||
@@ -2047,12 +2084,21 @@ template detailedInfo*(sym: PSym): string =
|
||||
proc isInlineIterator*(typ: PType): bool {.inline.} =
|
||||
typ.kind == tyProc and tfIterator in typ.flags and typ.callConv != ccClosure
|
||||
|
||||
proc isIterator*(typ: PType): bool {.inline.} =
|
||||
typ.kind == tyProc and tfIterator in typ.flags
|
||||
|
||||
proc isClosureIterator*(typ: PType): bool {.inline.} =
|
||||
typ.kind == tyProc and tfIterator in typ.flags and typ.callConv == ccClosure
|
||||
|
||||
proc isClosure*(typ: PType): bool {.inline.} =
|
||||
typ.kind == tyProc and typ.callConv == ccClosure
|
||||
|
||||
proc isNimcall*(s: PSym): bool {.inline.} =
|
||||
s.typ.callConv == ccNimCall
|
||||
|
||||
proc isExplicitCallConv*(s: PSym): bool {.inline.} =
|
||||
tfExplicitCallConv in s.typ.flags
|
||||
|
||||
proc isSinkParam*(s: PSym): bool {.inline.} =
|
||||
s.kind == skParam and (s.typ.kind == tySink or tfHasOwned in s.typ.flags)
|
||||
|
||||
|
||||
@@ -20,9 +20,6 @@ import strutils except addf
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
when not defined(nimHasCursor):
|
||||
{.pragma: cursor.}
|
||||
|
||||
proc hashNode*(p: RootRef): Hash
|
||||
proc treeToYaml*(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
|
||||
# Convert a tree into its YAML representation; this is used by the
|
||||
@@ -112,7 +109,7 @@ type
|
||||
data*: TIIPairSeq
|
||||
|
||||
|
||||
proc initIiTable*(x: var TIITable)
|
||||
proc initIITable*(x: var TIITable)
|
||||
proc iiTableGet*(t: TIITable, key: int): int
|
||||
proc iiTablePut*(t: var TIITable, key, val: int)
|
||||
|
||||
@@ -200,6 +197,7 @@ proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym =
|
||||
result = nil
|
||||
|
||||
proc sameIgnoreBacktickGensymInfo(a, b: string): bool =
|
||||
result = false
|
||||
if a[0] != b[0]: return false
|
||||
var alen = a.len - 1
|
||||
while alen > 0 and a[alen] != '`': dec(alen)
|
||||
@@ -229,10 +227,11 @@ proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym =
|
||||
## Named parameters are special because a named parameter can be
|
||||
## gensym'ed and then they have '\`<number>' suffix that we need to
|
||||
## ignore, see compiler / evaltempl.nim, snippet:
|
||||
## ```
|
||||
## ```nim
|
||||
## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id),
|
||||
## if c.instLines: actual.info else: templ.info)
|
||||
## ```
|
||||
result = nil
|
||||
for i in 1..<list.len:
|
||||
let it = list[i].sym
|
||||
if it.name.id == ident.id or
|
||||
@@ -330,10 +329,12 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
|
||||
maxRecDepth: int): Rope =
|
||||
var sonsRope: Rope
|
||||
if n == nil:
|
||||
result = ""
|
||||
sonsRope = rope("null")
|
||||
elif containsOrIncl(marker, n.id):
|
||||
result = ""
|
||||
sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
|
||||
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
|
||||
strutils.toHex(cast[int](n), sizeof(n) * 2))]
|
||||
else:
|
||||
if n.len > 0:
|
||||
sonsRope = rope("[")
|
||||
@@ -1066,6 +1067,7 @@ proc isAddrNode*(n: PNode): bool =
|
||||
else: false
|
||||
|
||||
proc listSymbolNames*(symbols: openArray[PSym]): string =
|
||||
result = ""
|
||||
for sym in symbols:
|
||||
if result.len > 0:
|
||||
result.add ", "
|
||||
|
||||
25
compiler/backendpragmas.nim
Normal file
25
compiler/backendpragmas.nim
Normal file
@@ -0,0 +1,25 @@
|
||||
import pragmas, options, ast, trees
|
||||
|
||||
proc pushBackendOption(optionsStack: var seq[TOptions], options: var TOptions) =
|
||||
optionsStack.add options
|
||||
|
||||
proc popBackendOption(optionsStack: var seq[TOptions], options: var TOptions) =
|
||||
options = optionsStack[^1]
|
||||
optionsStack.setLen(optionsStack.len-1)
|
||||
|
||||
proc processPushBackendOption*(optionsStack: var seq[TOptions], options: var TOptions,
|
||||
n: PNode, start: int) =
|
||||
pushBackendOption(optionsStack, options)
|
||||
for i in start..<n.len:
|
||||
let it = n[i]
|
||||
if it.kind in nkPragmaCallKinds and it.len == 2 and it[1].kind == nkIntLit:
|
||||
let sw = whichPragma(it[0])
|
||||
let opts = pragmaToOptions(sw)
|
||||
if opts != {}:
|
||||
if it[1].intVal != 0:
|
||||
options.incl opts
|
||||
else:
|
||||
options.excl opts
|
||||
|
||||
template processPopBackendOption*(optionsStack: var seq[TOptions], options: var TOptions) =
|
||||
popBackendOption(optionsStack, options)
|
||||
@@ -87,5 +87,6 @@ const populationCount: array[uint8, uint8] = block:
|
||||
arr
|
||||
|
||||
proc bitSetCard*(x: TBitSet): BiggestInt =
|
||||
result = 0
|
||||
for it in x:
|
||||
result.inc int(populationCount[it])
|
||||
|
||||
@@ -38,6 +38,7 @@ template less(a, b): bool = cmp(a, b) < 0
|
||||
template eq(a, b): bool = cmp(a, b) == 0
|
||||
|
||||
proc getOrDefault*[Key, Val](b: BTree[Key, Val], key: Key): Val =
|
||||
result = default(Val)
|
||||
var x = b.root
|
||||
while x.isInternal:
|
||||
for j in 0..<x.entries:
|
||||
@@ -68,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):
|
||||
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])
|
||||
@@ -91,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):
|
||||
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])
|
||||
|
||||
@@ -46,6 +46,7 @@ proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
|
||||
# cannot analyse the location; assume the worst
|
||||
return true
|
||||
|
||||
result = false
|
||||
if le != nil:
|
||||
for i in 1..<ri.len:
|
||||
let r = ri[i]
|
||||
@@ -87,7 +88,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
|
||||
# Great, we can use 'd':
|
||||
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
|
||||
if d.k == locNone: d = getTemp(p, typ[0], needsInit=true)
|
||||
elif d.k notin {locTemp} and not hasNoInit(ri):
|
||||
# reset before pass as 'result' var:
|
||||
discard "resetLoc(p, d)"
|
||||
@@ -95,8 +96,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
pl.add(");\n")
|
||||
line(p, cpsStmts, pl)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ[0], tmp, needsInit=true)
|
||||
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
|
||||
pl.add(addrLoc(p.config, tmp))
|
||||
pl.add(");\n")
|
||||
line(p, cpsStmts, pl)
|
||||
@@ -114,28 +114,24 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
excl d.flags, lfSingleUse
|
||||
else:
|
||||
if d.k == locNone and p.splitDecls == 0:
|
||||
getTempCpp(p, typ[0], d, pl)
|
||||
d = getTempCpp(p, typ[0], pl)
|
||||
else:
|
||||
if d.k == locNone: getTemp(p, typ[0], d)
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
if d.k == locNone: d = getTemp(p, typ[0])
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
|
||||
elif isHarmlessStore(p, canRaise, d):
|
||||
if d.k == locNone: getTemp(p, typ[0], d)
|
||||
if d.k == locNone: d = getTemp(p, typ[0])
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ[0], tmp, needsInit=true)
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, tmp, list, {}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
@@ -156,14 +152,15 @@ proc reifiedOpenArray(n: PNode): bool {.inline.} =
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope, Rope) =
|
||||
var a, b, c: TLoc
|
||||
initLocExpr(p, q[1], a)
|
||||
initLocExpr(p, q[2], b)
|
||||
initLocExpr(p, q[3], c)
|
||||
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) =
|
||||
var a = initLocExpr(p, q[1])
|
||||
var b = initLocExpr(p, q[2])
|
||||
var c = initLocExpr(p, q[3])
|
||||
# but first produce the required index checks:
|
||||
if optBoundsCheck in p.options:
|
||||
genBoundsCheck(p, a, b, c)
|
||||
if prepareForMutation:
|
||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||
let ty = skipTypes(a.t, abstractVar+{tyPtr})
|
||||
let dest = getTypeDesc(p.module, destType)
|
||||
let lengthExpr = "($1)-($2)+1" % [rdLoc(c), rdLoc(b)]
|
||||
@@ -203,6 +200,7 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope,
|
||||
[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 Rope) =
|
||||
@@ -222,8 +220,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
|
||||
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0])
|
||||
result.add x & ", " & y
|
||||
else:
|
||||
var a: TLoc
|
||||
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
|
||||
var a: TLoc = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n)
|
||||
case skipTypes(a.t, abstractVar+{tyStatic}).kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
if reifiedOpenArray(n):
|
||||
@@ -267,20 +264,19 @@ 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, gcOrc} and
|
||||
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
|
||||
getSize(p.config, a.lode.typ) < 1024:
|
||||
getTemp(p, a.lode.typ, result, needsInit=false)
|
||||
result = getTemp(p, a.lode.typ, needsInit=false)
|
||||
genAssignment(p, result, a, {})
|
||||
else:
|
||||
result = a
|
||||
|
||||
proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc =
|
||||
getTemp(p, a.lode.typ, result, needsInit=false)
|
||||
result = getTemp(p, a.lode.typ, needsInit=false)
|
||||
genAssignment(p, result, a, {})
|
||||
|
||||
proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} =
|
||||
var a: TLoc
|
||||
initLocExpr(p, n[0], a)
|
||||
var a: TLoc = initLocExpr(p, n[0])
|
||||
appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc])
|
||||
|
||||
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) =
|
||||
@@ -290,15 +286,16 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
|
||||
elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
|
||||
var n = if n.kind != nkHiddenAddr: n else: n[0]
|
||||
openArrayLoc(p, param.typ, n, result)
|
||||
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]):
|
||||
initLocExpr(p, n, a)
|
||||
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and
|
||||
(optByRef notin param.options or not p.module.compileToCpp):
|
||||
a = initLocExpr(p, n)
|
||||
if n.kind in {nkCharLit..nkNilLit}:
|
||||
addAddrLoc(p.config, literalsNeedsTmp(p, a), result)
|
||||
else:
|
||||
addAddrLoc(p.config, withTmpIfNeeded(p, a, needsTmp), result)
|
||||
elif p.module.compileToCpp and param.typ.kind in {tyVar} and
|
||||
n.kind == nkHiddenAddr:
|
||||
initLocExprSingleUse(p, n[0], a)
|
||||
a = initLocExprSingleUse(p, n[0])
|
||||
# if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
|
||||
# means '*T'. See posix.nim for lots of examples that do that in the wild.
|
||||
let callee = call[0]
|
||||
@@ -309,7 +306,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
|
||||
else:
|
||||
addRdLoc(a, result)
|
||||
else:
|
||||
initLocExprSingleUse(p, n, a)
|
||||
a = initLocExprSingleUse(p, n)
|
||||
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
|
||||
#assert result != nil
|
||||
|
||||
@@ -318,12 +315,13 @@ proc genArgNoParam(p: BProc, n: PNode; result: var Rope; needsTmp = false) =
|
||||
if n.kind == nkStringToCString:
|
||||
genArgStringToCString(p, n, result, needsTmp)
|
||||
else:
|
||||
initLocExprSingleUse(p, n, a)
|
||||
a = initLocExprSingleUse(p, n)
|
||||
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
|
||||
|
||||
import aliasanalysis
|
||||
|
||||
proc potentialAlias(n: PNode, potentialWrites: seq[PNode]): bool =
|
||||
result = false
|
||||
for p in potentialWrites:
|
||||
if p.aliases(n) != no or n.aliases(p) != no:
|
||||
return true
|
||||
@@ -379,13 +377,13 @@ proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
|
||||
# We must generate temporaries in cases like #14396
|
||||
# to keep the strict Left-To-Right evaluation
|
||||
var needTmp = newSeq[bool](ri.len - 1)
|
||||
var potentialWrites: seq[PNode]
|
||||
var potentialWrites: seq[PNode] = @[]
|
||||
for i in countdown(ri.len - 1, 1):
|
||||
if ri[i].skipTrivialIndirections.kind == nkSym:
|
||||
needTmp[i - 1] = potentialAlias(ri[i], potentialWrites)
|
||||
else:
|
||||
#if not ri[i].typ.isCompileTimeOnly:
|
||||
var potentialReads: seq[PNode]
|
||||
var potentialReads: seq[PNode] = @[]
|
||||
getPotentialReads(ri[i], potentialReads)
|
||||
for n in potentialReads:
|
||||
if not needTmp[i - 1]:
|
||||
@@ -417,9 +415,8 @@ proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
|
||||
res = res & "_actual".rope
|
||||
|
||||
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var op: TLoc
|
||||
# this is a hotspot in the compiler
|
||||
initLocExpr(p, ri[0], op)
|
||||
var op: TLoc = initLocExpr(p, ri[0])
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInstOwned)
|
||||
assert(typ.kind == tyProc)
|
||||
@@ -441,8 +438,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)"
|
||||
const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists
|
||||
|
||||
var op: TLoc
|
||||
initLocExpr(p, ri[0], op)
|
||||
var op: TLoc = initLocExpr(p, ri[0])
|
||||
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInstOwned)
|
||||
@@ -467,24 +463,23 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
|
||||
# Great, we can use 'd':
|
||||
if d.k == locNone:
|
||||
getTemp(p, typ[0], d, needsInit=true)
|
||||
d = getTemp(p, typ[0], needsInit=true)
|
||||
elif d.k notin {locTemp} and not hasNoInit(ri):
|
||||
# reset before pass as 'result' var:
|
||||
discard "resetLoc(p, d)"
|
||||
pl.add(addrLoc(p.config, d))
|
||||
genCallPattern()
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ[0], tmp, needsInit=true)
|
||||
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
|
||||
pl.add(addrLoc(p.config, tmp))
|
||||
genCallPattern()
|
||||
if canRaise: raiseExit(p)
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
elif isHarmlessStore(p, canRaise, d):
|
||||
if d.k == locNone: getTemp(p, typ[0], d)
|
||||
if d.k == locNone: d = getTemp(p, typ[0])
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
|
||||
if tfIterator in typ.flags:
|
||||
list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
else:
|
||||
@@ -492,11 +487,9 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ[0], tmp)
|
||||
var tmp: TLoc = getTemp(p, typ[0])
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
|
||||
if tfIterator in typ.flags:
|
||||
list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
|
||||
else:
|
||||
@@ -664,7 +657,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
|
||||
inc j
|
||||
inc i
|
||||
of '\'':
|
||||
var idx, stars: int
|
||||
var idx, stars: int = 0
|
||||
if scanCppGenericSlot(pat, i, idx, stars):
|
||||
var t = resolveStarsInCppType(typ, idx, stars)
|
||||
if t == nil: result.add("void")
|
||||
@@ -678,8 +671,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
|
||||
result.add(substr(pat, start, i - 1))
|
||||
|
||||
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var op: TLoc
|
||||
initLocExpr(p, ri[0], op)
|
||||
var op: TLoc = initLocExpr(p, ri[0])
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
@@ -701,10 +693,9 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
d.r = pl
|
||||
excl d.flags, lfSingleUse
|
||||
else:
|
||||
if d.k == locNone: getTemp(p, typ[0], d)
|
||||
if d.k == locNone: d = getTemp(p, typ[0])
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.lode, OnUnknown)
|
||||
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
@@ -724,8 +715,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
|
||||
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
# generates a crappy ObjC call
|
||||
var op: TLoc
|
||||
initLocExpr(p, ri[0], op)
|
||||
var op: TLoc = initLocExpr(p, ri[0])
|
||||
var pl = "["
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
@@ -767,24 +757,22 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
# beware of 'result = p(result)'. We always allocate a temporary:
|
||||
if d.k in {locTemp, locNone}:
|
||||
# We already got a temp. Great, special case it:
|
||||
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
|
||||
if d.k == locNone: d = getTemp(p, typ[0], needsInit=true)
|
||||
pl.add("Result: ")
|
||||
pl.add(addrLoc(p.config, d))
|
||||
pl.add("];\n")
|
||||
line(p, cpsStmts, pl)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ[0], tmp, needsInit=true)
|
||||
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
|
||||
pl.add(addrLoc(p.config, tmp))
|
||||
pl.add("];\n")
|
||||
line(p, cpsStmts, pl)
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
else:
|
||||
pl.add("]")
|
||||
if d.k == locNone: getTemp(p, typ[0], d)
|
||||
if d.k == locNone: d = getTemp(p, typ[0])
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, ri, OnUnknown)
|
||||
var list: TLoc = initLoc(locCall, ri, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -57,8 +57,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
specializeResetT(p, accessor, lastSon(typ))
|
||||
of tyArray:
|
||||
let arraySize = lengthOrd(p.config, typ[0])
|
||||
var i: TLoc
|
||||
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i)
|
||||
var i: TLoc = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt))
|
||||
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
|
||||
[i.r, arraySize])
|
||||
specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.r]), typ[1])
|
||||
@@ -95,7 +94,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
of ctInt8, ctInt16, ctInt32, ctInt64:
|
||||
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
|
||||
else:
|
||||
doAssert false, "unexpected set type kind"
|
||||
raiseAssert "unexpected set type kind"
|
||||
of {tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
|
||||
tyGenericParam, tyOrdinal, tyRange, tyOpenArray, tyForward, tyVarargs,
|
||||
tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#
|
||||
|
||||
# included from cgen.nim
|
||||
|
||||
const
|
||||
RangeExpandLimit = 256 # do not generate ranges
|
||||
# over 'RangeExpandLimit' elements
|
||||
@@ -36,7 +35,9 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
|
||||
if n.kind == nkEmpty:
|
||||
result = false
|
||||
elif n.kind in nkCallKinds and n[0] != nil and n[0].typ != nil and n[0].typ.skipTypes(abstractInst).kind == tyProc:
|
||||
if isInvalidReturnType(conf, n[0].typ, true):
|
||||
if n[0].kind == nkSym and sfConstructor in n[0].sym.flags:
|
||||
result = true
|
||||
elif isInvalidReturnType(conf, n[0].typ, true):
|
||||
# var v = f()
|
||||
# is transformed into: var v; f(addr v)
|
||||
# where 'f' **does not** initialize the result!
|
||||
@@ -49,6 +50,7 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
|
||||
result = true
|
||||
|
||||
proc inExceptBlockLen(p: BProc): int =
|
||||
result = 0
|
||||
for x in p.nestedTryStmts:
|
||||
if x.inExcept: result.inc
|
||||
|
||||
@@ -70,7 +72,6 @@ template startBlock(p: BProc, start: FormatStr = "{$n",
|
||||
proc endBlock(p: BProc)
|
||||
|
||||
proc genVarTuple(p: BProc, n: PNode) =
|
||||
var tup, field: TLoc
|
||||
if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
|
||||
|
||||
# if we have a something that's been captured, use the lowering instead:
|
||||
@@ -82,7 +83,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
# check only the first son
|
||||
var forHcr = treatGlobalDifferentlyForHCR(p.module, n[0].sym)
|
||||
let hcrCond = if forHcr: getTempName(p.module) else: ""
|
||||
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]]
|
||||
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]] = @[]
|
||||
# determine if the tuple is constructed at top-level scope or inside of a block (if/while/block)
|
||||
let isGlobalInBlock = forHcr and p.blocks.len > 2
|
||||
# do not close and reopen blocks if this is a 'global' but inside of a block (if/while/block)
|
||||
@@ -94,7 +95,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
startBlock(p)
|
||||
|
||||
genLineDir(p, n)
|
||||
initLocExpr(p, n[^1], tup)
|
||||
var tup = initLocExpr(p, n[^1])
|
||||
var t = tup.t.skipTypes(abstractInst)
|
||||
for i in 0..<n.len-2:
|
||||
let vn = n[i]
|
||||
@@ -107,7 +108,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
else:
|
||||
assignLocalVar(p, vn)
|
||||
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1]))
|
||||
initLoc(field, locExpr, vn, tup.storage)
|
||||
var field = initLoc(locExpr, vn, tup.storage)
|
||||
if t.kind == tyTuple:
|
||||
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
|
||||
else:
|
||||
@@ -168,7 +169,7 @@ proc endBlock(p: BProc, blockEnd: Rope) =
|
||||
proc endBlock(p: BProc) =
|
||||
let topBlock = p.blocks.len - 1
|
||||
let frameLen = p.blocks[topBlock].frameLen
|
||||
var blockEnd: Rope
|
||||
var blockEnd: Rope = ""
|
||||
if frameLen > 0:
|
||||
blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope])
|
||||
if p.blocks[topBlock].label.len != 0:
|
||||
@@ -243,8 +244,7 @@ proc genGotoState(p: BProc, n: PNode) =
|
||||
# switch (x.state) {
|
||||
# case 0: goto STATE0;
|
||||
# ...
|
||||
var a: TLoc
|
||||
initLocExpr(p, n[0], a)
|
||||
var a: TLoc = initLocExpr(p, n[0])
|
||||
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
|
||||
p.flags.incl beforeRetNeeded
|
||||
lineF(p, cpsStmts, "case -1:$n", [])
|
||||
@@ -263,13 +263,13 @@ proc genGotoState(p: BProc, n: PNode) =
|
||||
|
||||
proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
|
||||
var a: TLoc
|
||||
initLoc(d, locExpr, n, OnUnknown)
|
||||
d = initLoc(locExpr, n, OnUnknown)
|
||||
|
||||
if n[0].kind == nkClosure:
|
||||
initLocExpr(p, n[0][1], a)
|
||||
a = initLocExpr(p, n[0][1])
|
||||
d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)]
|
||||
else:
|
||||
initLocExpr(p, n[0], a)
|
||||
a = initLocExpr(p, n[0])
|
||||
# the environment is guaranteed to contain the 'state' field at offset 1:
|
||||
d.r = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)]
|
||||
|
||||
@@ -289,11 +289,28 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) =
|
||||
#echo "New code produced for ", v.name.s, " ", p.config $ value.info
|
||||
genBracedInit(p, value, isConst = false, v.typ, result)
|
||||
|
||||
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) =
|
||||
var params = newRopeAppender()
|
||||
var argsCounter = 0
|
||||
let typ = skipTypes(value[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
for i in 1..<value.len:
|
||||
assert(typ.len == typ.n.len)
|
||||
genOtherArg(p, value, i, typ, params, argsCounter)
|
||||
if params.len == 0:
|
||||
decl = runtimeFormat("$#;\n", [decl])
|
||||
else:
|
||||
decl = runtimeFormat("$#($#);\n", [decl, params])
|
||||
|
||||
proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
if sfGoto in v.flags:
|
||||
# translate 'var state {.goto.} = X' into 'goto LX':
|
||||
genGotoVar(p, value)
|
||||
return
|
||||
let imm = isAssignedImmediately(p.config, value)
|
||||
let isCppCtorCall = p.module.compileToCpp and imm and
|
||||
value.kind in nkCallKinds and value[0].kind == nkSym and
|
||||
v.typ.kind != tyPtr and sfConstructor in value[0].sym.flags
|
||||
var targetProc = p
|
||||
var valueAsRope = ""
|
||||
potentialValueInit(p, v, value, valueAsRope)
|
||||
@@ -305,7 +322,11 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
if sfPure in v.flags:
|
||||
# v.owner.kind != skModule:
|
||||
targetProc = p.module.preInitProc
|
||||
assignGlobalVar(targetProc, vn, valueAsRope)
|
||||
if isCppCtorCall and not containsHiddenPointer(v.typ):
|
||||
callGlobalVarCppCtor(targetProc, v, vn, value)
|
||||
else:
|
||||
assignGlobalVar(targetProc, vn, valueAsRope)
|
||||
|
||||
# XXX: be careful here.
|
||||
# Global variables should not be zeromem-ed within loops
|
||||
# (see bug #20).
|
||||
@@ -314,13 +335,12 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
# global variables will be initialized to zero.
|
||||
if valueAsRope.len == 0:
|
||||
var loc = v.loc
|
||||
|
||||
# When the native TLS is unavailable, a global thread-local variable needs
|
||||
# one more layer of indirection in order to access the TLS block.
|
||||
# Only do this for complex types that may need a call to `objectInit`
|
||||
if sfThread in v.flags and emulatedThreadVars(p.config) and
|
||||
isComplexValueType(v.typ):
|
||||
initLocExprSingleUse(p.module.preInitProc, vn, loc)
|
||||
loc = initLocExprSingleUse(p.module.preInitProc, vn)
|
||||
genObjectInit(p.module.preInitProc, cpsInit, v.typ, loc, constructObj)
|
||||
# Alternative construction using default constructor (which may zeromem):
|
||||
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
|
||||
@@ -328,31 +348,21 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
genVarPrototype(p.module.g.generatedHeader, vn)
|
||||
registerTraverseProc(p, v)
|
||||
else:
|
||||
let imm = isAssignedImmediately(p.config, value)
|
||||
if imm and p.module.compileToCpp and p.splitDecls == 0 and
|
||||
not containsHiddenPointer(v.typ):
|
||||
not containsHiddenPointer(v.typ) and
|
||||
nimErrorFlagAccessed notin p.flags:
|
||||
# C++ really doesn't like things like 'Foo f; f = x' as that invokes a
|
||||
# parameterless constructor followed by an assignment operator. So we
|
||||
# generate better code here: 'Foo f = x;'
|
||||
genLineDir(p, vn)
|
||||
let decl = localVarDecl(p, vn)
|
||||
var decl = localVarDecl(p, vn)
|
||||
var tmp: TLoc
|
||||
if value.kind in nkCallKinds and value[0].kind == nkSym and
|
||||
sfConstructor in value[0].sym.flags:
|
||||
var params = newRopeAppender()
|
||||
var argsCounter = 0
|
||||
let typ = skipTypes(value[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
for i in 1..<value.len:
|
||||
assert(typ.len == typ.n.len)
|
||||
genOtherArg(p, value, i, typ, params, argsCounter)
|
||||
if params.len == 0:
|
||||
lineF(p, cpsStmts, "$#;$n", [decl])
|
||||
else:
|
||||
lineF(p, cpsStmts, "$#($#);$n", [decl, params])
|
||||
if isCppCtorCall:
|
||||
genCppVarForCtor(p, v, vn, value, decl)
|
||||
line(p, cpsStmts, decl)
|
||||
else:
|
||||
initLocExprSingleUse(p, value, tmp)
|
||||
lineF(p, cpsStmts, "$# = $#;$n", [decl, tmp.rdLoc])
|
||||
tmp = initLocExprSingleUse(p, value)
|
||||
lineF(p, cpsStmts, "$# = $#;\n", [decl, tmp.rdLoc])
|
||||
return
|
||||
assignLocalVar(p, vn)
|
||||
initLocalVar(p, v, imm)
|
||||
@@ -379,7 +389,8 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
startBlock(targetProc)
|
||||
if value.kind != nkEmpty and valueAsRope.len == 0:
|
||||
genLineDir(targetProc, vn)
|
||||
loadInto(targetProc, vn, value, v.loc)
|
||||
if not isCppCtorCall:
|
||||
loadInto(targetProc, vn, value, v.loc)
|
||||
if forHcr:
|
||||
endBlock(targetProc)
|
||||
|
||||
@@ -396,8 +407,7 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||
|
||||
proc genClosureVar(p: BProc, a: PNode) =
|
||||
var immediateAsgn = a[2].kind != nkEmpty
|
||||
var v: TLoc
|
||||
initLocExpr(p, a[0], v)
|
||||
var v: TLoc = initLocExpr(p, a[0])
|
||||
genLineDir(p, a)
|
||||
if immediateAsgn:
|
||||
loadInto(p, a[0], a[2], v)
|
||||
@@ -432,7 +442,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
a: TLoc
|
||||
lelse: TLabel
|
||||
if not isEmptyType(n.typ) and d.k == locNone:
|
||||
getTemp(p, n.typ, d)
|
||||
d = getTemp(p, n.typ)
|
||||
genLineDir(p, n)
|
||||
let lend = getLabel(p)
|
||||
for it in n.sons:
|
||||
@@ -440,7 +450,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
|
||||
if it.len == 2:
|
||||
startBlock(p)
|
||||
initLocExprSingleUse(p, it[0], a)
|
||||
a = initLocExprSingleUse(p, it[0])
|
||||
lelse = getLabel(p)
|
||||
inc(p.labels)
|
||||
lineF(p, cpsStmts, "if (!$1) goto $2;$n",
|
||||
@@ -508,7 +518,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
# wrapped inside stmt lists by inject destructors won't be recognised
|
||||
let n = n.flattenStmts()
|
||||
var casePos = -1
|
||||
var arraySize: int
|
||||
var arraySize: int = 0
|
||||
for i in 0..<n.len:
|
||||
let it = n[i]
|
||||
if it.kind == nkCaseStmt:
|
||||
@@ -542,8 +552,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
genStmts(p, n[j])
|
||||
|
||||
let caseStmt = n[casePos]
|
||||
var a: TLoc
|
||||
initLocExpr(p, caseStmt[0], a)
|
||||
var a: TLoc = initLocExpr(p, caseStmt[0])
|
||||
# first goto:
|
||||
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
|
||||
|
||||
@@ -581,8 +590,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
else:
|
||||
genStmts(p, it)
|
||||
|
||||
var a: TLoc
|
||||
initLocExpr(p, caseStmt[0], a)
|
||||
var a: TLoc = initLocExpr(p, caseStmt[0])
|
||||
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
|
||||
endBlock(p)
|
||||
|
||||
@@ -610,11 +618,11 @@ proc genWhileStmt(p: BProc, t: PNode) =
|
||||
else:
|
||||
p.breakIdx = startBlock(p, "while (1) {$n")
|
||||
p.blocks[p.breakIdx].isLoop = true
|
||||
initLocExpr(p, t[0], a)
|
||||
a = initLocExpr(p, t[0])
|
||||
if (t[0].kind != nkIntLit) or (t[0].intVal == 0):
|
||||
lineF(p, cpsStmts, "if (!$1) goto ", [rdLoc(a)])
|
||||
assignLabel(p.blocks[p.breakIdx], p.s(cpsStmts))
|
||||
lineF(p, cpsStmts, ";$n", [])
|
||||
appcg(p, cpsStmts, ";$n", [])
|
||||
genStmts(p, loopBody)
|
||||
|
||||
if optProfiler in p.options:
|
||||
@@ -629,7 +637,7 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
|
||||
# bug #4505: allocate the temp in the outer scope
|
||||
# so that it can escape the generated {}:
|
||||
if d.k == locNone:
|
||||
getTemp(p, n.typ, d)
|
||||
d = getTemp(p, n.typ)
|
||||
d.flags.incl(lfEnforceDeref)
|
||||
preserveBreakIdx:
|
||||
p.breakIdx = startBlock(p)
|
||||
@@ -649,14 +657,13 @@ proc genParForStmt(p: BProc, t: PNode) =
|
||||
|
||||
preserveBreakIdx:
|
||||
let forLoopVar = t[0].sym
|
||||
var rangeA, rangeB: TLoc
|
||||
assignLocalVar(p, t[0])
|
||||
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
|
||||
#discard mangleName(forLoopVar)
|
||||
let call = t[1]
|
||||
assert(call.len in {4, 5})
|
||||
initLocExpr(p, call[1], rangeA)
|
||||
initLocExpr(p, call[2], rangeB)
|
||||
assert(call.len == 4 or call.len == 5)
|
||||
var rangeA = initLocExpr(p, call[1])
|
||||
var rangeB = initLocExpr(p, call[2])
|
||||
|
||||
# $n at the beginning because of #9710
|
||||
if call.len == 4: # procName(a, b, annotation)
|
||||
@@ -673,8 +680,7 @@ proc genParForStmt(p: BProc, t: PNode) =
|
||||
rangeA.rdLoc, rangeB.rdLoc,
|
||||
call[3].getStr.rope])
|
||||
else: # `||`(a, b, step, annotation)
|
||||
var step: TLoc
|
||||
initLocExpr(p, call[3], step)
|
||||
var step: TLoc = initLocExpr(p, call[3])
|
||||
lineF(p, cpsStmts, "$n#pragma omp $5$n" &
|
||||
"for ($1 = $2; $1 <= $3; $1 += $4)",
|
||||
[forLoopVar.loc.rdLoc,
|
||||
@@ -744,8 +750,7 @@ proc raiseInstr(p: BProc; result: var Rope) =
|
||||
|
||||
proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
if t[0].kind != nkEmpty:
|
||||
var a: TLoc
|
||||
initLocExprSingleUse(p, t[0], a)
|
||||
var a: TLoc = initLocExprSingleUse(p, t[0])
|
||||
finallyActions(p)
|
||||
var e = rdLoc(a)
|
||||
discard getTypeDesc(p.module, t[0].typ)
|
||||
@@ -767,11 +772,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
else:
|
||||
finallyActions(p)
|
||||
genLineDir(p, t)
|
||||
# reraise the last exception:
|
||||
if p.config.exc == excCpp:
|
||||
line(p, cpsStmts, "throw;\n")
|
||||
else:
|
||||
linefmt(p, cpsStmts, "#reraiseException();$n", [])
|
||||
linefmt(p, cpsStmts, "#reraiseException();$n", [])
|
||||
raiseInstr(p, p.s(cpsStmts))
|
||||
|
||||
template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
|
||||
@@ -779,12 +780,12 @@ template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
|
||||
var x, y: TLoc
|
||||
for i in 0..<b.len - 1:
|
||||
if b[i].kind == nkRange:
|
||||
initLocExpr(p, b[i][0], x)
|
||||
initLocExpr(p, b[i][1], y)
|
||||
x = initLocExpr(p, b[i][0])
|
||||
y = initLocExpr(p, b[i][1])
|
||||
lineCg(p, cpsStmts, rangeFormat,
|
||||
[rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
|
||||
else:
|
||||
initLocExpr(p, b[i], x)
|
||||
x = initLocExpr(p, b[i])
|
||||
lineCg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
|
||||
|
||||
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
||||
@@ -826,8 +827,7 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
||||
|
||||
template genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
|
||||
rangeFormat, eqFormat: FormatStr) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, t[0], a)
|
||||
var a: TLoc = initLocExpr(p, t[0])
|
||||
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, t.len-1, a)
|
||||
fixLabel(p, lend)
|
||||
|
||||
@@ -837,8 +837,8 @@ proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
var x: TLoc
|
||||
for i in 0..<b.len - 1:
|
||||
assert(b[i].kind != nkRange)
|
||||
initLocExpr(p, b[i], x)
|
||||
var j: int
|
||||
x = initLocExpr(p, b[i])
|
||||
var j: int = 0
|
||||
case b[i].kind
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
j = int(hashString(p.config, b[i].strVal) and high(branches))
|
||||
@@ -861,8 +861,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
|
||||
var bitMask = math.nextPowerOfTwo(strings) - 1
|
||||
var branches: seq[Rope]
|
||||
newSeq(branches, bitMask + 1)
|
||||
var a: TLoc
|
||||
initLocExpr(p, t[0], a) # fist pass: generate ifs+goto:
|
||||
var a: TLoc = initLocExpr(p, t[0]) # first pass: generate ifs+goto:
|
||||
var labId = p.labels
|
||||
for i in 1..<t.len:
|
||||
inc(p.labels)
|
||||
@@ -898,6 +897,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
|
||||
genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
|
||||
|
||||
proc branchHasTooBigRange(b: PNode): bool =
|
||||
result = false
|
||||
for it in b:
|
||||
# last son is block
|
||||
if (it.kind == nkRange) and
|
||||
@@ -905,6 +905,7 @@ proc branchHasTooBigRange(b: PNode): bool =
|
||||
return true
|
||||
|
||||
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
|
||||
result = 0
|
||||
for i in 1..<n.len:
|
||||
var branch = n[i]
|
||||
var stmtBlock = lastSon(branch)
|
||||
@@ -940,8 +941,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
|
||||
var splitPoint = ifSwitchSplitPoint(p, n)
|
||||
|
||||
# generate if part (might be empty):
|
||||
var a: TLoc
|
||||
initLocExpr(p, n[0], a)
|
||||
var a: TLoc = initLocExpr(p, n[0])
|
||||
var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
|
||||
rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
|
||||
eqFormat = "if ($1 == $2) goto $3;$n",
|
||||
@@ -971,7 +971,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
|
||||
proc genCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
genLineDir(p, t)
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
d = getTemp(p, t.typ)
|
||||
case skipTypes(t[0].typ, abstractVarRange).kind
|
||||
of tyString:
|
||||
genStringCase(p, t, tyString, d)
|
||||
@@ -997,7 +997,7 @@ proc genRestoreFrameAfterException(p: BProc) =
|
||||
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
#[ code to generate:
|
||||
|
||||
std::exception_ptr error = nullptr;
|
||||
std::exception_ptr error;
|
||||
try {
|
||||
body;
|
||||
} catch (Exception e) {
|
||||
@@ -1022,13 +1022,13 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
p.module.includeHeader("<exception>")
|
||||
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
d = getTemp(p, t.typ)
|
||||
genLineDir(p, t)
|
||||
|
||||
inc(p.labels, 2)
|
||||
let etmp = p.labels
|
||||
|
||||
p.procSec(cpsInit).add(ropecg(p.module, "\tstd::exception_ptr T$1_ = nullptr;", [etmp]))
|
||||
lineCg(p, cpsStmts, "std::exception_ptr T$1_;$n", [etmp])
|
||||
|
||||
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
|
||||
p.nestedTryStmts.add((fin, false, 0.Natural))
|
||||
@@ -1062,7 +1062,6 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
if hasIf: lineF(p, cpsStmts, "else ", [])
|
||||
startBlock(p)
|
||||
# we handled the error:
|
||||
linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp])
|
||||
expr(p, t[i][0], d)
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||
endBlock(p)
|
||||
@@ -1082,7 +1081,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let checkFor = $getObjDepth(typeNode.typ)
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(typeNode.typ)))])
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(typeNode.typ, p.config)))])
|
||||
else:
|
||||
let checkFor = genTypeInfoV1(p.module, typeNode.typ, typeNode.info)
|
||||
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
|
||||
@@ -1125,7 +1124,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
|
||||
if t[i].len == 1:
|
||||
# general except section:
|
||||
startBlock(p, "catch (...) {", [])
|
||||
startBlock(p, "catch (...) {$n", [])
|
||||
genExceptBranchBody(t[i][0])
|
||||
endBlock(p)
|
||||
catchAllPresent = true
|
||||
@@ -1151,7 +1150,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
# general finally block:
|
||||
if t.len > 0 and t[^1].kind == nkFinally:
|
||||
if not catchAllPresent:
|
||||
startBlock(p, "catch (...) {", [])
|
||||
startBlock(p, "catch (...) {$n", [])
|
||||
genRestoreFrameAfterException(p)
|
||||
linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp])
|
||||
endBlock(p)
|
||||
@@ -1188,7 +1187,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
|
||||
expr(p, body, d)
|
||||
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
d = getTemp(p, t.typ)
|
||||
genLineDir(p, t)
|
||||
cgsym(p.module, "popCurrentExceptionEx")
|
||||
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
|
||||
@@ -1266,7 +1265,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
p.flags.incl nimErrorFlagAccessed
|
||||
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
d = getTemp(p, t.typ)
|
||||
|
||||
expr(p, t[0], d)
|
||||
|
||||
@@ -1301,7 +1300,8 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let checkFor = $getObjDepth(t[i][j].typ)
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ)))])
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)",
|
||||
[memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
|
||||
else:
|
||||
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
|
||||
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
|
||||
@@ -1372,7 +1372,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
# propagateCurrentException();
|
||||
#
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
d = getTemp(p, t.typ)
|
||||
let quirkyExceptions = p.config.exc == excQuirky or
|
||||
(t.kind == nkHiddenTryStmt and sfSystemModule in p.module.module.flags)
|
||||
if not quirkyExceptions:
|
||||
@@ -1381,7 +1381,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
p.flags.incl noSafePoints
|
||||
genLineDir(p, t)
|
||||
cgsym(p.module, "Exception")
|
||||
var safePoint: Rope
|
||||
var safePoint: Rope = ""
|
||||
if not quirkyExceptions:
|
||||
safePoint = getTempName(p.module)
|
||||
linefmt(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
|
||||
@@ -1446,7 +1446,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let checkFor = $getObjDepth(t[i][j].typ)
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ)))])
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
|
||||
else:
|
||||
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
|
||||
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
|
||||
@@ -1484,8 +1484,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
|
||||
of nkSym:
|
||||
var sym = it.sym
|
||||
if sym.kind in {skProc, skFunc, skIterator, skMethod}:
|
||||
var a: TLoc
|
||||
initLocExpr(p, it, a)
|
||||
var a: TLoc = initLocExpr(p, it)
|
||||
res.add($rdLoc(a))
|
||||
elif sym.kind == skType:
|
||||
res.add($getTypeDesc(p.module, sym.typ))
|
||||
@@ -1497,8 +1496,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
|
||||
res.add($getTypeDesc(p.module, it.typ))
|
||||
else:
|
||||
discard getTypeDesc(p.module, skipTypes(it.typ, abstractPtrs))
|
||||
var a: TLoc
|
||||
initLocExpr(p, it, a)
|
||||
var a: TLoc = initLocExpr(p, it)
|
||||
res.add($a.rdLoc)
|
||||
|
||||
if isAsmStmt and hasGnuAsm in CC[p.config.cCompiler].props:
|
||||
@@ -1538,7 +1536,7 @@ proc determineSection(n: PNode): TCFileSection =
|
||||
result = cfsProcHeaders
|
||||
if n.len >= 1 and n[0].kind in {nkStrLit..nkTripleStrLit}:
|
||||
let sec = n[0].strVal
|
||||
if sec.startsWith("/*TYPESECTION*/"): result = cfsTypes
|
||||
if sec.startsWith("/*TYPESECTION*/"): result = cfsForwardTypes # TODO WORKAROUND
|
||||
elif sec.startsWith("/*VARSECTION*/"): result = cfsVars
|
||||
elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders
|
||||
|
||||
@@ -1555,9 +1553,14 @@ proc genEmit(p: BProc, t: PNode) =
|
||||
line(p, cpsStmts, s)
|
||||
|
||||
proc genPragma(p: BProc, n: PNode) =
|
||||
for it in n.sons:
|
||||
for i in 0..<n.len:
|
||||
let it = n[i]
|
||||
case whichPragma(it)
|
||||
of wEmit: genEmit(p, it)
|
||||
of wPush:
|
||||
processPushBackendOption(p.optionsStack, p.options, n, i+1)
|
||||
of wPop:
|
||||
processPopBackendOption(p.optionsStack, p.options)
|
||||
else: discard
|
||||
|
||||
|
||||
@@ -1575,6 +1578,8 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
|
||||
"#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
|
||||
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
|
||||
lit])
|
||||
if p.config.exc == excGoto:
|
||||
raiseExit(p)
|
||||
|
||||
when false:
|
||||
proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) =
|
||||
@@ -1593,13 +1598,12 @@ when false:
|
||||
expr(p, call, d)
|
||||
|
||||
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||
var a, tmp: TLoc
|
||||
var dotExpr = e[0]
|
||||
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0]
|
||||
initLocExpr(p, e[0], a)
|
||||
getTemp(p, a.t, tmp)
|
||||
var a = initLocExpr(p, e[0])
|
||||
var tmp: TLoc = getTemp(p, a.t)
|
||||
expr(p, e[1], tmp)
|
||||
if optTinyRtti notin p.config.globalOptions and p.inUncheckedAssignSection == 0:
|
||||
if p.inUncheckedAssignSection == 0:
|
||||
let field = dotExpr[1].sym
|
||||
genDiscriminantCheck(p, a, tmp, dotExpr[0].typ, field)
|
||||
message(p.config, e.info, warnCaseTransition)
|
||||
@@ -1615,11 +1619,11 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
else:
|
||||
let le = e[0]
|
||||
let ri = e[1]
|
||||
var a: TLoc
|
||||
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), skVar)
|
||||
initLoc(a, locNone, le, OnUnknown)
|
||||
var a: TLoc = initLoc(locNone, le, OnUnknown)
|
||||
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar)
|
||||
a.flags.incl(lfEnforceDeref)
|
||||
a.flags.incl(lfPrepareForMutation)
|
||||
genLineDir(p, le) # it can be a nkBracketExpr, which may raise
|
||||
expr(p, le, a)
|
||||
a.flags.excl(lfPrepareForMutation)
|
||||
if fastAsgn: incl(a.flags, lfNoDeepCopy)
|
||||
@@ -1628,7 +1632,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
loadInto(p, le, ri, a)
|
||||
|
||||
proc genStmts(p: BProc, t: PNode) =
|
||||
var a: TLoc
|
||||
var a: TLoc = default(TLoc)
|
||||
|
||||
let isPush = p.config.hasHint(hintExtendedContext)
|
||||
if isPush: pushInfoContext(p.config, t.info)
|
||||
|
||||
@@ -21,7 +21,7 @@ const
|
||||
|
||||
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType)
|
||||
proc genCaseRange(p: BProc, branch: PNode)
|
||||
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
|
||||
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc
|
||||
|
||||
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
|
||||
typ: PType) =
|
||||
@@ -74,8 +74,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
genTraverseProc(c, accessor, lastSon(typ))
|
||||
of tyArray:
|
||||
let arraySize = lengthOrd(c.p.config, typ[0])
|
||||
var i: TLoc
|
||||
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i)
|
||||
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
|
||||
var oldCode = p.s(cpsStmts)
|
||||
freeze oldCode
|
||||
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
|
||||
@@ -119,12 +118,10 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
var p = c.p
|
||||
assert typ.kind == tySequence
|
||||
var i: TLoc
|
||||
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i)
|
||||
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
|
||||
var oldCode = p.s(cpsStmts)
|
||||
freeze oldCode
|
||||
var a: TLoc
|
||||
a.r = accessor
|
||||
var a: TLoc = TLoc(r: accessor)
|
||||
|
||||
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
|
||||
[i.r, lenExpr(c.p, a)])
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,13 +19,16 @@ when defined(nimPreviewSlimSystem):
|
||||
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
||||
case n.kind
|
||||
of nkStmtList:
|
||||
result = nil
|
||||
for i in 0..<n.len:
|
||||
result = getPragmaStmt(n[i], w)
|
||||
if result != nil: break
|
||||
of nkPragma:
|
||||
result = nil
|
||||
for i in 0..<n.len:
|
||||
if whichPragma(n[i]) == w: return n[i]
|
||||
else: discard
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
|
||||
result = getPragmaStmt(n, w) != nil
|
||||
@@ -53,7 +56,7 @@ proc hashString*(conf: ConfigRef; s: string): BiggestInt =
|
||||
a = a + (a shl 3)
|
||||
a = a xor (a shr 11)
|
||||
a = a + (a shl 15)
|
||||
result = cast[Hash](a)
|
||||
result = cast[Hash](uint(a))
|
||||
|
||||
template getUniqueType*(key: PType): PType = key
|
||||
|
||||
@@ -121,8 +124,11 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind =
|
||||
proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
|
||||
var pt = skipTypes(s.typ, typedescInst)
|
||||
assert skResult != s.kind
|
||||
|
||||
if tfByRef in pt.flags: return true
|
||||
|
||||
#note precedence: params override types
|
||||
if optByRef in s.options: return true
|
||||
elif sfByCopy in s.flags: return false
|
||||
elif tfByRef in pt.flags: return true
|
||||
elif tfByCopy in pt.flags: return false
|
||||
case pt.kind
|
||||
of tyObject:
|
||||
|
||||
@@ -12,10 +12,12 @@
|
||||
import
|
||||
ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
|
||||
nversion, nimsets, msgs, bitsets, idents, types,
|
||||
ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
|
||||
ccgutils, os, ropes, math, wordrecg, treetab, cgmeth,
|
||||
rodutils, renderer, cgendata, aliases,
|
||||
lowerings, tables, sets, ndi, lineinfos, pathutils, transf,
|
||||
injectdestructors, astmsgs, modulepaths
|
||||
injectdestructors, astmsgs, modulepaths, backendpragmas
|
||||
|
||||
import pipelineutils
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -59,12 +61,10 @@ proc findPendingModule(m: BModule, s: PSym): BModule =
|
||||
var ms = getModule(s)
|
||||
result = m.g.modules[ms.position]
|
||||
|
||||
proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) =
|
||||
result.k = k
|
||||
result.storage = s
|
||||
result.lode = lode
|
||||
result.r = ""
|
||||
result.flags = {}
|
||||
proc initLoc(k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}): TLoc =
|
||||
result = TLoc(k: k, storage: s, lode: lode,
|
||||
r: "", flags: flags
|
||||
)
|
||||
|
||||
proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) {.inline.} =
|
||||
# fills the loc if it is not already initialized
|
||||
@@ -214,20 +214,20 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
|
||||
elif frmt[i] == '#' and frmt[i+1] == '#':
|
||||
inc(i, 2)
|
||||
strLit.add("#")
|
||||
|
||||
var start = i
|
||||
while i < frmt.len:
|
||||
if frmt[i] != '$' and frmt[i] != '#': inc(i)
|
||||
else: break
|
||||
if i - 1 >= start:
|
||||
strLit.add(substr(frmt, start, i - 1))
|
||||
else:
|
||||
strLit.add(frmt[i])
|
||||
inc(i)
|
||||
|
||||
flushStrLit()
|
||||
result.add newCall(ident"rope", resVar)
|
||||
|
||||
proc addIndent(p: BProc; result: var Rope) =
|
||||
for i in 0..<p.blocks.len:
|
||||
result.add "\t".rope
|
||||
var i = result.len
|
||||
let newLen = i + p.blocks.len
|
||||
result.setLen newLen
|
||||
while i < newLen:
|
||||
result[i] = '\t'
|
||||
inc i
|
||||
|
||||
template appcg(m: BModule, c: var Rope, frmt: FormatStr,
|
||||
args: untyped) =
|
||||
@@ -267,11 +267,21 @@ proc safeLineNm(info: TLineInfo): int =
|
||||
proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
|
||||
assert line >= 0
|
||||
if optLineDir in conf.options and line > 0:
|
||||
r.addf("$N#line $2 $1$N",
|
||||
r.addf("\n#line $2 $1\n",
|
||||
[rope(makeSingleLineCString(filename)), rope(line)])
|
||||
|
||||
proc genCLineDir(r: var Rope, filename: string, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
|
||||
assert line >= 0
|
||||
if optLineDir in p.config.options and line > 0:
|
||||
if lastFileIndex == info.fileIndex:
|
||||
r.addf("\n#line $1\n", [rope(line)])
|
||||
else:
|
||||
r.addf("\n#line $2 $1\n",
|
||||
[rope(makeSingleLineCString(filename)), rope(line)])
|
||||
|
||||
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
|
||||
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf)
|
||||
if optLineDir in conf.options:
|
||||
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf)
|
||||
|
||||
proc freshLineInfo(p: BProc; info: TLineInfo): bool =
|
||||
if p.lastLineInfo.line != info.line or
|
||||
@@ -279,17 +289,33 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
|
||||
p.lastLineInfo.line = info.line
|
||||
p.lastLineInfo.fileIndex = info.fileIndex
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc genCLineDir(r: var Rope, p: BProc, info: TLineInfo; conf: ConfigRef) =
|
||||
if optLineDir in conf.options:
|
||||
let lastFileIndex = p.lastLineInfo.fileIndex
|
||||
if freshLineInfo(p, info):
|
||||
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, p, info, lastFileIndex)
|
||||
|
||||
proc genLineDir(p: BProc, t: PNode) =
|
||||
if p == p.module.preInitProc: return
|
||||
let line = t.info.safeLineNm
|
||||
|
||||
if optEmbedOrigSrc in p.config.globalOptions:
|
||||
p.s(cpsStmts).add("//" & sourceLine(p.config, t.info) & "\L")
|
||||
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config)
|
||||
let lastFileIndex = p.lastLineInfo.fileIndex
|
||||
let freshLine = freshLineInfo(p, t.info)
|
||||
if freshLine:
|
||||
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p, t.info, lastFileIndex)
|
||||
if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
|
||||
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
|
||||
if freshLineInfo(p, t.info):
|
||||
linefmt(p, cpsStmts, "nimln_($1, $2);$n",
|
||||
if freshLine:
|
||||
if lastFileIndex == t.info.fileIndex:
|
||||
linefmt(p, cpsStmts, "nimln_($1);",
|
||||
[line])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "nimlf_($1, $2);",
|
||||
[line, quotedFilename(p.config, t.info)])
|
||||
|
||||
proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||
@@ -349,19 +375,19 @@ template mapTypeChooser(n: PNode): TSymKind =
|
||||
template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode)
|
||||
|
||||
proc addAddrLoc(conf: ConfigRef; a: TLoc; result: var Rope) =
|
||||
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray:
|
||||
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != ctArray:
|
||||
result.add "(&" & a.r & ")"
|
||||
else:
|
||||
result.add a.r
|
||||
|
||||
proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
|
||||
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray:
|
||||
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != ctArray:
|
||||
result = "(&" & a.r & ")"
|
||||
else:
|
||||
result = a.r
|
||||
|
||||
proc byRefLoc(p: BProc; a: TLoc): Rope =
|
||||
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a)) != ctArray and not
|
||||
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a) == skParam) != ctArray and not
|
||||
p.module.compileToCpp:
|
||||
result = "(&" & a.r & ")"
|
||||
else:
|
||||
@@ -407,13 +433,13 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
|
||||
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
|
||||
of frEmbedded:
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
var tmp: TLoc
|
||||
var tmp: TLoc = default(TLoc)
|
||||
if mode == constructRefObj:
|
||||
let objType = t.skipTypes(abstractInst+{tyRef})
|
||||
rawConstExpr(p, newNodeIT(nkType, a.lode.info, objType), tmp)
|
||||
linefmt(p, cpsStmts,
|
||||
"#nimCopyMem((void*)$1, (NIM_CONST void*)&$2, sizeof($3));$n",
|
||||
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, mapTypeChooser(a))])
|
||||
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, descKindFromSymKind mapTypeChooser(a))])
|
||||
else:
|
||||
rawConstExpr(p, newNodeIT(nkType, a.lode.info, t), tmp)
|
||||
genAssignment(p, a, tmp, {})
|
||||
@@ -455,8 +481,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
|
||||
elif not isComplexValueType(typ):
|
||||
if containsGcRef:
|
||||
var nilLoc: TLoc
|
||||
initLoc(nilLoc, locTemp, loc.lode, OnStack)
|
||||
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
|
||||
nilLoc.r = rope("NIM_NIL")
|
||||
genRefAssign(p, loc, nilLoc)
|
||||
else:
|
||||
@@ -475,7 +500,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
|
||||
# so we use getTypeDesc here rather than rdLoc(loc)
|
||||
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
|
||||
[addrLoc(p.config, loc),
|
||||
getTypeDesc(p.module, loc.t, mapTypeChooser(loc))])
|
||||
getTypeDesc(p.module, loc.t, descKindFromSymKind mapTypeChooser(loc))])
|
||||
# XXX: We can be extra clever here and call memset only
|
||||
# on the bytes following the m_type field?
|
||||
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
|
||||
@@ -486,20 +511,19 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
|
||||
elif not isComplexValueType(typ):
|
||||
if containsGarbageCollectedRef(loc.t):
|
||||
var nilLoc: TLoc
|
||||
initLoc(nilLoc, locTemp, loc.lode, OnStack)
|
||||
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
|
||||
nilLoc.r = rope("NIM_NIL")
|
||||
genRefAssign(p, loc, nilLoc)
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
|
||||
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
|
||||
getTypeDesc(p.module, typ, descKindFromSymKind mapTypeChooser(loc))])
|
||||
else:
|
||||
if not isTemp or containsGarbageCollectedRef(loc.t):
|
||||
# don't use nimZeroMem for temporary values for performance if we can
|
||||
# avoid it:
|
||||
if not isImportedCppType(typ):
|
||||
if not isOrHasImportedCppType(typ):
|
||||
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
|
||||
[addrLoc(p.config, loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))])
|
||||
[addrLoc(p.config, loc), getTypeDesc(p.module, typ, descKindFromSymKind mapTypeChooser(loc))])
|
||||
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
|
||||
|
||||
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||
@@ -514,14 +538,14 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||
if not immediateAsgn:
|
||||
constructLoc(p, v.loc)
|
||||
|
||||
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
|
||||
inc(p.labels)
|
||||
result.r = "T" & rope(p.labels) & "_"
|
||||
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r])
|
||||
result.k = locTemp
|
||||
result.lode = lodeTyp t
|
||||
result.storage = OnStack
|
||||
result.flags = {}
|
||||
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
|
||||
storage: OnStack, flags: {})
|
||||
if p.module.compileToCpp and isOrHasImportedCppType(t):
|
||||
linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, dkVar), result.r])
|
||||
else:
|
||||
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkVar), result.r])
|
||||
constructLoc(p, result, not needsInit)
|
||||
when false:
|
||||
# XXX Introduce a compiler switch in order to detect these easily.
|
||||
@@ -532,25 +556,21 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||
echo "ENORMOUS TEMPORARY! ", p.config $ p.lastLineInfo
|
||||
writeStackTrace()
|
||||
|
||||
proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) =
|
||||
proc getTempCpp(p: BProc, t: PType, value: Rope): TLoc =
|
||||
inc(p.labels)
|
||||
result.r = "T" & rope(p.labels) & "_"
|
||||
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, skVar), result.r, value])
|
||||
result.k = locTemp
|
||||
result.lode = lodeTyp t
|
||||
result.storage = OnStack
|
||||
result.flags = {}
|
||||
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
|
||||
storage: OnStack, flags: {})
|
||||
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkVar), result.r, value])
|
||||
|
||||
proc getIntTemp(p: BProc, result: var TLoc) =
|
||||
proc getIntTemp(p: BProc): TLoc =
|
||||
inc(p.labels)
|
||||
result.r = "T" & rope(p.labels) & "_"
|
||||
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp,
|
||||
storage: OnStack, lode: lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt),
|
||||
flags: {})
|
||||
linefmt(p, cpsLocals, "NI $1;$n", [result.r])
|
||||
result.k = locTemp
|
||||
result.storage = OnStack
|
||||
result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt)
|
||||
result.flags = {}
|
||||
|
||||
proc localVarDecl(p: BProc; n: PNode): Rope =
|
||||
result = ""
|
||||
let s = n.sym
|
||||
if s.loc.k == locNone:
|
||||
fillLocalName(p, s)
|
||||
@@ -558,8 +578,11 @@ proc localVarDecl(p: BProc; n: PNode): Rope =
|
||||
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
|
||||
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
||||
result.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
|
||||
result.add getTypeDesc(p.module, s.typ, skVar)
|
||||
if s.constraint.isNil:
|
||||
|
||||
genCLineDir(result, p, n.info, p.config)
|
||||
|
||||
result.add getTypeDesc(p.module, s.typ, dkVar)
|
||||
if sfCodegenDecl notin s.flags:
|
||||
if sfRegister in s.flags: result.add(" register")
|
||||
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
||||
# decl.add(" GC_GUARD")
|
||||
@@ -574,8 +597,8 @@ proc assignLocalVar(p: BProc, n: PNode) =
|
||||
#assert(s.loc.k == locNone) # not yet assigned
|
||||
# this need not be fulfilled for inline procs; they are regenerated
|
||||
# for each module that uses them!
|
||||
let nl = if optLineDir in p.config.options: "" else: "\L"
|
||||
let decl = localVarDecl(p, n) & ";" & nl
|
||||
let nl = if optLineDir in p.config.options: "" else: "\n"
|
||||
let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};" else: ";") & nl
|
||||
line(p, cpsLocals, decl)
|
||||
|
||||
include ccgthreadvars
|
||||
@@ -588,6 +611,40 @@ proc treatGlobalDifferentlyForHCR(m: BModule, s: PSym): bool =
|
||||
# and s.owner.kind == skModule # owner isn't always a module (global pragma on local var)
|
||||
# and s.loc.k == locGlobalVar # loc isn't always initialized when this proc is used
|
||||
|
||||
proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) =
|
||||
let s = n.sym
|
||||
if sfCodegenDecl notin s.flags:
|
||||
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
||||
decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
|
||||
if p.hcrOn: decl.add("static ")
|
||||
elif sfImportc in s.flags: decl.add("extern ")
|
||||
elif lfExportLib in s.loc.flags: decl.add("N_LIB_EXPORT_VAR ")
|
||||
else: decl.add("N_LIB_PRIVATE ")
|
||||
if s.kind == skLet and value != "": decl.add("NIM_CONST ")
|
||||
decl.add(td)
|
||||
if p.hcrOn: decl.add("*")
|
||||
if sfRegister in s.flags: decl.add(" register")
|
||||
if sfVolatile in s.flags: decl.add(" volatile")
|
||||
if sfNoalias in s.flags: decl.add(" NIM_NOALIAS")
|
||||
else:
|
||||
if value != "":
|
||||
decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value])
|
||||
else:
|
||||
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
|
||||
|
||||
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope)
|
||||
|
||||
proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode) =
|
||||
let s = vn.sym
|
||||
fillBackendName(p.module, s)
|
||||
fillLoc(s.loc, locGlobalVar, vn, OnHeap)
|
||||
var decl: Rope = ""
|
||||
let td = getTypeDesc(p.module, vn.sym.typ, dkVar)
|
||||
genGlobalVarDecl(p, vn, td, "", decl)
|
||||
decl.add " " & $s.loc.r
|
||||
genCppVarForCtor(p, v, vn, value, decl)
|
||||
p.module.s[cfsVars].add decl
|
||||
|
||||
proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
|
||||
let s = n.sym
|
||||
if s.loc.k == locNone:
|
||||
@@ -613,29 +670,30 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
|
||||
internalError(p.config, n.info, ".threadvar variables cannot have a value")
|
||||
else:
|
||||
var decl: Rope = ""
|
||||
var td = getTypeDesc(p.module, s.loc.t, skVar)
|
||||
let td = getTypeDesc(p.module, s.loc.t, dkVar)
|
||||
genGlobalVarDecl(p, n, td, value, decl)
|
||||
if s.constraint.isNil:
|
||||
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
||||
decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
|
||||
if p.hcrOn: decl.add("static ")
|
||||
elif sfImportc in s.flags: decl.add("extern ")
|
||||
elif lfExportLib in s.loc.flags: decl.add("N_LIB_EXPORT_VAR ")
|
||||
else: decl.add("N_LIB_PRIVATE ")
|
||||
if s.kind == skLet and value != "": decl.add("NIM_CONST ")
|
||||
decl.add(td)
|
||||
if p.hcrOn: decl.add("*")
|
||||
if sfRegister in s.flags: decl.add(" register")
|
||||
if sfVolatile in s.flags: decl.add(" volatile")
|
||||
if sfNoalias in s.flags: decl.add(" NIM_NOALIAS")
|
||||
if value != "":
|
||||
decl.addf(" $1 = $2;$n", [s.loc.r, value])
|
||||
if p.module.compileToCpp and value.startsWith "{{}":
|
||||
# TODO: taking this branch, re"\{\{\}(,\s\{\})*\}" might be emitted, resulting in
|
||||
# either warnings (GCC 12.2+) or errors (Clang 15, MSVC 19.3+) of C++11+ compilers **when
|
||||
# explicit constructors are around** due to overload resolution rules in place [^0][^1][^2]
|
||||
# *Workaround* here: have C++'s static initialization mechanism do the default init work,
|
||||
# for us lacking a deeper knowledge of an imported object's constructors' ex-/implicitness
|
||||
# (so far) *and yet* trying to achieve default initialization.
|
||||
# Still, generating {}s in genConstObjConstr() just to omit them here is faaaar from ideal;
|
||||
# need to figure out a better way, possibly by keeping around more data about the
|
||||
# imported objects' contructors?
|
||||
#
|
||||
# [^0]: https://en.cppreference.com/w/cpp/language/aggregate_initialization
|
||||
# [^1]: https://cplusplus.github.io/CWG/issues/1518.html
|
||||
# [^2]: https://eel.is/c++draft/over.match.ctor
|
||||
decl.addf(" $1;$n", [s.loc.r])
|
||||
else:
|
||||
decl.addf(" $1 = $2;$n", [s.loc.r, value])
|
||||
else:
|
||||
decl.addf(" $1;$n", [s.loc.r])
|
||||
else:
|
||||
if value != "":
|
||||
decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value])
|
||||
else:
|
||||
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
|
||||
|
||||
p.module.s[cfsVars].add(decl)
|
||||
if p.withinLoop > 0 and value == "":
|
||||
# fixes tests/run/tzeroarray:
|
||||
@@ -656,7 +714,7 @@ proc getLabel(p: BProc): TLabel =
|
||||
result = "LA" & rope(p.labels) & "_"
|
||||
|
||||
proc fixLabel(p: BProc, labl: TLabel) =
|
||||
lineF(p, cpsStmts, "$1: ;$n", [labl])
|
||||
p.s(cpsStmts).add("$1: ;$n" % [labl])
|
||||
|
||||
proc genVarPrototype(m: BModule, n: PNode)
|
||||
proc requestConstImpl(p: BProc, sym: PSym)
|
||||
@@ -669,12 +727,12 @@ proc genLiteral(p: BProc, n: PNode; result: var Rope)
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
|
||||
proc raiseExit(p: BProc)
|
||||
|
||||
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
|
||||
initLoc(result, locNone, e, OnUnknown)
|
||||
proc initLocExpr(p: BProc, e: PNode, flags: TLocFlags = {}): TLoc =
|
||||
result = initLoc(locNone, e, OnUnknown, flags)
|
||||
expr(p, e, result)
|
||||
|
||||
proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
|
||||
initLoc(result, locNone, e, OnUnknown)
|
||||
proc initLocExprSingleUse(p: BProc, e: PNode): TLoc =
|
||||
result = initLoc(locNone, e, OnUnknown)
|
||||
if e.kind in nkCallKinds and (e[0].kind != nkSym or e[0].sym.magic == mNone):
|
||||
# We cannot check for tfNoSideEffect here because of mutable parameters.
|
||||
discard "bug #8202; enforce evaluation order for nested calls for C++ too"
|
||||
@@ -698,8 +756,12 @@ $1define nimfr_(proc, file) \
|
||||
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename;NI len;VarSlot s[slots];} FR_; \
|
||||
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; #nimFrame((TFrame*)&FR_);
|
||||
|
||||
$1define nimln_(n, file) \
|
||||
$1define nimln_(n) \
|
||||
FR_.line = n;
|
||||
|
||||
$1define nimlf_(n, file) \
|
||||
FR_.line = n; FR_.filename = file;
|
||||
|
||||
"""
|
||||
if p.module.s[cfsFrameDefines].len == 0:
|
||||
appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"])
|
||||
@@ -761,11 +823,10 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
var p = newProc(nil, m)
|
||||
p.options.excl optStackTrace
|
||||
p.flags.incl nimErrorFlagDisabled
|
||||
var dest: TLoc
|
||||
initLoc(dest, locTemp, lib.path, OnStack)
|
||||
var dest: TLoc = initLoc(locTemp, lib.path, OnStack)
|
||||
dest.r = getTempName(m)
|
||||
appcg(m, m.s[cfsDynLibInit],"$1 $2;$n",
|
||||
[getTypeDesc(m, lib.path.typ, skVar), rdLoc(dest)])
|
||||
[getTypeDesc(m, lib.path.typ, dkVar), rdLoc(dest)])
|
||||
expr(p, lib.path, dest)
|
||||
|
||||
m.s[cfsVars].add(p.s(cpsLocals))
|
||||
@@ -797,15 +858,14 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||
inc(m.labels, 2)
|
||||
if isCall:
|
||||
let n = lib.path
|
||||
var a: TLoc
|
||||
initLocExpr(m.initProc, n[0], a)
|
||||
var a: TLoc = initLocExpr(m.initProc, n[0])
|
||||
var params = rdLoc(a) & "("
|
||||
for i in 1..<n.len-1:
|
||||
initLocExpr(m.initProc, n[i], a)
|
||||
a = initLocExpr(m.initProc, n[i])
|
||||
params.add(rdLoc(a))
|
||||
params.add(", ")
|
||||
let load = "\t$1 = ($2) ($3$4));$n" %
|
||||
[tmp, getTypeDesc(m, sym.typ, skVar), params, makeCString($extname)]
|
||||
[tmp, getTypeDesc(m, sym.typ, dkVar), params, makeCString($extname)]
|
||||
var last = lastSon(n)
|
||||
if last.kind == nkHiddenStdConv: last = last[1]
|
||||
internalAssert(m.config, last.kind == nkStrLit)
|
||||
@@ -819,8 +879,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||
else:
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
|
||||
[tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)])
|
||||
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
|
||||
[tmp, getTypeDesc(m, sym.typ, dkVar), lib.name, makeCString($extname)])
|
||||
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, dkVar)])
|
||||
|
||||
proc varInDynamicLib(m: BModule, sym: PSym) =
|
||||
var lib = sym.annex
|
||||
@@ -832,9 +892,9 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
|
||||
inc(m.labels, 2)
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
|
||||
[tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)])
|
||||
[tmp, getTypeDesc(m, sym.typ, dkVar), lib.name, makeCString($extname)])
|
||||
m.s[cfsVars].addf("$2* $1;$n",
|
||||
[sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
|
||||
[sym.loc.r, getTypeDesc(m, sym.loc.t, dkVar)])
|
||||
|
||||
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
|
||||
sym.loc.r = mangleDynLibProc(sym)
|
||||
@@ -865,7 +925,9 @@ proc cgsymValue(m: BModule, name: string): Rope =
|
||||
result.addActualSuffixForHCR(m.module, sym)
|
||||
|
||||
proc generateHeaders(m: BModule) =
|
||||
m.s[cfsHeaders].add("\L#include \"nimbase.h\"\L")
|
||||
var nimbase = m.config.nimbasePattern
|
||||
if nimbase == "": nimbase = "nimbase.h"
|
||||
m.s[cfsHeaders].addf("\L#include \"$1\"\L", [nimbase])
|
||||
|
||||
for it in m.headerFiles:
|
||||
if it[0] == '#':
|
||||
@@ -931,6 +993,7 @@ const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTempl
|
||||
declarativeDefs
|
||||
|
||||
proc easyResultAsgn(n: PNode): PNode =
|
||||
result = nil
|
||||
case n.kind
|
||||
of nkStmtList, nkStmtListExpr:
|
||||
var i = 0
|
||||
@@ -1055,14 +1118,14 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
|
||||
proc getProcTypeCast(m: BModule, prc: PSym): Rope =
|
||||
result = getTypeDesc(m, prc.loc.t)
|
||||
if prc.typ.callConv == ccClosure:
|
||||
var rettype, params: Rope
|
||||
var rettype, params: Rope = ""
|
||||
var check = initIntSet()
|
||||
genProcParams(m, prc.typ, rettype, params, check)
|
||||
result = "$1(*)$2" % [rettype, params]
|
||||
|
||||
proc genProcBody(p: BProc; procBody: PNode) =
|
||||
genStmts(p, procBody) # modifies p.locals, p.init, etc.
|
||||
if {nimErrorFlagAccessed, nimErrorFlagDeclared} * p.flags == {nimErrorFlagAccessed}:
|
||||
if {nimErrorFlagAccessed, nimErrorFlagDeclared, nimErrorFlagDisabled} * p.flags == {nimErrorFlagAccessed}:
|
||||
p.flags.incl nimErrorFlagDeclared
|
||||
p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NIM_BOOL* nimErr_;$n", []))
|
||||
p.blocks[0].sections[cpsInit].add(ropecg(p.module, "nimErr_ = #nimErrorFlag();$n", []))
|
||||
@@ -1070,10 +1133,14 @@ proc genProcBody(p: BProc; procBody: PNode) =
|
||||
proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
|
||||
sfNoReturn in s.flags and m.config.exc != excGoto
|
||||
|
||||
proc genProcAux(m: BModule, prc: PSym) =
|
||||
proc genProcAux*(m: BModule, prc: PSym) =
|
||||
var p = newProc(prc, m)
|
||||
var header = newRopeAppender()
|
||||
genProcHeader(m, prc, header)
|
||||
let isCppMember = m.config.backend == backendCpp and sfCppMember * prc.flags != {}
|
||||
if isCppMember:
|
||||
genMemberProcHeader(m, prc, header)
|
||||
else:
|
||||
genProcHeader(m, prc, header)
|
||||
var returnStmt: Rope = ""
|
||||
assert(prc.ast != nil)
|
||||
|
||||
@@ -1081,17 +1148,19 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
if sfInjectDestructors in prc.flags:
|
||||
procBody = injectDestructorCalls(m.g.graph, m.idgen, prc, procBody)
|
||||
|
||||
let tmpInfo = prc.info
|
||||
discard freshLineInfo(p, prc.info)
|
||||
|
||||
if sfPure notin prc.flags and prc.typ[0] != nil:
|
||||
if resultPos >= prc.ast.len:
|
||||
internalError(m.config, prc.info, "proc has no result symbol")
|
||||
let resNode = prc.ast[resultPos]
|
||||
let res = resNode.sym # get result symbol
|
||||
if not isInvalidReturnType(m.config, prc.typ):
|
||||
if not isInvalidReturnType(m.config, prc.typ) and sfConstructor notin prc.flags:
|
||||
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
|
||||
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
|
||||
var decl = localVarDecl(p, resNode)
|
||||
var a: TLoc
|
||||
initLocExprSingleUse(p, val, a)
|
||||
var a: TLoc = initLocExprSingleUse(p, val)
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", [decl, rdLoc(a)])
|
||||
else:
|
||||
# declare the result symbol:
|
||||
@@ -1099,6 +1168,8 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
assert(res.loc.r != "")
|
||||
initLocalVar(p, res, immediateAsgn=false)
|
||||
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
|
||||
elif sfConstructor in prc.flags:
|
||||
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
|
||||
else:
|
||||
fillResult(p.config, resNode, prc.typ)
|
||||
assignParam(p, res, prc.typ[0])
|
||||
@@ -1123,13 +1194,15 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
closureSetup(p, prc)
|
||||
genProcBody(p, procBody)
|
||||
|
||||
var generatedProc: Rope
|
||||
prc.info = tmpInfo
|
||||
|
||||
var generatedProc: Rope = ""
|
||||
generatedProc.genCLineDir prc.info, m.config
|
||||
if isNoReturn(p.module, prc):
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
|
||||
header = "__declspec(noreturn) " & header
|
||||
if sfPure in prc.flags:
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
|
||||
header = "__declspec(naked) " & header
|
||||
generatedProc.add ropecg(p.module, "$1 {$n$2$3$4}$N$N",
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
|
||||
@@ -1174,7 +1247,7 @@ proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
|
||||
|
||||
proc genProcPrototype(m: BModule, sym: PSym) =
|
||||
useHeader(m, sym)
|
||||
if lfNoDecl in sym.loc.flags: return
|
||||
if lfNoDecl in sym.loc.flags or sfCppMember * sym.flags != {}: return
|
||||
if lfDynamicLib in sym.loc.flags:
|
||||
if sym.itemId.module != m.module.position and
|
||||
not containsOrIncl(m.declaredThings, sym.id):
|
||||
@@ -1210,6 +1283,20 @@ proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
if lfNoDecl in prc.loc.flags:
|
||||
fillProcLoc(m, prc.ast[namePos])
|
||||
genProcPrototype(m, prc)
|
||||
elif lfDynamicLib in prc.loc.flags:
|
||||
var q = findPendingModule(m, prc)
|
||||
fillProcLoc(q, prc.ast[namePos])
|
||||
genProcPrototype(m, prc)
|
||||
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
|
||||
symInDynamicLib(q, prc)
|
||||
# register the procedure even though it is in a different dynamic library and will not be
|
||||
# reloadable (and has no _actual suffix) - other modules will need to be able to get it through
|
||||
# the hcr dynlib (also put it in the DynLibInit section - right after it gets loaded)
|
||||
if isReloadable(q, prc):
|
||||
q.s[cfsDynLibInit].addf("\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n",
|
||||
[prc.loc.r, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)])
|
||||
else:
|
||||
symInDynamicLibPartial(m, prc)
|
||||
elif prc.typ.callConv == ccInline:
|
||||
# We add inline procs to the calling module to enable C based inlining.
|
||||
# This also means that a check with ``q.declaredThings`` is wrong, we need
|
||||
@@ -1228,20 +1315,6 @@ proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
# prc.loc.r = mangleName(m, prc)
|
||||
genProcPrototype(m, prc)
|
||||
genProcAux(m, prc)
|
||||
elif lfDynamicLib in prc.loc.flags:
|
||||
var q = findPendingModule(m, prc)
|
||||
fillProcLoc(q, prc.ast[namePos])
|
||||
genProcPrototype(m, prc)
|
||||
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
|
||||
symInDynamicLib(q, prc)
|
||||
# register the procedure even though it is in a different dynamic library and will not be
|
||||
# reloadable (and has no _actual suffix) - other modules will need to be able to get it through
|
||||
# the hcr dynlib (also put it in the DynLibInit section - right after it gets loaded)
|
||||
if isReloadable(q, prc):
|
||||
q.s[cfsDynLibInit].addf("\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n",
|
||||
[prc.loc.r, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)])
|
||||
else:
|
||||
symInDynamicLibPartial(m, prc)
|
||||
elif sfImportc notin prc.flags:
|
||||
var q = findPendingModule(m, prc)
|
||||
fillProcLoc(q, prc.ast[namePos])
|
||||
@@ -1305,14 +1378,14 @@ proc genVarPrototype(m: BModule, n: PNode) =
|
||||
if sym.owner.id != m.module.id:
|
||||
# else we already have the symbol generated!
|
||||
assert(sym.loc.r != "")
|
||||
incl(m.declaredThings, sym.id)
|
||||
if sfThread in sym.flags:
|
||||
declareThreadVar(m, sym, true)
|
||||
else:
|
||||
incl(m.declaredThings, sym.id)
|
||||
if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0:
|
||||
m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)]
|
||||
m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ")
|
||||
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, skVar))
|
||||
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, dkVar))
|
||||
if m.hcrOn: m.s[cfsVars].add("*")
|
||||
if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*")
|
||||
if sfRegister in sym.flags: m.s[cfsVars].add(" register")
|
||||
@@ -1321,7 +1394,7 @@ proc genVarPrototype(m: BModule, n: PNode) =
|
||||
m.s[cfsVars].addf(" $1;$n", [sym.loc.r])
|
||||
if m.hcrOn: m.initProc.procSec(cpsLocals).addf(
|
||||
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
|
||||
getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(m, sym)])
|
||||
getTypeDesc(m, sym.loc.t, dkVar), getModuleDllPath(m, sym)])
|
||||
|
||||
proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} =
|
||||
result.addf("#define NIM_INTBITS $1\L", [
|
||||
@@ -1353,17 +1426,21 @@ proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
|
||||
|
||||
proc getSomeNameForModule(conf: ConfigRef, filename: AbsoluteFile): Rope =
|
||||
## Returns a mangled module name.
|
||||
result = ""
|
||||
result.add mangleModuleName(conf, filename).mangle
|
||||
|
||||
proc getSomeNameForModule(m: BModule): Rope =
|
||||
## Returns a mangled module name.
|
||||
assert m.module.kind == skModule
|
||||
assert m.module.owner.kind == skPackage
|
||||
result = ""
|
||||
result.add mangleModuleName(m.g.config, m.filename).mangle
|
||||
|
||||
proc getSomeInitName(m: BModule, suffix: string): Rope =
|
||||
if not m.hcrOn:
|
||||
result = getSomeNameForModule(m)
|
||||
else:
|
||||
result = ""
|
||||
result.add suffix
|
||||
|
||||
proc getInitName(m: BModule): Rope =
|
||||
@@ -1382,10 +1459,10 @@ proc genMainProc(m: BModule) =
|
||||
## this function is called in cgenWriteModules after all modules are closed,
|
||||
## it means raising dependency on the symbols is too late as it will not propagate
|
||||
## into other modules, only simple rope manipulations are allowed
|
||||
|
||||
var preMainCode: Rope
|
||||
var preMainCode: Rope = ""
|
||||
if m.hcrOn:
|
||||
proc loadLib(handle: string, name: string): Rope =
|
||||
result = ""
|
||||
let prc = magicsys.getCompilerProc(m.g.graph, name)
|
||||
assert prc != nil
|
||||
let n = newStrNode(nkStrLit, prc.annex.path.strVal)
|
||||
@@ -1397,20 +1474,23 @@ proc genMainProc(m: BModule) =
|
||||
[handle, strLit])
|
||||
|
||||
preMainCode.add(loadLib("hcr_handle", "hcrGetProc"))
|
||||
preMainCode.add("\tvoid* rtl_handle;\L")
|
||||
preMainCode.add(loadLib("rtl_handle", "nimGC_setStackBottom"))
|
||||
preMainCode.add(hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr"))
|
||||
preMainCode.add("\tinner = PreMain;\L")
|
||||
preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L")
|
||||
preMainCode.add("\t(*inner)();\L")
|
||||
if m.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
|
||||
preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix])
|
||||
else:
|
||||
preMainCode.add("\tvoid* rtl_handle;\L")
|
||||
preMainCode.add(loadLib("rtl_handle", "nimGC_setStackBottom"))
|
||||
preMainCode.add(hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr"))
|
||||
preMainCode.add("\tinner = $1PreMain;\L" % [rope m.config.nimMainPrefix])
|
||||
preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L")
|
||||
preMainCode.add("\t(*inner)();\L")
|
||||
else:
|
||||
preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix])
|
||||
|
||||
var posixCmdLine: Rope
|
||||
var posixCmdLine: Rope = ""
|
||||
if optNoMain notin m.config.globalOptions:
|
||||
posixCmdLine.add "\tN_LIB_PRIVATE int cmdCount;\L"
|
||||
posixCmdLine.add "\tN_LIB_PRIVATE char** cmdLine;\L"
|
||||
posixCmdLine.add "\tN_LIB_PRIVATE char** gEnv;\L"
|
||||
posixCmdLine.add "N_LIB_PRIVATE int cmdCount;\L"
|
||||
posixCmdLine.add "N_LIB_PRIVATE char** cmdLine;\L"
|
||||
posixCmdLine.add "N_LIB_PRIVATE char** gEnv;\L"
|
||||
|
||||
const
|
||||
# The use of a volatile function pointer to call Pre/NimMainInner
|
||||
@@ -1423,15 +1503,15 @@ proc genMainProc(m: BModule) =
|
||||
"}$N$N" &
|
||||
"$4" &
|
||||
"N_LIB_PRIVATE void $3PreMain(void) {$N" &
|
||||
"\t##if $5$N" & # 1 for volatile call, 0 for non-volatile
|
||||
"##if $5$N" & # 1 for volatile call, 0 for non-volatile
|
||||
"\tvoid (*volatile inner)(void);$N" &
|
||||
"\tinner = $3PreMainInner;$N" &
|
||||
"$1" &
|
||||
"\t(*inner)();$N" &
|
||||
"\t##else$N" &
|
||||
"##else$N" &
|
||||
"$1" &
|
||||
"\t$3PreMainInner();$N" &
|
||||
"\t##endif$N" &
|
||||
"##endif$N" &
|
||||
"}$N$N"
|
||||
|
||||
MainProcs =
|
||||
@@ -1446,17 +1526,17 @@ proc genMainProc(m: BModule) =
|
||||
|
||||
NimMainProc =
|
||||
"N_CDECL(void, $5NimMain)(void) {$N" &
|
||||
"\t##if $6$N" & # 1 for volatile call, 0 for non-volatile
|
||||
"##if $6$N" & # 1 for volatile call, 0 for non-volatile
|
||||
"\tvoid (*volatile inner)(void);$N" &
|
||||
"$4" &
|
||||
"\tinner = $5NimMainInner;$N" &
|
||||
"$2" &
|
||||
"\t(*inner)();$N" &
|
||||
"\t##else$N" &
|
||||
"##else$N" &
|
||||
"$4" &
|
||||
"$2" &
|
||||
"\t$5NimMainInner();$N" &
|
||||
"\t##endif$N" &
|
||||
"##endif$N" &
|
||||
"}$N$N"
|
||||
|
||||
NimMainBody = NimMainInner & NimMainProc
|
||||
@@ -1487,7 +1567,7 @@ proc genMainProc(m: BModule) =
|
||||
WinCDllMain =
|
||||
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" &
|
||||
" LPVOID lpvReserved) {$N" &
|
||||
"\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" &
|
||||
"\tif (fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "\t}$N" &
|
||||
"\treturn 1;$N}$N$N"
|
||||
|
||||
PosixNimDllMain = WinNimDllMain
|
||||
@@ -1521,11 +1601,11 @@ proc genMainProc(m: BModule) =
|
||||
m.includeHeader("<libc/component.h>")
|
||||
|
||||
let initStackBottomCall =
|
||||
if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcOrc}: "".rope
|
||||
if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcAtomicArc, gcOrc}: "".rope
|
||||
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])
|
||||
inc(m.labels)
|
||||
|
||||
let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcOrc}: "1" else: "0"
|
||||
let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}: "1" else: "0"
|
||||
appcg(m, m.s[cfsProcs], PreMainBody, [m.g.mainDatInit, m.g.otherModsInit, m.config.nimMainPrefix, posixCmdLine, isVolatile])
|
||||
|
||||
if m.config.target.targetOS == osWindows and
|
||||
@@ -1624,7 +1704,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
|
||||
hcrModuleMeta.addf("\t\"\"};$n", [])
|
||||
hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(void**, HcrGetImportedModules)() { return (void**)hcr_module_list; }$n", [])
|
||||
hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(char*, HcrGetSigHash)() { return \"$1\"; }$n$n",
|
||||
[($sigHash(m.module)).rope])
|
||||
[($sigHash(m.module, m.config)).rope])
|
||||
if sfMainModule in m.module.flags:
|
||||
g.mainModProcs.add(hcrModuleMeta)
|
||||
g.mainModProcs.addf("static void* hcr_handle;$N", [])
|
||||
@@ -1665,7 +1745,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
|
||||
if sfSystemModule in m.module.flags:
|
||||
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
|
||||
g.mainDatInit.add(ropecg(m, "\t#initThreadVarsEmulation();$N", []))
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
|
||||
g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []))
|
||||
|
||||
if m.s[cfsInitProc].len > 0:
|
||||
@@ -1716,10 +1796,10 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R
|
||||
prc.typ.sym = nil
|
||||
|
||||
if not containsOrIncl(m.declaredThings, prc.id):
|
||||
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, skVar)])
|
||||
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, dkVar)])
|
||||
|
||||
result = "\t$1 = ($2) $3($4, $5);$n" %
|
||||
[tmp, getTypeDesc(m, prc.typ, skVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
|
||||
[tmp, getTypeDesc(m, prc.typ, dkVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
|
||||
|
||||
proc genInitCode(m: BModule) =
|
||||
## this function is called in cgenWriteModules after all modules are closed,
|
||||
@@ -1795,12 +1875,15 @@ proc genInitCode(m: BModule) =
|
||||
if beforeRetNeeded in m.initProc.flags:
|
||||
prc.add("\tBeforeRet_: ;\n")
|
||||
|
||||
if sfMainModule in m.module.flags and m.config.exc == excGoto:
|
||||
if m.config.exc == excGoto:
|
||||
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
|
||||
m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
|
||||
|
||||
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
|
||||
prc.add(deinitFrame(m.initProc))
|
||||
elif m.config.exc == excGoto:
|
||||
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
|
||||
m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
|
||||
|
||||
prc.addf("}$N", [])
|
||||
|
||||
@@ -1855,8 +1938,6 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
|
||||
openNamespaceNim(m.config.cppCustomNamespace, result)
|
||||
if m.s[cfsFrameDefines].len > 0:
|
||||
result.add(m.s[cfsFrameDefines])
|
||||
else:
|
||||
result.add("#define nimfr_(x, y)\n#define nimln_(x, y)\n")
|
||||
|
||||
for i in cfsForwardTypes..cfsProcs:
|
||||
if m.s[i].len > 0:
|
||||
@@ -1900,7 +1981,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
|
||||
result.preInitProc = newProc(nil, result)
|
||||
result.preInitProc.flags.incl nimErrorFlagDisabled
|
||||
result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated
|
||||
initNodeTable(result.dataCache)
|
||||
result.dataCache = initNodeTable()
|
||||
result.typeStack = @[]
|
||||
result.typeNodesName = getTempName(result)
|
||||
result.nimTypesName = getTempName(result)
|
||||
@@ -1929,10 +2010,7 @@ template injectG() {.dirty.} =
|
||||
graph.backend = newModuleList(graph)
|
||||
let g = BModuleList(graph.backend)
|
||||
|
||||
when not defined(nimHasSinkInference):
|
||||
{.pragma: nosinks.}
|
||||
|
||||
proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} =
|
||||
proc setupCgen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
injectG()
|
||||
result = newModule(g, module, graph.config)
|
||||
result.idgen = idgen
|
||||
@@ -2000,7 +2078,7 @@ proc addHcrInitGuards(p: BProc, n: PNode, inInitGuard: var bool) =
|
||||
|
||||
proc genTopLevelStmt*(m: BModule; n: PNode) =
|
||||
## Also called from `ic/cbackend.nim`.
|
||||
if passes.skipCodegen(m.config, n): return
|
||||
if pipelineutils.skipCodegen(m.config, n): return
|
||||
m.initProc.options = initProcOptions(m)
|
||||
#softRnl = if optLineDir in m.config.options: noRnl else: rnl
|
||||
# XXX replicate this logic!
|
||||
@@ -2013,12 +2091,6 @@ proc genTopLevelStmt*(m: BModule; n: PNode) =
|
||||
else:
|
||||
genProcBody(m.initProc, transformedN)
|
||||
|
||||
proc myProcess(b: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
if b != nil:
|
||||
var m = BModule(b)
|
||||
genTopLevelStmt(m, n)
|
||||
|
||||
proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
|
||||
if optForceFullMake notin m.config.globalOptions:
|
||||
if not moduleHasChanged(m.g.graph, m.module):
|
||||
@@ -2084,8 +2156,9 @@ proc updateCachedModule(m: BModule) =
|
||||
cf.flags = {CfileFlag.Cached}
|
||||
addFileToCompile(m.config, cf)
|
||||
|
||||
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
|
||||
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
|
||||
## Also called from IC.
|
||||
result = nil
|
||||
if sfMainModule in m.module.flags:
|
||||
# phase ordering problem here: We need to announce this
|
||||
# dependency to 'nimTestErrorFlag' before system.c has been written to disk.
|
||||
@@ -2095,7 +2168,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
|
||||
if {optGenStaticLib, optGenDynLib, optNoMain} * m.config.globalOptions == {}:
|
||||
for i in countdown(high(graph.globalDestructors), 0):
|
||||
n.add graph.globalDestructors[i]
|
||||
if passes.skipCodegen(m.config, n): return
|
||||
if pipelineutils.skipCodegen(m.config, n): return
|
||||
if moduleHasChanged(graph, m.module):
|
||||
# if the module is cached, we don't regenerate the main proc
|
||||
# nor the dispatchers? But if the dispatchers changed?
|
||||
@@ -2106,7 +2179,10 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
|
||||
|
||||
if m.hcrOn:
|
||||
# make sure this is pulled in (meaning hcrGetGlobal() is called for it during init)
|
||||
cgsym(m, "programResult")
|
||||
let sym = magicsys.getCompilerProc(m.g.graph, "programResult")
|
||||
# ignore when not available, could be a module imported early in `system`
|
||||
if sym != nil:
|
||||
cgsymImpl m, sym
|
||||
if m.inHcrInitGuard:
|
||||
endBlock(m.initProc)
|
||||
|
||||
@@ -2123,25 +2199,18 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
|
||||
cgsym(m, "rawWrite")
|
||||
|
||||
# raise dependencies on behalf of genMainProc
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
|
||||
cgsym(m, "initStackBottomWith")
|
||||
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
|
||||
cgsym(m, "initThreadVarsEmulation")
|
||||
|
||||
if m.g.forwardedProcs.len == 0:
|
||||
incl m.flags, objHasKidsValid
|
||||
let disp = generateMethodDispatchers(graph)
|
||||
for x in disp: genProcAux(m, x.sym)
|
||||
result = generateMethodDispatchers(graph, m.idgen)
|
||||
|
||||
let mm = m
|
||||
m.g.modulesClosed.add mm
|
||||
|
||||
|
||||
proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
if b == nil: return
|
||||
finalCodegenActions(graph, BModule(b), n)
|
||||
|
||||
proc genForwardedProcs(g: BModuleList) =
|
||||
# Forward declared proc:s lack bodies when first encountered, so they're given
|
||||
# a second pass here
|
||||
@@ -2168,5 +2237,3 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
|
||||
m.writeModule(pending=true)
|
||||
writeMapping(config, g.mapping)
|
||||
if g.generatedHeader != nil: writeHeader(g.generatedHeader)
|
||||
|
||||
const cgenPass* = makePass(myOpen, myProcess, myClose)
|
||||
|
||||
@@ -86,6 +86,7 @@ type
|
||||
options*: TOptions # options that should be used for code
|
||||
# generation; this is the same as prc.options
|
||||
# unless prc == nil
|
||||
optionsStack*: seq[TOptions]
|
||||
module*: BModule # used to prevent excessive parameter passing
|
||||
withinLoop*: int # > 0 if we are within a loop
|
||||
splitDecls*: int # > 0 if we are in some context for C++ that
|
||||
@@ -172,6 +173,7 @@ type
|
||||
|
||||
template config*(m: BModule): ConfigRef = m.g.config
|
||||
template config*(p: BProc): ConfigRef = p.module.g.config
|
||||
template vccAndC*(p: BProc): bool = p.module.config.cCompiler == ccVcc and p.module.config.backend == backendC
|
||||
|
||||
proc includeHeader*(this: BModule; header: string) =
|
||||
if not this.headerFiles.contains header:
|
||||
@@ -191,15 +193,17 @@ proc initBlock*(): TBlock =
|
||||
result.sections[i] = newRopeAppender()
|
||||
|
||||
proc newProc*(prc: PSym, module: BModule): BProc =
|
||||
new(result)
|
||||
result.prc = prc
|
||||
result.module = module
|
||||
result.options = if prc != nil: prc.options
|
||||
else: module.config.options
|
||||
result.blocks = @[initBlock()]
|
||||
result.nestedTryStmts = @[]
|
||||
result.finallySafePoints = @[]
|
||||
result.sigConflicts = initCountTable[string]()
|
||||
result = BProc(
|
||||
prc: prc,
|
||||
module: module,
|
||||
optionsStack: if module.initProc != nil: module.initProc.optionsStack
|
||||
else: @[],
|
||||
options: if prc != nil: prc.options
|
||||
else: module.config.options,
|
||||
blocks: @[initBlock()],
|
||||
sigConflicts: initCountTable[string]())
|
||||
if optQuirky in result.options:
|
||||
result.flags = {nimErrorFlagDisabled}
|
||||
|
||||
proc newModuleList*(g: ModuleGraph): BModuleList =
|
||||
BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: int32]](),
|
||||
|
||||
@@ -44,6 +44,8 @@ proc getDispatcher*(s: PSym): PSym =
|
||||
if dispatcherPos < s.ast.len:
|
||||
result = s.ast[dispatcherPos].sym
|
||||
doAssert sfDispatcher in result.flags
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc methodCall*(n: PNode; conf: ConfigRef): PNode =
|
||||
result = n
|
||||
@@ -62,6 +64,7 @@ type
|
||||
MethodResult = enum No, Invalid, Yes
|
||||
|
||||
proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
|
||||
result = No
|
||||
if a.name.id != b.name.id: return
|
||||
if a.typ.len != b.typ.len:
|
||||
return
|
||||
@@ -113,7 +116,7 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) =
|
||||
s.ast[dispatcherPos] = dispatcher
|
||||
|
||||
proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
|
||||
var disp = copySym(s, nextSymId(idgen))
|
||||
var disp = copySym(s, idgen)
|
||||
incl(disp.flags, sfDispatcher)
|
||||
excl(disp.flags, sfExported)
|
||||
let old = disp.typ
|
||||
@@ -127,7 +130,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
|
||||
disp.loc.r = ""
|
||||
if s.typ[0] != nil:
|
||||
if disp.ast.len > resultPos:
|
||||
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, nextSymId(idgen))
|
||||
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, idgen)
|
||||
else:
|
||||
# We've encountered a method prototype without a filled-in
|
||||
# resultPos slot. We put a placeholder in there that will
|
||||
@@ -149,7 +152,7 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
|
||||
disp.ast[resultPos] = copyTree(meth.ast[resultPos])
|
||||
|
||||
proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
|
||||
var witness: PSym
|
||||
var witness: PSym = nil
|
||||
for i in 0..<g.methods.len:
|
||||
let disp = g.methods[i].dispatcher
|
||||
case sameMethodBucket(disp, s, multimethods = optMultiMethods in g.config.globalOptions)
|
||||
@@ -178,6 +181,7 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
|
||||
|
||||
proc relevantCol(methods: seq[PSym], col: int): bool =
|
||||
# returns true iff the position is relevant
|
||||
result = false
|
||||
var t = methods[0].typ[col].skipTypes(skipPtrs)
|
||||
if t.kind == tyObject:
|
||||
for i in 1..high(methods):
|
||||
@@ -186,6 +190,7 @@ proc relevantCol(methods: seq[PSym], col: int): bool =
|
||||
return true
|
||||
|
||||
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
|
||||
result = 0
|
||||
for col in 1..<a.typ.len:
|
||||
if contains(relevantCols, col):
|
||||
var aa = skipTypes(a.typ[col], skipPtrs)
|
||||
@@ -213,7 +218,7 @@ proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
|
||||
a[j] = v
|
||||
if h == 1: break
|
||||
|
||||
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PSym =
|
||||
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym =
|
||||
var base = methods[0].ast[dispatcherPos].sym
|
||||
result = base
|
||||
var paramLen = base.typ.len
|
||||
@@ -272,7 +277,7 @@ proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PS
|
||||
nilchecks.flags.incl nfTransf # should not be further transformed
|
||||
result.ast[bodyPos] = nilchecks
|
||||
|
||||
proc generateMethodDispatchers*(g: ModuleGraph): PNode =
|
||||
proc generateMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator): PNode =
|
||||
result = newNode(nkStmtList)
|
||||
for bucket in 0..<g.methods.len:
|
||||
var relevantCols = initIntSet()
|
||||
@@ -282,4 +287,4 @@ proc generateMethodDispatchers*(g: ModuleGraph): PNode =
|
||||
# if multi-methods are not enabled, we are interested only in the first field
|
||||
break
|
||||
sortBucket(g.methods[bucket].methods, relevantCols)
|
||||
result.add newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols))
|
||||
result.add newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols, idgen))
|
||||
|
||||
@@ -183,7 +183,7 @@ proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode =
|
||||
ctx.newStateAssgn(newIntTypeNode(stateNo, ctx.g.getSysType(TLineInfo(), tyInt)))
|
||||
|
||||
proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
|
||||
result = newSym(skVar, getIdent(ctx.g.cache, name), nextSymId(ctx.idgen), ctx.fn, ctx.fn.info)
|
||||
result = newSym(skVar, getIdent(ctx.g.cache, name), ctx.idgen, ctx.fn, ctx.fn.info)
|
||||
result.typ = typ
|
||||
assert(not typ.isNil)
|
||||
|
||||
@@ -258,8 +258,9 @@ proc hasYields(n: PNode): bool =
|
||||
of nkYieldStmt:
|
||||
result = true
|
||||
of nkSkip:
|
||||
discard
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
for c in n:
|
||||
if c.hasYields:
|
||||
result = true
|
||||
@@ -325,7 +326,7 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
|
||||
var ifBranch: PNode
|
||||
|
||||
if c.len > 1:
|
||||
var cond: PNode
|
||||
var cond: PNode = nil
|
||||
for i in 0..<c.len - 1:
|
||||
assert(c[i].kind == nkType)
|
||||
let nextCond = newTree(nkCall,
|
||||
@@ -388,19 +389,22 @@ proc getFinallyNode(ctx: var Ctx, n: PNode): PNode =
|
||||
proc hasYieldsInExpressions(n: PNode): bool =
|
||||
case n.kind
|
||||
of nkSkip:
|
||||
discard
|
||||
result = false
|
||||
of nkStmtListExpr:
|
||||
if isEmptyType(n.typ):
|
||||
result = false
|
||||
for c in n:
|
||||
if c.hasYieldsInExpressions:
|
||||
return true
|
||||
else:
|
||||
result = n.hasYields
|
||||
of nkCast:
|
||||
result = false
|
||||
for i in 1..<n.len:
|
||||
if n[i].hasYieldsInExpressions:
|
||||
return true
|
||||
else:
|
||||
result = false
|
||||
for c in n:
|
||||
if c.hasYieldsInExpressions:
|
||||
return true
|
||||
@@ -495,7 +499,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||
|
||||
if ns:
|
||||
needsSplit = true
|
||||
var tmp: PSym
|
||||
var tmp: PSym = nil
|
||||
let isExpr = not isEmptyType(n.typ)
|
||||
if isExpr:
|
||||
tmp = ctx.newTempVar(n.typ)
|
||||
@@ -855,7 +859,9 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
|
||||
case n.kind
|
||||
of nkReturnStmt:
|
||||
# We're somewhere in try, transform to finally unrolling
|
||||
assert(ctx.nearestFinally != 0)
|
||||
if ctx.nearestFinally == 0:
|
||||
# return is within the finally
|
||||
return
|
||||
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
|
||||
@@ -1348,7 +1354,7 @@ proc freshVars(n: PNode; c: var FreshVarsContext): PNode =
|
||||
let idefs = copyNode(it)
|
||||
for v in 0..it.len-3:
|
||||
if it[v].kind == nkSym:
|
||||
let x = copySym(it[v].sym, nextSymId(c.idgen))
|
||||
let x = copySym(it[v].sym, c.idgen)
|
||||
c.tab[it[v].sym.id] = x
|
||||
idefs.add newSymNode(x)
|
||||
else:
|
||||
@@ -1359,6 +1365,7 @@ proc freshVars(n: PNode; c: var FreshVarsContext): PNode =
|
||||
else:
|
||||
result.add it
|
||||
of nkRaiseStmt:
|
||||
result = nil
|
||||
localError(c.config, c.info, "unsupported control flow: 'finally: ... raise' duplicated because of 'break'")
|
||||
else:
|
||||
result = n
|
||||
@@ -1389,7 +1396,7 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode =
|
||||
discard c.finallys.pop()
|
||||
|
||||
of nkWhileStmt, nkBlockStmt:
|
||||
if n.hasYields == false: return n
|
||||
if not n.hasYields: return n
|
||||
c.blocks.add((n, c.finallys.len))
|
||||
for i in 0 ..< n.len:
|
||||
result[i] = preprocess(c, n[i])
|
||||
@@ -1431,9 +1438,9 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
|
||||
# Lambda lifting was not done yet. Use temporary :state sym, which will
|
||||
# be handled specially by lambda lifting. Local temp vars (if needed)
|
||||
# should follow the same logic.
|
||||
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), nextSymId(idgen), fn, fn.info)
|
||||
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), idgen, fn, fn.info)
|
||||
ctx.stateVarSym.typ = g.createClosureIterStateType(fn, idgen)
|
||||
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), nextSymId(idgen), fn, fn.info)
|
||||
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), idgen, fn, fn.info)
|
||||
var pc = PreprocessContext(finallys: @[], config: g.config, idgen: idgen)
|
||||
var n = preprocess(pc, n.toStmtList)
|
||||
#echo "transformed into ", n
|
||||
@@ -1466,9 +1473,10 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
|
||||
result = ctx.transformStateAssignments(result)
|
||||
result = ctx.wrapIntoStateLoop(result)
|
||||
|
||||
# echo "TRANSFORM TO STATES: "
|
||||
# echo renderTree(result)
|
||||
when false:
|
||||
echo "TRANSFORM TO STATES: "
|
||||
echo renderTree(result)
|
||||
|
||||
# echo "exception table:"
|
||||
# for i, e in ctx.exceptionTable:
|
||||
# echo i, " -> ", e
|
||||
echo "exception table:"
|
||||
for i, e in ctx.exceptionTable:
|
||||
echo i, " -> ", e
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Helpers for binaries that use compiler passes, e.g.: nim, nimsuggest, nimfix
|
||||
## Helpers for binaries that use compiler passes, e.g.: nim, nimsuggest
|
||||
|
||||
import
|
||||
options, idents, nimconf, extccomp, commands, msgs,
|
||||
|
||||
@@ -184,7 +184,7 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
info: TLineInfo; orig: string; conf: ConfigRef) =
|
||||
var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off
|
||||
var i = 0
|
||||
var notes: set[TMsgKind]
|
||||
var notes: set[TMsgKind] = {}
|
||||
var isBracket = false
|
||||
if i < arg.len and arg[i] == '[':
|
||||
isBracket = true
|
||||
@@ -238,9 +238,9 @@ proc processCompile(conf: ConfigRef; filename: string) =
|
||||
extccomp.addExternalFileToCompile(conf, found)
|
||||
|
||||
const
|
||||
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', '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' or 'lib' expected, but '$1' found"
|
||||
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console', 'lib' or 'staticlib' expected, but '$1' found"
|
||||
errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found"
|
||||
|
||||
template warningOptionNoop(switch: string) =
|
||||
@@ -262,13 +262,18 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
|
||||
of "go": result = conf.selectedGC == gcGo
|
||||
of "none": result = conf.selectedGC == gcNone
|
||||
of "stack", "regions": result = conf.selectedGC == gcRegions
|
||||
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
|
||||
of "atomicarc": result = conf.selectedGC == gcAtomicArc
|
||||
else:
|
||||
result = false
|
||||
localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
|
||||
of "opt":
|
||||
case arg.normalize
|
||||
of "speed": result = contains(conf.options, optOptimizeSpeed)
|
||||
of "size": result = contains(conf.options, optOptimizeSize)
|
||||
of "none": result = conf.options * {optOptimizeSpeed, optOptimizeSize} == {}
|
||||
else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
|
||||
else:
|
||||
result = false
|
||||
localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
|
||||
of "verbosity": result = $conf.verbosity == arg
|
||||
of "app":
|
||||
case arg.normalize
|
||||
@@ -278,7 +283,9 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
|
||||
not contains(conf.globalOptions, optGenGuiApp)
|
||||
of "staticlib": result = contains(conf.globalOptions, optGenStaticLib) and
|
||||
not contains(conf.globalOptions, optGenGuiApp)
|
||||
else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
|
||||
else:
|
||||
result = false
|
||||
localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
|
||||
of "dynliboverride":
|
||||
result = isDynlibOverride(conf, arg)
|
||||
of "exceptions":
|
||||
@@ -287,8 +294,12 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
|
||||
of "setjmp": result = conf.exc == excSetjmp
|
||||
of "quirky": result = conf.exc == excQuirky
|
||||
of "goto": result = conf.exc == excGoto
|
||||
else: localError(conf, info, errInvalidExceptionSystem % arg)
|
||||
else: invalidCmdLineOption(conf, passCmd1, switch, info)
|
||||
else:
|
||||
result = false
|
||||
localError(conf, info, errInvalidExceptionSystem % arg)
|
||||
else:
|
||||
result = false
|
||||
invalidCmdLineOption(conf, passCmd1, switch, info)
|
||||
|
||||
proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool =
|
||||
case switch.normalize
|
||||
@@ -334,9 +345,14 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
|
||||
if switch.normalize == "patterns": deprecatedAlias(switch, "trmacros")
|
||||
result = contains(conf.options, optTrMacros)
|
||||
of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
|
||||
of "nilseqs", "nilchecks", "taintmode": warningOptionNoop(switch)
|
||||
of "nilseqs", "nilchecks", "taintmode":
|
||||
warningOptionNoop(switch)
|
||||
result = false
|
||||
of "panics": result = contains(conf.globalOptions, optPanics)
|
||||
else: invalidCmdLineOption(conf, passCmd1, switch, info)
|
||||
of "jsbigint64": result = contains(conf.globalOptions, optJsBigInt64)
|
||||
else:
|
||||
result = false
|
||||
invalidCmdLineOption(conf, passCmd1, switch, info)
|
||||
|
||||
proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
|
||||
notRelativeToProj = false): AbsoluteDir =
|
||||
@@ -378,7 +394,8 @@ proc makeAbsolute(s: string): AbsoluteFile =
|
||||
proc setTrackingInfo(conf: ConfigRef; dirty, file, line, column: string,
|
||||
info: TLineInfo) =
|
||||
## set tracking info, common code for track, trackDirty, & ideTrack
|
||||
var ln, col: int
|
||||
var ln: int = 0
|
||||
var col: int = 0
|
||||
if parseUtils.parseInt(line, ln) <= 0:
|
||||
localError(conf, info, errInvalidNumber % line)
|
||||
if parseUtils.parseInt(column, col) <= 0:
|
||||
@@ -515,14 +532,7 @@ proc initOrcDefines*(conf: ConfigRef) =
|
||||
if conf.exc == excNone and conf.backend != backendCpp:
|
||||
conf.exc = excGoto
|
||||
|
||||
proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef, isOrc: bool) =
|
||||
if isOrc:
|
||||
conf.selectedGC = gcOrc
|
||||
defineSymbol(conf.symbols, "gcorc")
|
||||
else:
|
||||
conf.selectedGC = gcArc
|
||||
defineSymbol(conf.symbols, "gcarc")
|
||||
|
||||
proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef) =
|
||||
defineSymbol(conf.symbols, "gcdestructors")
|
||||
incl conf.globalOptions, optSeqDestructors
|
||||
incl conf.globalOptions, optTinyRtti
|
||||
@@ -532,10 +542,11 @@ proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef, isOrc: bool) =
|
||||
if conf.exc == excNone and conf.backend != backendCpp:
|
||||
conf.exc = excGoto
|
||||
|
||||
proc unregisterArcOrc(conf: ConfigRef) =
|
||||
proc unregisterArcOrc*(conf: ConfigRef) =
|
||||
undefSymbol(conf.symbols, "gcdestructors")
|
||||
undefSymbol(conf.symbols, "gcarc")
|
||||
undefSymbol(conf.symbols, "gcorc")
|
||||
undefSymbol(conf.symbols, "gcatomicarc")
|
||||
undefSymbol(conf.symbols, "nimSeqsV2")
|
||||
undefSymbol(conf.symbols, "nimV2")
|
||||
excl conf.globalOptions, optSeqDestructors
|
||||
@@ -561,9 +572,17 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
|
||||
conf.selectedGC = gcMarkAndSweep
|
||||
defineSymbol(conf.symbols, "gcmarkandsweep")
|
||||
of "destructors", "arc":
|
||||
registerArcOrc(pass, conf, false)
|
||||
conf.selectedGC = gcArc
|
||||
defineSymbol(conf.symbols, "gcarc")
|
||||
registerArcOrc(pass, conf)
|
||||
of "orc":
|
||||
registerArcOrc(pass, conf, true)
|
||||
conf.selectedGC = gcOrc
|
||||
defineSymbol(conf.symbols, "gcorc")
|
||||
registerArcOrc(pass, conf)
|
||||
of "atomicarc":
|
||||
conf.selectedGC = gcAtomicArc
|
||||
defineSymbol(conf.symbols, "gcatomicarc")
|
||||
registerArcOrc(pass, conf)
|
||||
of "hooks":
|
||||
conf.selectedGC = gcHooks
|
||||
defineSymbol(conf.symbols, "gchooks")
|
||||
@@ -587,8 +606,8 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
|
||||
|
||||
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
conf: ConfigRef) =
|
||||
var
|
||||
key, val: string
|
||||
var key = ""
|
||||
var val = ""
|
||||
case switch.normalize
|
||||
of "eval":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
@@ -603,17 +622,17 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
for path in nimbleSubs(conf, arg):
|
||||
addPath(conf, if pass == passPP: processCfgPath(conf, path, info)
|
||||
else: processPath(conf, path, info), info)
|
||||
of "nimblepath", "babelpath":
|
||||
if switch.normalize == "babelpath": deprecatedAlias(switch, "nimblepath")
|
||||
of "nimblepath":
|
||||
if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions:
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
var path = processPath(conf, arg, info, notRelativeToProj=true)
|
||||
let nimbleDir = AbsoluteDir getEnv("NIMBLE_DIR")
|
||||
if not nimbleDir.isEmpty and pass == passPP:
|
||||
path = nimbleDir / RelativeDir"pkgs2"
|
||||
nimblePath(conf, path, info)
|
||||
path = nimbleDir / RelativeDir"pkgs"
|
||||
nimblePath(conf, path, info)
|
||||
of "nonimblepath", "nobabelpath":
|
||||
if switch.normalize == "nobabelpath": deprecatedAlias(switch, "nonimblepath")
|
||||
of "nonimblepath":
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
disableNimblePath(conf)
|
||||
of "clearnimblepath":
|
||||
@@ -649,6 +668,11 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "backend", "b":
|
||||
let backend = parseEnum(arg.normalize, TBackend.default)
|
||||
if backend == TBackend.default: localError(conf, info, "invalid backend: '$1'" % arg)
|
||||
if backend == backendJs: # bug #21209
|
||||
conf.globalOptions.excl {optThreadAnalysis, optThreads}
|
||||
if optRun in conf.globalOptions:
|
||||
# for now, -r uses nodejs, so define nodejs
|
||||
defineSymbol(conf.symbols, "nodejs")
|
||||
conf.backend = backend
|
||||
of "doccmd": conf.docCmd = arg
|
||||
of "define", "d":
|
||||
@@ -796,6 +820,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
defineSymbol(conf.symbols, "dll")
|
||||
of "staticlib":
|
||||
incl(conf.globalOptions, optGenStaticLib)
|
||||
incl(conf.globalOptions, optNoMain)
|
||||
excl(conf.globalOptions, optGenGuiApp)
|
||||
defineSymbol(conf.symbols, "library")
|
||||
defineSymbol(conf.symbols, "staticlib")
|
||||
@@ -819,8 +844,16 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "header":
|
||||
if conf != nil: conf.headerFile = arg
|
||||
incl(conf.globalOptions, optGenIndex)
|
||||
of "nimbasepattern":
|
||||
if conf != nil: conf.nimbasePattern = arg
|
||||
of "index":
|
||||
processOnOffSwitchG(conf, {optGenIndex}, arg, pass, info)
|
||||
case arg.normalize
|
||||
of "", "on": conf.globalOptions.incl {optGenIndex}
|
||||
of "only": conf.globalOptions.incl {optGenIndexOnly, optGenIndex}
|
||||
of "off": conf.globalOptions.excl {optGenIndex, optGenIndexOnly}
|
||||
else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
|
||||
of "noimportdoc":
|
||||
processOnOffSwitchG(conf, {optNoImportdoc}, arg, pass, info)
|
||||
of "import":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}:
|
||||
@@ -853,6 +886,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
setTarget(conf.target, conf.target.targetOS, cpu)
|
||||
of "run", "r":
|
||||
processOnOffSwitchG(conf, {optRun}, arg, pass, info)
|
||||
if conf.backend == backendJs:
|
||||
# for now, -r uses nodejs, so define nodejs
|
||||
defineSymbol(conf.symbols, "nodejs")
|
||||
of "maxloopiterationsvm":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
conf.maxLoopIterationsVM = parseInt(arg)
|
||||
@@ -867,7 +903,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "verbosity":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
let verbosity = parseInt(arg)
|
||||
if verbosity notin {0..3}:
|
||||
if verbosity notin 0..3:
|
||||
localError(conf, info, "invalid verbosity level: '$1'" % arg)
|
||||
conf.verbosity = verbosity
|
||||
var verb = NotesVerbosity[conf.verbosity]
|
||||
@@ -1000,6 +1036,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
conf.exc = low(ExceptionSystem)
|
||||
defineSymbol(conf.symbols, "noCppExceptions")
|
||||
of "shownonexports":
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
showNonExportedFields(conf)
|
||||
of "exceptions":
|
||||
case arg.normalize
|
||||
of "cpp": conf.exc = excCpp
|
||||
@@ -1054,29 +1093,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "expandarc":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
conf.arcToExpand[arg] = "T"
|
||||
of "useversion":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
case arg
|
||||
of "1.0":
|
||||
defineSymbol(conf.symbols, "NimMajor", "1")
|
||||
defineSymbol(conf.symbols, "NimMinor", "0")
|
||||
# old behaviors go here:
|
||||
defineSymbol(conf.symbols, "nimOldRelativePathBehavior")
|
||||
undefSymbol(conf.symbols, "nimDoesntTrackDefects")
|
||||
ast.eqTypeFlags.excl {tfGcSafe, tfNoSideEffect}
|
||||
conf.globalOptions.incl optNimV1Emulation
|
||||
of "1.2":
|
||||
defineSymbol(conf.symbols, "NimMajor", "1")
|
||||
defineSymbol(conf.symbols, "NimMinor", "2")
|
||||
conf.globalOptions.incl optNimV12Emulation
|
||||
of "1.6":
|
||||
defineSymbol(conf.symbols, "NimMajor", "1")
|
||||
defineSymbol(conf.symbols, "NimMinor", "6")
|
||||
conf.globalOptions.incl optNimV16Emulation
|
||||
else:
|
||||
localError(conf, info, "unknown Nim version; currently supported values are: `1.0`, `1.2`")
|
||||
# always be compatible with 1.x.100:
|
||||
defineSymbol(conf.symbols, "NimPatch", "100")
|
||||
of "benchmarkvm":
|
||||
processOnOffSwitchG(conf, {optBenchmarkVM}, arg, pass, info)
|
||||
of "profilevm":
|
||||
@@ -1090,6 +1106,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
processOnOffSwitchG(conf, {optPanics}, arg, pass, info)
|
||||
if optPanics in conf.globalOptions:
|
||||
defineSymbol(conf.symbols, "nimPanics")
|
||||
of "jsbigint64":
|
||||
processOnOffSwitchG(conf, {optJsBigInt64}, arg, pass, info)
|
||||
of "sourcemap": # xxx document in --fullhelp
|
||||
conf.globalOptions.incl optSourcemap
|
||||
conf.options.incl optLineDir
|
||||
@@ -1104,7 +1122,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
else: invalidCmdLineOption(conf, pass, switch, info)
|
||||
|
||||
proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
|
||||
var cmd, arg: string
|
||||
var cmd = ""
|
||||
var arg = ""
|
||||
splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo)
|
||||
processSwitch(cmd, arg, pass, gCmdLineInfo, config)
|
||||
|
||||
@@ -1131,7 +1150,10 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
|
||||
config.projectName = unixToNativePath(p.key)
|
||||
config.arguments = cmdLineRest(p)
|
||||
result = true
|
||||
elif pass != passCmd2: setCommandEarly(config, p.key)
|
||||
elif pass != passCmd2:
|
||||
setCommandEarly(config, p.key)
|
||||
result = false
|
||||
else: result = false
|
||||
else:
|
||||
if pass == passCmd1: config.commandArgs.add p.key
|
||||
if argsCount == 1:
|
||||
@@ -1142,4 +1164,6 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
|
||||
config.projectName = unixToNativePath(p.key)
|
||||
config.arguments = cmdLineRest(p)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
inc argsCount
|
||||
|
||||
28
compiler/compiler.nimble
Normal file
28
compiler/compiler.nimble
Normal file
@@ -0,0 +1,28 @@
|
||||
include "../lib/system/compilation.nim"
|
||||
version = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
||||
author = "Andreas Rumpf"
|
||||
description = "Compiler package providing the compiler sources as a library."
|
||||
license = "MIT"
|
||||
skipDirs = @["."]
|
||||
installDirs = @["compiler"]
|
||||
|
||||
import os
|
||||
|
||||
var compilerDir = ""
|
||||
|
||||
before install:
|
||||
rmDir("compiler")
|
||||
|
||||
let
|
||||
files = listFiles(".")
|
||||
dirs = listDirs(".")
|
||||
|
||||
mkDir("compiler")
|
||||
|
||||
for f in files:
|
||||
cpFile(f, "compiler" / f)
|
||||
|
||||
for d in dirs:
|
||||
cpDir(d, "compiler" / d)
|
||||
|
||||
requires "nim"
|
||||
@@ -27,7 +27,7 @@ const
|
||||
proc declareSelf(c: PContext; info: TLineInfo) =
|
||||
## Adds the magical 'Self' symbols to the current scope.
|
||||
let ow = getCurrOwner(c)
|
||||
let s = newSym(skType, getIdent(c.cache, "Self"), nextSymId(c.idgen), ow, info)
|
||||
let s = newSym(skType, getIdent(c.cache, "Self"), c.idgen, ow, info)
|
||||
s.typ = newType(tyTypeDesc, nextTypeId(c.idgen), ow)
|
||||
s.typ.flags.incl {tfUnresolved, tfPacked}
|
||||
s.typ.add newType(tyEmpty, nextTypeId(c.idgen), ow)
|
||||
@@ -62,7 +62,7 @@ proc semConceptDecl(c: PContext; n: PNode): PNode =
|
||||
result[i] = n[i]
|
||||
result[^1] = semConceptDecl(c, n[^1])
|
||||
of nkCommentStmt:
|
||||
discard
|
||||
result = n
|
||||
else:
|
||||
localError(c.config, n.info, "unexpected construct in the new-styled concept: " & renderTree(n))
|
||||
result = n
|
||||
@@ -121,8 +121,11 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
|
||||
for i in 0..<a.len:
|
||||
if not matchType(c, f[i], a[i], m): return false
|
||||
return true
|
||||
else:
|
||||
result = false
|
||||
|
||||
of tyGenericInvocation:
|
||||
result = false
|
||||
if a.kind == tyGenericInst and a[0].kind == tyGenericBody:
|
||||
if sameType(f[0], a[0]) and f.len == a.len-1:
|
||||
for i in 1 ..< f.len:
|
||||
@@ -156,15 +159,17 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
|
||||
result = matchType(c, old, ak, m)
|
||||
if m.magic == mArrPut and ak.kind == tyGenericParam:
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
#echo "B for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)
|
||||
|
||||
of tyVar, tySink, tyLent, tyOwned:
|
||||
# modifiers in the concept must be there in the actual implementation
|
||||
# too but not vice versa.
|
||||
if a.kind == f.kind:
|
||||
result = matchType(c, f.sons[0], a.sons[0], m)
|
||||
result = matchType(c, f[0], a[0], m)
|
||||
elif m.magic == mArrPut:
|
||||
result = matchType(c, f.sons[0], a, m)
|
||||
result = matchType(c, f[0], a, m)
|
||||
else:
|
||||
result = false
|
||||
of tyEnum, tyObject, tyDistinct:
|
||||
@@ -185,6 +190,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
|
||||
m.inferred.setLen oldLen
|
||||
of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr,
|
||||
tyGenericInst:
|
||||
result = false
|
||||
let ak = a.skipTypes(ignorableForArgType - {f.kind})
|
||||
if ak.kind == f.kind and f.len == ak.len:
|
||||
for i in 0..<ak.len:
|
||||
@@ -209,6 +215,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
|
||||
if not result:
|
||||
m.inferred.setLen oldLen
|
||||
else:
|
||||
result = false
|
||||
for i in 0..<f.len:
|
||||
result = matchType(c, f[i], a, m)
|
||||
if result: break # and remember the binding!
|
||||
@@ -257,7 +264,7 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
|
||||
m.inferred.setLen oldLen
|
||||
return false
|
||||
|
||||
if not matchReturnType(c, n[0].sym.typ.sons[0], candidate.typ.sons[0], m):
|
||||
if not matchReturnType(c, n[0].sym.typ[0], candidate.typ[0], m):
|
||||
m.inferred.setLen oldLen
|
||||
return false
|
||||
|
||||
@@ -274,7 +281,7 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
|
||||
proc matchSyms(c: PContext, n: PNode; kinds: set[TSymKind]; m: var MatchCon): bool =
|
||||
## Walk the current scope, extract candidates which the same name as 'n[namePos]',
|
||||
## 'n' is the nkProcDef or similar from the concept that we try to match.
|
||||
let candidates = searchInScopesFilterBy(c, n[namePos].sym.name, kinds)
|
||||
let candidates = searchInScopesAllCandidatesFilterBy(c, n[namePos].sym.name, kinds)
|
||||
for candidate in candidates:
|
||||
#echo "considering ", typeToString(candidate.typ), " ", candidate.magic
|
||||
m.magic = candidate.magic
|
||||
@@ -306,6 +313,8 @@ proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool =
|
||||
result = matchSyms(c, n, {skMethod}, m)
|
||||
of nkIteratorDef:
|
||||
result = matchSyms(c, n, {skIterator}, m)
|
||||
of nkCommentStmt:
|
||||
result = true
|
||||
else:
|
||||
# error was reported earlier.
|
||||
result = false
|
||||
|
||||
@@ -25,7 +25,7 @@ proc undefSymbol*(symbols: StringTableRef; symbol: string) =
|
||||
# result = if isDefined(symbol): gSymbols[symbol] else: nil
|
||||
|
||||
iterator definedSymbolNames*(symbols: StringTableRef): string =
|
||||
for key, val in pairs(symbols):
|
||||
for key in keys(symbols):
|
||||
yield key
|
||||
|
||||
proc countDefinedSymbols*(symbols: StringTableRef): int =
|
||||
@@ -45,10 +45,8 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimNewTypedesc") # deadcode
|
||||
defineSymbol("nimrequiresnimframe") # deadcode
|
||||
defineSymbol("nimparsebiggestfloatmagic") # deadcode
|
||||
defineSymbol("nimalias") # deadcode
|
||||
defineSymbol("nimlocks") # deadcode
|
||||
defineSymbol("nimnode") # deadcode pending `nimnode` reference in opengl package
|
||||
# refs https://github.com/nim-lang/opengl/pull/79
|
||||
defineSymbol("nimnode") # deadcode
|
||||
defineSymbol("nimvarargstyped") # deadcode
|
||||
defineSymbol("nimtypedescfixed") # deadcode
|
||||
defineSymbol("nimKnowsNimvm") # deadcode
|
||||
@@ -84,10 +82,24 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasSignatureHashInMacro") # deadcode
|
||||
defineSymbol("nimHasDefault") # deadcode
|
||||
defineSymbol("nimMacrosSizealignof") # deadcode
|
||||
defineSymbol("nimNoZeroExtendMagic") # deadcode
|
||||
defineSymbol("nimMacrosGetNodeId") # deadcode
|
||||
defineSymbol("nimFixedForwardGeneric") # deadcode
|
||||
defineSymbol("nimToOpenArrayCString") # deadcode
|
||||
defineSymbol("nimHasUsed") # deadcode
|
||||
defineSymbol("nimnomagic64") # deadcode
|
||||
defineSymbol("nimNewShiftOps") # deadcode
|
||||
defineSymbol("nimHasCursor") # deadcode
|
||||
defineSymbol("nimAlignPragma") # deadcode
|
||||
defineSymbol("nimHasExceptionsQuery") # deadcode
|
||||
defineSymbol("nimHasIsNamedTuple") # deadcode
|
||||
defineSymbol("nimHashOrdinalFixed") # deadcode
|
||||
defineSymbol("nimHasSinkInference") # deadcode
|
||||
defineSymbol("nimNewIntegerOps") # deadcode
|
||||
defineSymbol("nimHasInvariant") # deadcode
|
||||
|
||||
|
||||
|
||||
# > 0.20.0
|
||||
defineSymbol("nimNoZeroExtendMagic")
|
||||
defineSymbol("nimMacrosGetNodeId")
|
||||
for f in Feature:
|
||||
defineSymbol("nimHas" & $f)
|
||||
|
||||
@@ -98,31 +110,18 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
|
||||
defineSymbol("nimFixedOwned")
|
||||
defineSymbol("nimHasStyleChecks")
|
||||
defineSymbol("nimToOpenArrayCString")
|
||||
defineSymbol("nimHasUsed")
|
||||
defineSymbol("nimFixedForwardGeneric")
|
||||
defineSymbol("nimnomagic64")
|
||||
defineSymbol("nimNewShiftOps")
|
||||
defineSymbol("nimHasCursor")
|
||||
defineSymbol("nimAlignPragma")
|
||||
defineSymbol("nimHasExceptionsQuery")
|
||||
defineSymbol("nimHasIsNamedTuple")
|
||||
defineSymbol("nimHashOrdinalFixed")
|
||||
|
||||
when defined(nimHasLibFFI):
|
||||
# Renaming as we can't conflate input vs output define flags; e.g. this
|
||||
# will report the right thing regardless of whether user adds
|
||||
# `-d:nimHasLibFFI` in his user config.
|
||||
defineSymbol("nimHasLibFFIEnabled")
|
||||
defineSymbol("nimHasLibFFIEnabled") # deadcode
|
||||
|
||||
defineSymbol("nimHasSinkInference")
|
||||
defineSymbol("nimNewIntegerOps")
|
||||
defineSymbol("nimHasInvariant")
|
||||
defineSymbol("nimHasStacktraceMsgs")
|
||||
defineSymbol("nimHasStacktraceMsgs") # deadcode
|
||||
defineSymbol("nimDoesntTrackDefects")
|
||||
defineSymbol("nimHasLentIterators")
|
||||
defineSymbol("nimHasDeclaredMagic")
|
||||
defineSymbol("nimHasStacktracesModule")
|
||||
defineSymbol("nimHasLentIterators") # deadcode
|
||||
defineSymbol("nimHasDeclaredMagic") # deadcode
|
||||
defineSymbol("nimHasStacktracesModule") # deadcode
|
||||
defineSymbol("nimHasEffectTraitsModule")
|
||||
defineSymbol("nimHasCastPragmaBlocks")
|
||||
defineSymbol("nimHasDeclaredLocs")
|
||||
@@ -133,8 +132,8 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasCustomLiterals")
|
||||
defineSymbol("nimHasUnifiedTuple")
|
||||
defineSymbol("nimHasIterable")
|
||||
defineSymbol("nimHasTypeofVoid")
|
||||
defineSymbol("nimHasDragonBox")
|
||||
defineSymbol("nimHasTypeofVoid") # deadcode
|
||||
defineSymbol("nimHasDragonBox") # deadcode
|
||||
defineSymbol("nimHasHintAll")
|
||||
defineSymbol("nimHasTrace")
|
||||
defineSymbol("nimHasEffectsOf")
|
||||
@@ -146,6 +145,19 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasCallsitePragma")
|
||||
defineSymbol("nimHasAmbiguousEnumHint")
|
||||
|
||||
defineSymbol("nimHasWarnCastSizes") # deadcode
|
||||
defineSymbol("nimHasOutParams")
|
||||
defineSymbol("nimHasSystemRaisesDefect")
|
||||
defineSymbol("nimHasWarnUnnamedBreak")
|
||||
defineSymbol("nimHasGenericDefine")
|
||||
defineSymbol("nimHasDefineAliases")
|
||||
defineSymbol("nimHasWarnBareExcept")
|
||||
defineSymbol("nimHasDup")
|
||||
defineSymbol("nimHasChecksums")
|
||||
defineSymbol("nimHasSendable")
|
||||
defineSymbol("nimAllowNonVarDestructor")
|
||||
defineSymbol("nimHasQuirky")
|
||||
defineSymbol("nimHasEnsureMove")
|
||||
|
||||
defineSymbol("nimUseStrictDefs")
|
||||
defineSymbol("nimHasNolineTooLong")
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
# This module implements a dependency file generator.
|
||||
|
||||
import options, ast, ropes, passes, pathutils, msgs, lineinfos
|
||||
import options, ast, ropes, pathutils, msgs, lineinfos
|
||||
|
||||
import modulegraphs
|
||||
|
||||
@@ -42,7 +42,7 @@ proc toNimblePath(s: string, isStdlib: bool): string =
|
||||
let sub = "lib/"
|
||||
var start = s.find(sub)
|
||||
if start < 0:
|
||||
doAssert false
|
||||
raiseAssert "unreachable"
|
||||
else:
|
||||
start += sub.len
|
||||
let base = s[start..^1]
|
||||
@@ -63,12 +63,16 @@ proc toNimblePath(s: string, isStdlib: bool): string =
|
||||
sub.add "/pkgs/"
|
||||
var start = s.find(sub)
|
||||
if start < 0:
|
||||
result = s
|
||||
else:
|
||||
start += sub.len
|
||||
start += skipUntil(s, '/', start)
|
||||
start += 1
|
||||
result = pkgPrefix & s[start..^1]
|
||||
sub[^1] = '2'
|
||||
sub.add '/'
|
||||
start = s.find(sub) # /pkgs2
|
||||
if start < 0:
|
||||
return s
|
||||
|
||||
start += sub.len
|
||||
start += skipUntil(s, '/', start)
|
||||
start += 1
|
||||
result = pkgPrefix & s[start..^1]
|
||||
|
||||
proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
|
||||
doAssert n.kind == nkSym, $n.kind
|
||||
@@ -79,7 +83,7 @@ proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
|
||||
let child = nativeToUnixPath(path.dir / path.name).toNimblePath(belongsToStdlib(g.graph, n.sym))
|
||||
addDependencyAux(b, parent, child)
|
||||
|
||||
proc addDotDependency(c: PPassContext, n: PNode): PNode =
|
||||
proc addDotDependency*(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
let g = PGen(c)
|
||||
let b = Backend(g.graph.backend)
|
||||
@@ -100,18 +104,7 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
|
||||
rope(project.splitFile.name), b.dotGraph],
|
||||
changeFileExt(project, "dot"))
|
||||
|
||||
when not defined(nimHasSinkInference):
|
||||
{.pragma: nosinks.}
|
||||
|
||||
proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} =
|
||||
var g: PGen
|
||||
new(g)
|
||||
g.module = module
|
||||
g.config = graph.config
|
||||
g.graph = graph
|
||||
proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
result = PGen(module: module, config: graph.config, graph: graph)
|
||||
if graph.backend == nil:
|
||||
graph.backend = Backend(dotGraph: "")
|
||||
result = g
|
||||
|
||||
const gendependPass* = makePass(open = myOpen, process = addDotDependency)
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ type
|
||||
proc codeListing(c: ControlFlowGraph, start = 0; last = -1): string =
|
||||
# for debugging purposes
|
||||
# first iteration: compute all necessary labels:
|
||||
result = ""
|
||||
var jumpTargets = initIntSet()
|
||||
let last = if last < 0: c.len-1 else: min(last, c.len-1)
|
||||
for i in start..last:
|
||||
@@ -111,7 +112,7 @@ proc patch(c: var Con, p: TPosition) =
|
||||
proc gen(c: var Con; n: PNode)
|
||||
|
||||
proc popBlock(c: var Con; oldLen: int) =
|
||||
var exits: seq[TPosition]
|
||||
var exits: seq[TPosition] = @[]
|
||||
exits.add c.gotoI()
|
||||
for f in c.blocks[oldLen].breakFixups:
|
||||
c.patch(f[0])
|
||||
@@ -263,8 +264,9 @@ proc genBreakOrRaiseAux(c: var Con, i: int, n: PNode) =
|
||||
if c.blocks[i].isTryBlock:
|
||||
c.blocks[i].raiseFixups.add lab1
|
||||
else:
|
||||
var trailingFinales: seq[PNode]
|
||||
if c.inTryStmt > 0: #Ok, we are in a try, lets see which (if any) try's we break out from:
|
||||
var trailingFinales: seq[PNode] = @[]
|
||||
if c.inTryStmt > 0:
|
||||
# Ok, we are in a try, lets see which (if any) try's we break out from:
|
||||
for b in countdown(c.blocks.high, i):
|
||||
if c.blocks[b].isTryBlock:
|
||||
trailingFinales.add c.blocks[b].finale
|
||||
@@ -385,7 +387,8 @@ proc genCall(c: var Con; n: PNode) =
|
||||
# Pass by 'out' is a 'must def'. Good enough for a move optimizer.
|
||||
genDef(c, n[i])
|
||||
# every call can potentially raise:
|
||||
if false: # c.inTryStmt > 0 and canRaiseConservative(n[0]):
|
||||
if c.inTryStmt > 0 and canRaiseConservative(n[0]):
|
||||
inc c.interestingInstructions
|
||||
# we generate the instruction sequence:
|
||||
# fork lab1
|
||||
# goto exceptionHandler (except or finally)
|
||||
@@ -467,7 +470,7 @@ proc gen(c: var Con; n: PNode) =
|
||||
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, PathKinds1:
|
||||
gen(c, n[1])
|
||||
of nkVarSection, nkLetSection: genVarSection(c, n)
|
||||
of nkDefer: doAssert false, "dfa construction pass requires the elimination of 'defer'"
|
||||
of nkDefer: raiseAssert "dfa construction pass requires the elimination of 'defer'"
|
||||
else: discard
|
||||
|
||||
when false:
|
||||
@@ -493,7 +496,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):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
result = c.code # will move
|
||||
else:
|
||||
shallowCopy(result, c.code)
|
||||
|
||||
@@ -7,13 +7,17 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# This is the documentation generator. Cross-references are generated
|
||||
# by knowing how the anchors are going to be named.
|
||||
## This is the Nim documentation generator. Cross-references are generated
|
||||
## by knowing how the anchors are going to be named.
|
||||
##
|
||||
## .. importdoc:: ../docgen.md
|
||||
##
|
||||
## For corresponding users' documentation see [Nim DocGen Tools Guide].
|
||||
|
||||
import
|
||||
ast, strutils, strtabs, algorithm, sequtils, options, msgs, os, idents,
|
||||
wordrecg, syntaxes, renderer, lexer,
|
||||
packages/docutils/[rst, rstgen, dochelpers],
|
||||
packages/docutils/[rst, rstidx, rstgen, dochelpers],
|
||||
json, xmltree, trees, types,
|
||||
typesrenderer, astalgo, lineinfos, intsets,
|
||||
pathutils, tables, nimpaths, renderverbatim, osproc, packages
|
||||
@@ -91,7 +95,7 @@ type
|
||||
jEntriesFinal: JsonNode # final JSON after RST pass 2 and rendering
|
||||
types: TStrTable
|
||||
sharedState: PRstSharedState
|
||||
standaloneDoc: bool
|
||||
standaloneDoc: bool # is markup (.rst/.md) document?
|
||||
conf*: ConfigRef
|
||||
cache*: IdentCache
|
||||
exampleCounter: int
|
||||
@@ -108,13 +112,16 @@ type
|
||||
proc add(dest: var ItemPre, rst: PRstNode) = dest.add ItemFragment(isRst: true, rst: rst)
|
||||
proc add(dest: var ItemPre, str: string) = dest.add ItemFragment(isRst: false, str: str)
|
||||
|
||||
proc addRstFileIndex(d: PDoc, info: lineinfos.TLineInfo): rstast.FileIndex =
|
||||
proc addRstFileIndex(d: PDoc, fileIndex: lineinfos.FileIndex): rstast.FileIndex =
|
||||
let invalid = rstast.FileIndex(-1)
|
||||
result = d.nimToRstFid.getOrDefault(info.fileIndex, default = invalid)
|
||||
result = d.nimToRstFid.getOrDefault(fileIndex, default = invalid)
|
||||
if result == invalid:
|
||||
let fname = toFullPath(d.conf, info)
|
||||
let fname = toFullPath(d.conf, fileIndex)
|
||||
result = addFilename(d.sharedState, fname)
|
||||
d.nimToRstFid[info.fileIndex] = result
|
||||
d.nimToRstFid[fileIndex] = result
|
||||
|
||||
proc addRstFileIndex(d: PDoc, info: lineinfos.TLineInfo): rstast.FileIndex =
|
||||
addRstFileIndex(d, info.fileIndex)
|
||||
|
||||
proc cmpDecimalsIgnoreCase(a, b: string): int =
|
||||
## For sorting with correct handling of cases like 'uint8' and 'uint16'.
|
||||
@@ -163,6 +170,7 @@ proc cmpDecimalsIgnoreCase(a, b: string): int =
|
||||
|
||||
proc prettyString(a: object): string =
|
||||
# xxx pending std/prettyprint refs https://github.com/nim-lang/RFCs/issues/203#issuecomment-602534906
|
||||
result = ""
|
||||
for k, v in fieldPairs(a):
|
||||
result.add k & ": " & $v & "\n"
|
||||
|
||||
@@ -208,12 +216,16 @@ proc whichType(d: PDoc; n: PNode): PSym =
|
||||
if n.kind == nkSym:
|
||||
if d.types.strTableContains(n.sym):
|
||||
result = n.sym
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
result = nil
|
||||
for i in 0..<n.safeLen:
|
||||
let x = whichType(d, n[i])
|
||||
if x != nil: return x
|
||||
|
||||
proc attachToType(d: PDoc; p: PSym): PSym =
|
||||
result = nil
|
||||
let params = p.ast[paramsPos]
|
||||
template check(i) =
|
||||
result = whichType(d, params[i])
|
||||
@@ -225,7 +237,7 @@ proc attachToType(d: PDoc; p: PSym): PSym =
|
||||
if params.len > 0: check(0)
|
||||
for i in 2..<params.len: check(i)
|
||||
|
||||
template declareClosures =
|
||||
template declareClosures(currentFilename: AbsoluteFile, destFile: string) =
|
||||
proc compilerMsgHandler(filename: string, line, col: int,
|
||||
msgKind: rst.MsgKind, arg: string) {.gcsafe.} =
|
||||
# translate msg kind:
|
||||
@@ -249,9 +261,19 @@ template declareClosures =
|
||||
of mwBrokenLink: k = warnRstBrokenLink
|
||||
of mwUnsupportedLanguage: k = warnRstLanguageXNotSupported
|
||||
of mwUnsupportedField: k = warnRstFieldXNotSupported
|
||||
of mwUnusedImportdoc: k = warnRstUnusedImportdoc
|
||||
of mwRstStyle: k = warnRstStyle
|
||||
{.gcsafe.}:
|
||||
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
|
||||
let errorsAsWarnings = (roPreferMarkdown in d.sharedState.options) and
|
||||
not d.standaloneDoc # not tolerate errors in .rst/.md files
|
||||
if whichMsgClass(msgKind) == mcError and errorsAsWarnings:
|
||||
liMessage(conf, newLineInfo(conf, AbsoluteFile filename, line, col),
|
||||
k, arg, doNothing, instLoc(), ignoreError=true)
|
||||
# when our Markdown parser fails, we currently can only terminate the
|
||||
# parsing (and then we will return monospaced text instead of markup):
|
||||
raiseRecoverableError("")
|
||||
else:
|
||||
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
|
||||
|
||||
proc docgenFindFile(s: string): string {.gcsafe.} =
|
||||
result = options.findFile(conf, s).string
|
||||
@@ -259,10 +281,29 @@ template declareClosures =
|
||||
result = getCurrentDir() / s
|
||||
if not fileExists(result): result = ""
|
||||
|
||||
proc docgenFindRefFile(targetRelPath: string):
|
||||
tuple[targetPath: string, linkRelPath: string] {.gcsafe.} =
|
||||
let fromDir = splitFile(destFile).dir # dir where we reference from
|
||||
let basedir = os.splitFile(currentFilename.string).dir
|
||||
let outDirPath: RelativeFile =
|
||||
presentationPath(conf, AbsoluteFile(basedir / targetRelPath))
|
||||
# use presentationPath because `..` path can be be mangled to `_._`
|
||||
result.targetPath = string(conf.outDir / outDirPath)
|
||||
if not fileExists(result.targetPath):
|
||||
# this can happen if targetRelPath goes to parent directory `OUTDIR/..`.
|
||||
# Trying it, this may cause ambiguities, but allows us to insert
|
||||
# "packages" into each other, which is actually used in Nim repo itself.
|
||||
let destPath = fromDir / targetRelPath
|
||||
if destPath != result.targetPath and fileExists(destPath):
|
||||
result.targetPath = destPath
|
||||
|
||||
result.linkRelPath = relativePath(result.targetPath.splitFile.dir,
|
||||
fromDir).replace('\\', '/')
|
||||
|
||||
|
||||
proc parseRst(text: string,
|
||||
line, column: int,
|
||||
conf: ConfigRef, sharedState: PRstSharedState): PRstNode =
|
||||
declareClosures()
|
||||
result = rstParsePass1(text, line, column, sharedState)
|
||||
|
||||
proc getOutFile2(conf: ConfigRef; filename: RelativeFile,
|
||||
@@ -283,8 +324,10 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
|
||||
outExt: string = HtmlExt, module: PSym = nil,
|
||||
standaloneDoc = false, preferMarkdown = true,
|
||||
hasToc = true): PDoc =
|
||||
declareClosures()
|
||||
let destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false).string
|
||||
new(result)
|
||||
let d = result # pass `d` to `declareClosures`:
|
||||
declareClosures(currentFilename = filename, destFile = destFile)
|
||||
result.module = module
|
||||
result.conf = conf
|
||||
result.cache = cache
|
||||
@@ -298,14 +341,14 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
|
||||
result.hasToc = hasToc
|
||||
result.sharedState = newRstSharedState(
|
||||
options, filename.string,
|
||||
docgenFindFile, compilerMsgHandler, hasToc)
|
||||
docgenFindFile, docgenFindRefFile, compilerMsgHandler, hasToc)
|
||||
initRstGenerator(result[], (if conf.isLatexCmd: outLatex else: outHtml),
|
||||
conf.configVars, filename.string,
|
||||
docgenFindFile, compilerMsgHandler)
|
||||
|
||||
if conf.configVars.hasKey("doc.googleAnalytics") and
|
||||
conf.configVars.hasKey("doc.plausibleAnalytics"):
|
||||
doAssert false, "Either use googleAnalytics or plausibleAnalytics"
|
||||
raiseAssert "Either use googleAnalytics or plausibleAnalytics"
|
||||
|
||||
if conf.configVars.hasKey("doc.googleAnalytics"):
|
||||
result.analytics = """
|
||||
@@ -330,7 +373,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
|
||||
result.seenSymbols = newStringTable(modeCaseInsensitive)
|
||||
result.id = 100
|
||||
result.jEntriesFinal = newJArray()
|
||||
initStrTable result.types
|
||||
result.types = initStrTable()
|
||||
result.onTestSnippet =
|
||||
proc (gen: var RstGenerator; filename, cmd: string; status: int; content: string) {.gcsafe.} =
|
||||
if conf.docCmd == docCmdSkip: return
|
||||
@@ -373,7 +416,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
|
||||
if gotten != status:
|
||||
rawMessage(conf, errGenerated, "snippet failed: cmd: '$1' status: $2 expected: $3 output: $4" % [cmd, $gotten, $status, output])
|
||||
result.emitted = initIntSet()
|
||||
result.destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false).string
|
||||
result.destFile = destFile
|
||||
result.thisDir = result.destFile.AbsoluteFile.splitFile.dir
|
||||
|
||||
template dispA(conf: ConfigRef; dest: var string, xml, tex: string,
|
||||
@@ -390,16 +433,21 @@ proc getVarIdx(varnames: openArray[string], id: string): int =
|
||||
proc genComment(d: PDoc, n: PNode): PRstNode =
|
||||
if n.comment.len > 0:
|
||||
d.sharedState.currFileIdx = addRstFileIndex(d, n.info)
|
||||
result = parseRst(n.comment,
|
||||
toLinenumber(n.info),
|
||||
toColumn(n.info) + DocColOffset,
|
||||
d.conf, d.sharedState)
|
||||
try:
|
||||
result = parseRst(n.comment,
|
||||
toLinenumber(n.info),
|
||||
toColumn(n.info) + DocColOffset,
|
||||
d.conf, d.sharedState)
|
||||
except ERecoverableError:
|
||||
result = newRstNode(rnLiteralBlock, @[newRstLeaf(n.comment)])
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc genRecCommentAux(d: PDoc, n: PNode): PRstNode =
|
||||
if n == nil: return nil
|
||||
result = genComment(d, n)
|
||||
if result == nil:
|
||||
if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef,
|
||||
if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef, nkTypeClassTy,
|
||||
nkObjectTy, nkRefTy, nkPtrTy, nkAsgn, nkFastAsgn, nkSinkAsgn, nkHiddenStdConv}:
|
||||
# notin {nkEmpty..nkNilLit, nkEnumTy, nkTupleTy}:
|
||||
for i in 0..<n.len:
|
||||
@@ -428,6 +476,7 @@ proc getPlainDocstring(n: PNode): string =
|
||||
elif startsWith(n.comment, "##"):
|
||||
result = n.comment
|
||||
else:
|
||||
result = ""
|
||||
for i in 0..<n.safeLen:
|
||||
result = getPlainDocstring(n[i])
|
||||
if result.len > 0: return
|
||||
@@ -443,9 +492,8 @@ proc externalDep(d: PDoc; module: PSym): string =
|
||||
proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string;
|
||||
renderFlags: TRenderFlags = {};
|
||||
procLink: string) =
|
||||
var r: TSrcGen
|
||||
var r: TSrcGen = initTokRender(n, renderFlags)
|
||||
var literal = ""
|
||||
initTokRender(r, n, renderFlags)
|
||||
var kind = tkEof
|
||||
var tokenPos = 0
|
||||
var procTokenPos = 0
|
||||
@@ -537,10 +585,13 @@ proc runAllExamples(d: PDoc) =
|
||||
# most useful semantics is that `docCmd` comes after `rdoccmd`, so that we can (temporarily) override
|
||||
# via command line
|
||||
# D20210224T221756:here
|
||||
let cmd = "$nim $backend -r --lib:$libpath --warning:UnusedImport:off --path:$path --nimcache:$nimcache $rdoccmd $docCmd $file" % [
|
||||
var pathArgs = "--path:$path" % [ "path", quoteShell(d.conf.projectPath) ]
|
||||
for p in d.conf.searchPaths:
|
||||
pathArgs = "$args --path:$path" % [ "args", pathArgs, "path", quoteShell(p) ]
|
||||
let cmd = "$nim $backend -r --lib:$libpath --warning:UnusedImport:off $pathArgs --nimcache:$nimcache $rdoccmd $docCmd $file" % [
|
||||
"nim", quoteShell(os.getAppFilename()),
|
||||
"backend", $d.conf.backend,
|
||||
"path", quoteShell(d.conf.projectPath),
|
||||
"pathArgs", pathArgs,
|
||||
"libpath", quoteShell(d.conf.libpath),
|
||||
"nimcache", quoteShell(outputDir),
|
||||
"file", quoteShell(outp),
|
||||
@@ -556,9 +607,11 @@ proc runAllExamples(d: PDoc) =
|
||||
rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
|
||||
# removeFile(outp.changeFileExt(ExeExt)) # it's in nimcache, no need to remove
|
||||
|
||||
proc quoted(a: string): string = result.addQuoted(a)
|
||||
proc quoted(a: string): string =
|
||||
result = ""
|
||||
result.addQuoted(a)
|
||||
|
||||
proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): auto =
|
||||
proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): (string, int, int) =
|
||||
# xxx expose in compiler/lineinfos.nim
|
||||
(conf.toMsgFilename(info), info.line.int, info.col.int + ColOffset)
|
||||
|
||||
@@ -575,7 +628,6 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c
|
||||
let useRenderModule = false
|
||||
let loc = d.conf.toFileLineCol(n.info)
|
||||
let code = extractRunnableExamplesSource(d.conf, n)
|
||||
let codeIndent = extractRunnableExamplesSource(d.conf, n, indent = 2)
|
||||
|
||||
if d.conf.errorCounter > 0:
|
||||
return (rdoccmd, code)
|
||||
@@ -591,6 +643,7 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c
|
||||
docComment.comment = comment
|
||||
var runnableExamples = newTree(nkStmtList,
|
||||
docComment,
|
||||
newTree(nkImportStmt, newStrNode(nkStrLit, "std/assertions")),
|
||||
newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
|
||||
runnableExamples.info = n.info
|
||||
for a in n.lastSon: runnableExamples.add a
|
||||
@@ -604,6 +657,7 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c
|
||||
else:
|
||||
var code2 = code
|
||||
if code.len > 0 and "codeReordering" notin code:
|
||||
let codeIndent = extractRunnableExamplesSource(d.conf, n, indent = 2)
|
||||
# hacky but simplest solution, until we devise a way to make `{.line.}`
|
||||
# work without introducing a scope
|
||||
code2 = """
|
||||
@@ -614,6 +668,7 @@ $#
|
||||
#[
|
||||
$#
|
||||
]#
|
||||
import std/assertions
|
||||
import $#
|
||||
$#
|
||||
""" % [comment, d.filename.quoted, code2]
|
||||
@@ -680,7 +735,7 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var ItemPre,
|
||||
let (rdoccmd, code) = prepareExample(d, n, topLevel)
|
||||
var msg = "Example:"
|
||||
if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd
|
||||
var s: string
|
||||
var s: string = ""
|
||||
dispA(d.conf, s, "\n<p><strong class=\"examples_text\">$1</strong></p>\n",
|
||||
"\n\n\\textbf{$1}\n", [msg])
|
||||
dest.add s
|
||||
@@ -765,21 +820,24 @@ proc isVisible(d: PDoc; n: PNode): bool =
|
||||
elif n.kind == nkPragmaExpr:
|
||||
result = isVisible(d, n[0])
|
||||
|
||||
proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
|
||||
proc getName(n: PNode): string =
|
||||
case n.kind
|
||||
of nkPostfix: result = getName(d, n[1], splitAfter)
|
||||
of nkPragmaExpr: result = getName(d, n[0], splitAfter)
|
||||
of nkSym: result = esc(d.target, n.sym.renderDefinitionName, splitAfter)
|
||||
of nkIdent: result = esc(d.target, n.ident.s, splitAfter)
|
||||
of nkPostfix: result = getName(n[1])
|
||||
of nkPragmaExpr: result = getName(n[0])
|
||||
of nkSym: result = n.sym.renderDefinitionName
|
||||
of nkIdent: result = n.ident.s
|
||||
of nkAccQuoted:
|
||||
result = esc(d.target, "`")
|
||||
for i in 0..<n.len: result.add(getName(d, n[i], splitAfter))
|
||||
result.add esc(d.target, "`")
|
||||
result = "`"
|
||||
for i in 0..<n.len: result.add(getName(n[i]))
|
||||
result = "`"
|
||||
of nkOpenSymChoice, nkClosedSymChoice:
|
||||
result = getName(d, n[0], splitAfter)
|
||||
result = getName(n[0])
|
||||
else:
|
||||
result = ""
|
||||
|
||||
proc getNameEsc(d: PDoc, n: PNode): string =
|
||||
esc(d.target, getName(n))
|
||||
|
||||
proc getNameIdent(cache: IdentCache; n: PNode): PIdent =
|
||||
case n.kind
|
||||
of nkPostfix: result = getNameIdent(cache, n[1])
|
||||
@@ -893,14 +951,17 @@ proc genDeprecationMsg(d: PDoc, n: PNode): string =
|
||||
if n[1].kind in {nkStrLit..nkTripleStrLit}:
|
||||
result = getConfigVar(d.conf, "doc.deprecationmsg") % [
|
||||
"label", "Deprecated:", "message", xmltree.escape(n[1].strVal)]
|
||||
else:
|
||||
result = ""
|
||||
else:
|
||||
doAssert false
|
||||
raiseAssert "unreachable"
|
||||
|
||||
type DocFlags = enum
|
||||
kDefault
|
||||
kForceExport
|
||||
|
||||
proc genSeeSrc(d: PDoc, path: string, line: int): string =
|
||||
result = ""
|
||||
let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc")
|
||||
if docItemSeeSrc.len > 0:
|
||||
let path = relativeTo(AbsoluteFile path, AbsoluteDir getCurrentDir(), '/')
|
||||
@@ -928,6 +989,13 @@ proc symbolPriority(k: TSymKind): int =
|
||||
else: 0 # including skProc which have higher priority
|
||||
# documentation itself has even higher priority 1
|
||||
|
||||
proc getTypeKind(n: PNode): string =
|
||||
case n[2].kind
|
||||
of nkEnumTy: "enum"
|
||||
of nkObjectTy: "object"
|
||||
of nkTupleTy: "tuple"
|
||||
else: ""
|
||||
|
||||
proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
|
||||
## Converts symbol info (names/types/parameters) in `n` into format
|
||||
## `LangSymbol` convenient for ``rst.nim``/``dochelpers.nim``.
|
||||
@@ -935,7 +1003,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
|
||||
result.symKind = k.toHumanStr
|
||||
if k in routineKinds:
|
||||
var
|
||||
paramTypes: seq[string]
|
||||
paramTypes: seq[string] = @[]
|
||||
renderParamTypes(paramTypes, n[paramsPos], toNormalize=true)
|
||||
let paramNames = renderParamNames(n[paramsPos], toNormalize=true)
|
||||
# In some rare cases (system.typeof) parameter type is not set for default:
|
||||
@@ -960,9 +1028,8 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
|
||||
genNode = n[miscPos][1] # FIXME: what is index 1?
|
||||
if genNode != nil:
|
||||
var literal = ""
|
||||
var r: TSrcGen
|
||||
initTokRender(r, genNode, {renderNoBody, renderNoComments,
|
||||
renderNoPragmas, renderNoProcDefs})
|
||||
var r: TSrcGen = initTokRender(genNode, {renderNoBody, renderNoComments,
|
||||
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
|
||||
var kind = tkEof
|
||||
while true:
|
||||
getNextTok(r, kind, literal)
|
||||
@@ -971,31 +1038,26 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
|
||||
if kind != tkSpaces:
|
||||
result.generics.add(literal.nimIdentNormalize)
|
||||
|
||||
if k == skType:
|
||||
case n[2].kind
|
||||
of nkEnumTy: result.symTypeKind = "enum"
|
||||
of nkObjectTy: result.symTypeKind = "object"
|
||||
of nkTupleTy: result.symTypeKind = "tuple"
|
||||
else: discard
|
||||
if k == skType: result.symTypeKind = getTypeKind(n)
|
||||
|
||||
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
|
||||
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonExports: bool = false) =
|
||||
if (docFlags != kForceExport) and not isVisible(d, nameNode): return
|
||||
let
|
||||
name = getName(d, nameNode)
|
||||
name = getName(nameNode)
|
||||
nameEsc = esc(d.target, name)
|
||||
var plainDocstring = getPlainDocstring(n) # call here before genRecComment!
|
||||
var result = ""
|
||||
var literal, plainName = ""
|
||||
var kind = tkEof
|
||||
var comm: ItemPre
|
||||
var comm: ItemPre = default(ItemPre)
|
||||
if n.kind in routineDefs:
|
||||
getAllRunnableExamples(d, n, comm)
|
||||
else:
|
||||
comm.add genRecComment(d, n)
|
||||
|
||||
var r: TSrcGen
|
||||
# Obtain the plain rendered string for hyperlink titles.
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments,
|
||||
renderNoPragmas, renderNoProcDefs})
|
||||
var r: TSrcGen = initTokRender(n, {renderNoBody, renderNoComments, renderDocComments,
|
||||
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
|
||||
while true:
|
||||
getNextTok(r, kind, literal)
|
||||
if kind == tkEof:
|
||||
@@ -1008,9 +1070,12 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
|
||||
inc(d.id)
|
||||
let
|
||||
plainNameEsc = esc(d.target, plainName.strip)
|
||||
detailedName = k.toHumanStr & " " & (
|
||||
typeDescr =
|
||||
if k == skType and getTypeKind(n) != "": getTypeKind(n)
|
||||
else: k.toHumanStr
|
||||
detailedName = typeDescr & " " & (
|
||||
if k in routineKinds: plainName else: name)
|
||||
uniqueName = if k in routineKinds: plainNameEsc else: name
|
||||
uniqueName = if k in routineKinds: plainNameEsc else: nameEsc
|
||||
sortName = if k in routineKinds: plainName.strip else: name
|
||||
cleanPlainSymbol = renderPlainSymbolName(nameNode)
|
||||
complexSymbol = complexName(k, n, cleanPlainSymbol)
|
||||
@@ -1024,11 +1089,16 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
|
||||
let lineinfo = rstast.TLineInfo(
|
||||
line: nameNode.info.line, col: nameNode.info.col,
|
||||
fileIndex: addRstFileIndex(d, nameNode.info))
|
||||
addAnchorNim(d.sharedState, refn = symbolOrId, tooltip = detailedName,
|
||||
rstLangSymbol, priority = symbolPriority(k), info = lineinfo)
|
||||
addAnchorNim(d.sharedState, external = false, refn = symbolOrId,
|
||||
tooltip = detailedName, langSym = rstLangSymbol,
|
||||
priority = symbolPriority(k), info = lineinfo,
|
||||
module = addRstFileIndex(d, FileIndex d.module.position))
|
||||
|
||||
nodeToHighlightedHtml(d, n, result, {renderNoBody, renderNoComments,
|
||||
renderDocComments, renderSyms}, symbolOrIdEnc)
|
||||
let renderFlags =
|
||||
if nonExports: {renderNoBody, renderNoComments, renderDocComments, renderSyms,
|
||||
renderExpandUsing, renderNonExportedFields}
|
||||
else: {renderNoBody, renderNoComments, renderDocComments, renderSyms, renderExpandUsing}
|
||||
nodeToHighlightedHtml(d, n, result, renderFlags, symbolOrIdEnc)
|
||||
|
||||
let seeSrc = genSeeSrc(d, toFullPath(d.conf, n.info), n.info.line.int)
|
||||
|
||||
@@ -1060,8 +1130,10 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
|
||||
if e.sym.kind != skEnumField: continue
|
||||
let plain = renderPlainSymbolName(e)
|
||||
let symbolOrId = d.newUniquePlainSymbol(plain)
|
||||
setIndexTerm(d[], external, symbolOrId, plain, nameNode.sym.name.s & '.' & plain,
|
||||
xmltree.escape(getPlainDocstring(e).docstringSummary))
|
||||
setIndexTerm(d[], ieNim, htmlFile = external, id = symbolOrId,
|
||||
term = plain, linkTitle = nameNode.sym.name.s & '.' & plain,
|
||||
linkDesc = xmltree.escape(getPlainDocstring(e).docstringSummary),
|
||||
line = n.info.line.int)
|
||||
|
||||
d.tocSimple[k].add TocItem(
|
||||
sortName: sortName,
|
||||
@@ -1076,25 +1148,23 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
|
||||
"itemSymOrID", symbolOrId.replace(",", ",<wbr>"),
|
||||
"itemSymOrIDEnc", symbolOrIdEnc])
|
||||
|
||||
# Ironically for types the complexSymbol is *cleaner* than the plainName
|
||||
# because it doesn't include object fields or documentation comments. So we
|
||||
# use the plain one for callable elements, and the complex for the rest.
|
||||
var linkTitle = changeFileExt(extractFilename(d.filename), "") & ": "
|
||||
if n.kind in routineDefs: linkTitle.add(xmltree.escape(plainName.strip))
|
||||
else: linkTitle.add(xmltree.escape(complexSymbol.strip))
|
||||
|
||||
setIndexTerm(d[], external, symbolOrId, name, linkTitle,
|
||||
xmltree.escape(plainDocstring.docstringSummary))
|
||||
setIndexTerm(d[], ieNim, htmlFile = external, id = symbolOrId, term = name,
|
||||
linkTitle = detailedName,
|
||||
linkDesc = xmltree.escape(plainDocstring.docstringSummary),
|
||||
line = n.info.line.int)
|
||||
if k == skType and nameNode.kind == nkSym:
|
||||
d.types.strTableAdd nameNode.sym
|
||||
|
||||
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonItem =
|
||||
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): JsonItem =
|
||||
if not isVisible(d, nameNode): return
|
||||
var
|
||||
name = getName(d, nameNode)
|
||||
name = getNameEsc(d, nameNode)
|
||||
comm = genRecComment(d, n)
|
||||
r: TSrcGen
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
|
||||
renderFlags = {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing}
|
||||
if nonExports:
|
||||
renderFlags.incl renderNonExportedFields
|
||||
r = initTokRender(n, renderFlags)
|
||||
result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
|
||||
"col": %n.info.col}
|
||||
if comm != nil:
|
||||
@@ -1126,9 +1196,9 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonItem =
|
||||
result.json["signature"]["genericParams"] = newJArray()
|
||||
for genericParam in n[genericParamsPos]:
|
||||
var param = %{"name": %($genericParam)}
|
||||
if genericParam.sym.typ.sons.len > 0:
|
||||
if genericParam.sym.typ.len > 0:
|
||||
param["types"] = newJArray()
|
||||
for kind in genericParam.sym.typ.sons:
|
||||
for kind in genericParam.sym.typ:
|
||||
param["types"].add %($kind)
|
||||
result.json["signature"]["genericParams"].add param
|
||||
if optGenIndex in d.conf.globalOptions:
|
||||
@@ -1223,6 +1293,8 @@ proc documentNewEffect(cache: IdentCache; n: PNode): PNode =
|
||||
let s = n[namePos].sym
|
||||
if tfReturnsNew in s.typ.flags:
|
||||
result = newIdentNode(getIdent(cache, "new"), n.info)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
|
||||
let spec = effectSpec(x, effectType)
|
||||
@@ -1245,6 +1317,8 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id
|
||||
|
||||
result = newTreeI(nkExprColonExpr, n.info,
|
||||
newIdentNode(getIdent(cache, $effectType), n.info), effects)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode =
|
||||
let s = n[namePos].sym
|
||||
@@ -1258,6 +1332,8 @@ proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName
|
||||
if effects.len > 0:
|
||||
result = newTreeI(nkExprColonExpr, n.info,
|
||||
newIdentNode(getIdent(cache, pragmaName), n.info), effects)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc documentRaises*(cache: IdentCache; n: PNode) =
|
||||
if n[namePos].kind != nkSym: return
|
||||
@@ -1279,12 +1355,13 @@ proc documentRaises*(cache: IdentCache; n: PNode) =
|
||||
if p5 != nil: n[pragmasPos].add p5
|
||||
if p6 != nil: n[pragmasPos].add p6
|
||||
|
||||
proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) =
|
||||
proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags = kDefault) =
|
||||
## Goes through nim nodes recursively and collects doc comments.
|
||||
## Main function for `doc`:option: command,
|
||||
## which is implemented in ``docgen2.nim``.
|
||||
template genItemAux(skind) =
|
||||
genItem(d, n, n[namePos], skind, docFlags)
|
||||
let showNonExports = optShowNonExportedFields in config.globalOptions
|
||||
case n.kind
|
||||
of nkPragma:
|
||||
let pragmaNode = findPragma(n, wDeprecated)
|
||||
@@ -1311,35 +1388,57 @@ proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) =
|
||||
if n[i].kind != nkCommentStmt:
|
||||
# order is always 'type var let const':
|
||||
genItem(d, n[i], n[i][0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)), docFlags)
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)), docFlags, showNonExports)
|
||||
of nkStmtList:
|
||||
for i in 0..<n.len: generateDoc(d, n[i], orig)
|
||||
for i in 0..<n.len: generateDoc(d, n[i], orig, config)
|
||||
of nkWhenStmt:
|
||||
# generate documentation for the first branch only:
|
||||
if not checkForFalse(n[0][0]):
|
||||
generateDoc(d, lastSon(n[0]), orig)
|
||||
generateDoc(d, lastSon(n[0]), orig, config)
|
||||
of nkImportStmt:
|
||||
for it in n: traceDeps(d, it)
|
||||
of nkExportStmt:
|
||||
for it in n:
|
||||
if it.kind == nkSym:
|
||||
if d.module != nil and d.module == it.sym.owner:
|
||||
generateDoc(d, it.sym.ast, orig, kForceExport)
|
||||
generateDoc(d, it.sym.ast, orig, config, kForceExport)
|
||||
elif it.sym.ast != nil:
|
||||
exportSym(d, it.sym)
|
||||
of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept"
|
||||
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n[0])
|
||||
of nkCallKinds:
|
||||
var comm: ItemPre
|
||||
var comm: ItemPre = default(ItemPre)
|
||||
getAllRunnableExamples(d, n, comm)
|
||||
if comm.len != 0: d.modDescPre.add(comm)
|
||||
else: discard
|
||||
|
||||
proc overloadGroupName(s: string, k: TSymKind): string =
|
||||
## Turns a name like `f` into anchor `f-procs-all`
|
||||
#s & " " & k.toHumanStr & "s all"
|
||||
s & "-" & k.toHumanStr & "s-all"
|
||||
|
||||
proc setIndexTitle(d: PDoc, useMetaTitle: bool) =
|
||||
let titleKind = if d.standaloneDoc: ieMarkupTitle else: ieNimTitle
|
||||
let external = AbsoluteFile(d.destFile)
|
||||
.relativeTo(d.conf.outDir, '/')
|
||||
.changeFileExt(HtmlExt)
|
||||
.string
|
||||
var term, linkTitle: string
|
||||
if useMetaTitle and d.meta[metaTitle].len != 0:
|
||||
term = d.meta[metaTitleRaw]
|
||||
linkTitle = d.meta[metaTitleRaw]
|
||||
else:
|
||||
let filename = extractFilename(d.filename)
|
||||
term =
|
||||
if d.standaloneDoc: filename # keep .rst/.md extension
|
||||
else: changeFileExt(filename, "") # rm .nim extension
|
||||
linkTitle =
|
||||
if d.standaloneDoc: term # keep .rst/.md extension
|
||||
else: canonicalImport(d.conf, AbsoluteFile d.filename)
|
||||
if not d.standaloneDoc:
|
||||
linkTitle = "module " & linkTitle
|
||||
setIndexTerm(d[], titleKind, htmlFile = external, id = "",
|
||||
term = term, linkTitle = linkTitle)
|
||||
|
||||
proc finishGenerateDoc*(d: var PDoc) =
|
||||
## Perform 2nd RST pass for resolution of links/footnotes/headings...
|
||||
# copy file map `filenames` to ``rstgen.nim`` for its warnings
|
||||
@@ -1352,7 +1451,24 @@ proc finishGenerateDoc*(d: var PDoc) =
|
||||
firstRst = fragment.rst
|
||||
break
|
||||
d.hasToc = d.hasToc or d.sharedState.hasToc
|
||||
preparePass2(d.sharedState, firstRst)
|
||||
# in --index:only mode we do NOT want to load other .idx, only write ours:
|
||||
let importdoc = optGenIndexOnly notin d.conf.globalOptions and
|
||||
optNoImportdoc notin d.conf.globalOptions
|
||||
preparePass2(d.sharedState, firstRst, importdoc)
|
||||
|
||||
if optGenIndexOnly in d.conf.globalOptions:
|
||||
# Top-level doc.comments may contain titles and :idx: statements:
|
||||
for fragment in d.modDescPre:
|
||||
if fragment.isRst:
|
||||
traverseForIndex(d[], fragment.rst)
|
||||
setIndexTitle(d, useMetaTitle = d.standaloneDoc)
|
||||
# Symbol-associated doc.comments may contain :idx: statements:
|
||||
for k in TSymKind:
|
||||
for _, overloadChoices in d.section[k].secItems:
|
||||
for item in overloadChoices:
|
||||
for fragment in item.descRst:
|
||||
if fragment.isRst:
|
||||
traverseForIndex(d[], fragment.rst)
|
||||
|
||||
# add anchors to overload groups before RST resolution
|
||||
for k in TSymKind:
|
||||
@@ -1362,13 +1478,25 @@ proc finishGenerateDoc*(d: var PDoc) =
|
||||
let refn = overloadGroupName(plainName, k)
|
||||
let tooltip = "$1 ($2 overloads)" % [
|
||||
k.toHumanStr & " " & plainName, $overloadChoices.len]
|
||||
addAnchorNim(d.sharedState, refn, tooltip,
|
||||
let name = nimIdentBackticksNormalize(plainName)
|
||||
# save overload group to ``.idx``
|
||||
let external = d.destFile.AbsoluteFile.relativeTo(d.conf.outDir, '/').
|
||||
changeFileExt(HtmlExt).string
|
||||
setIndexTerm(d[], ieNimGroup, htmlFile = external, id = refn,
|
||||
term = name, linkTitle = k.toHumanStr,
|
||||
linkDesc = "", line = overloadChoices[0].info.line.int)
|
||||
if optGenIndexOnly in d.conf.globalOptions: continue
|
||||
addAnchorNim(d.sharedState, external=false, refn, tooltip,
|
||||
LangSymbol(symKind: k.toHumanStr,
|
||||
name: nimIdentBackticksNormalize(plainName),
|
||||
name: name,
|
||||
isGroup: true),
|
||||
priority = symbolPriority(k),
|
||||
# select index `0` just to have any meaningful warning:
|
||||
info = overloadChoices[0].info)
|
||||
info = overloadChoices[0].info,
|
||||
module = addRstFileIndex(d, FileIndex d.module.position))
|
||||
|
||||
if optGenIndexOnly in d.conf.globalOptions:
|
||||
return
|
||||
|
||||
# Finalize fragments of ``.nim`` or ``.rst`` file
|
||||
proc renderItemPre(d: PDoc, fragments: ItemPre, result: var string) =
|
||||
@@ -1388,7 +1516,7 @@ proc finishGenerateDoc*(d: var PDoc) =
|
||||
overloadChoices.sort(cmp)
|
||||
var nameContent = ""
|
||||
for item in overloadChoices:
|
||||
var itemDesc: string
|
||||
var itemDesc: string = ""
|
||||
renderItemPre(d, item.descRst, itemDesc)
|
||||
nameContent.add(
|
||||
getConfigVar(d.conf, "doc.item") % (
|
||||
@@ -1414,17 +1542,20 @@ proc finishGenerateDoc*(d: var PDoc) =
|
||||
for i, entry in d.jEntriesPre:
|
||||
if entry.rst != nil:
|
||||
let resolved = resolveSubs(d.sharedState, entry.rst)
|
||||
var str: string
|
||||
var str: string = ""
|
||||
renderRstToOut(d[], resolved, str)
|
||||
entry.json[entry.rstField] = %str
|
||||
d.jEntriesPre[i].rst = nil
|
||||
|
||||
d.jEntriesFinal.add entry.json # generates docs
|
||||
|
||||
setIndexTitle(d, useMetaTitle = d.standaloneDoc)
|
||||
completePass2(d.sharedState)
|
||||
|
||||
proc add(d: PDoc; j: JsonItem) =
|
||||
if j.json != nil or j.rst != nil: d.jEntriesPre.add j
|
||||
|
||||
proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) =
|
||||
proc generateJson*(d: PDoc, n: PNode, config: ConfigRef, includeComments: bool = true) =
|
||||
case n.kind
|
||||
of nkPragma:
|
||||
let doctypeNode = findPragma(n, wDoctype)
|
||||
@@ -1456,18 +1587,18 @@ proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) =
|
||||
if n[i].kind != nkCommentStmt:
|
||||
# order is always 'type var let const':
|
||||
d.add genJsonItem(d, n[i], n[i][0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)))
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)), optShowNonExportedFields in config.globalOptions)
|
||||
of nkStmtList:
|
||||
for i in 0..<n.len:
|
||||
generateJson(d, n[i], includeComments)
|
||||
generateJson(d, n[i], config, includeComments)
|
||||
of nkWhenStmt:
|
||||
# generate documentation for the first branch only:
|
||||
if not checkForFalse(n[0][0]):
|
||||
generateJson(d, lastSon(n[0]), includeComments)
|
||||
generateJson(d, lastSon(n[0]), config, includeComments)
|
||||
else: discard
|
||||
|
||||
proc genTagsItem(d: PDoc, n, nameNode: PNode, k: TSymKind): string =
|
||||
result = getName(d, nameNode) & "\n"
|
||||
result = getNameEsc(d, nameNode) & "\n"
|
||||
|
||||
proc generateTags*(d: PDoc, n: PNode, r: var string) =
|
||||
case n.kind
|
||||
@@ -1526,7 +1657,7 @@ proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) =
|
||||
for plainName in overloadableNames.sorted(cmpDecimalsIgnoreCase):
|
||||
var overloadChoices = d.tocTable[kind][plainName]
|
||||
overloadChoices.sort(cmp)
|
||||
var content: string
|
||||
var content: string = ""
|
||||
for item in overloadChoices:
|
||||
content.add item.content
|
||||
d.toc2[kind].add getConfigVar(d.conf, "doc.section.toc2") % [
|
||||
@@ -1557,7 +1688,7 @@ proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile):
|
||||
|
||||
proc genOutFile(d: PDoc, groupedToc = false): string =
|
||||
var
|
||||
code, content: string
|
||||
code, content: string = ""
|
||||
title = ""
|
||||
var j = 0
|
||||
var toc = ""
|
||||
@@ -1574,13 +1705,7 @@ proc genOutFile(d: PDoc, groupedToc = false): string =
|
||||
# Extract the title. Non API modules generate an entry in the index table.
|
||||
if d.meta[metaTitle].len != 0:
|
||||
title = d.meta[metaTitle]
|
||||
let external = AbsoluteFile(d.destFile)
|
||||
.relativeTo(d.conf.outDir, '/')
|
||||
.changeFileExt(HtmlExt)
|
||||
.string
|
||||
setIndexTerm(d[], external, "", title)
|
||||
else:
|
||||
# Modules get an automatic title for the HTML, but no entry in the index.
|
||||
title = canonicalImport(d.conf, AbsoluteFile d.filename)
|
||||
title = esc(d.target, title)
|
||||
var subtitle = ""
|
||||
@@ -1614,16 +1739,22 @@ proc genOutFile(d: PDoc, groupedToc = false): string =
|
||||
"moduledesc", d.modDescFinal, "date", getDateStr(), "time", getClockStr(),
|
||||
"content", content, "author", d.meta[metaAuthor],
|
||||
"version", esc(d.target, d.meta[metaVersion]), "analytics", d.analytics,
|
||||
"deprecationMsg", d.modDeprecationMsg]
|
||||
"deprecationMsg", d.modDeprecationMsg, "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch]
|
||||
else:
|
||||
code = content
|
||||
result = code
|
||||
|
||||
proc indexFile(d: PDoc): AbsoluteFile =
|
||||
let dir = d.conf.outDir
|
||||
result = dir / changeFileExt(presentationPath(d.conf,
|
||||
AbsoluteFile d.filename),
|
||||
IndexExt)
|
||||
let (finalDir, _, _) = result.string.splitFile
|
||||
createDir(finalDir)
|
||||
|
||||
proc generateIndex*(d: PDoc) =
|
||||
if optGenIndex in d.conf.globalOptions:
|
||||
let dir = d.conf.outDir
|
||||
createDir(dir)
|
||||
let dest = dir / changeFileExt(presentationPath(d.conf, AbsoluteFile d.filename), IndexExt)
|
||||
let dest = indexFile(d)
|
||||
writeIndexFile(d[], dest.string)
|
||||
|
||||
proc updateOutfile(d: PDoc, outfile: AbsoluteFile) =
|
||||
@@ -1634,6 +1765,9 @@ proc updateOutfile(d: PDoc, outfile: AbsoluteFile) =
|
||||
d.conf.outFile = splitPath(d.conf.outFile.string)[1].RelativeFile
|
||||
|
||||
proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) =
|
||||
if optGenIndexOnly in d.conf.globalOptions:
|
||||
d.conf.outFile = indexFile(d).relativeTo(d.conf.outDir) # just for display
|
||||
return
|
||||
runAllExamples(d)
|
||||
var content = genOutFile(d, groupedToc)
|
||||
if optStdout in d.conf.globalOptions:
|
||||
@@ -1663,7 +1797,7 @@ proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) =
|
||||
|
||||
proc writeOutputJson*(d: PDoc, useWarning = false) =
|
||||
runAllExamples(d)
|
||||
var modDesc: string
|
||||
var modDesc: string = ""
|
||||
for desc in d.modDescFinal:
|
||||
modDesc &= desc
|
||||
let content = %*{"orig": d.filename,
|
||||
@@ -1675,7 +1809,7 @@ proc writeOutputJson*(d: PDoc, useWarning = false) =
|
||||
else:
|
||||
let dir = d.destFile.splitFile.dir
|
||||
createDir(dir)
|
||||
var f: File
|
||||
var f: File = default(File)
|
||||
if open(f, d.destFile, fmWrite):
|
||||
write(f, $content)
|
||||
close(f)
|
||||
@@ -1698,7 +1832,7 @@ proc commandDoc*(cache: IdentCache, conf: ConfigRef) =
|
||||
var ast = parseFile(conf.projectMainIdx, cache, conf)
|
||||
if ast == nil: return
|
||||
var d = newDocumentor(conf.projectFull, cache, conf, hasToc = true)
|
||||
generateDoc(d, ast, ast)
|
||||
generateDoc(d, ast, ast, conf)
|
||||
finishGenerateDoc(d)
|
||||
writeOutput(d)
|
||||
generateIndex(d)
|
||||
@@ -1709,13 +1843,16 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef;
|
||||
var filen = addFileExt(filename, "txt")
|
||||
var d = newDocumentor(filen, cache, conf, outExt, standaloneDoc = true,
|
||||
preferMarkdown = preferMarkdown, hasToc = false)
|
||||
let rst = parseRst(readFile(filen.string),
|
||||
line=LineRstInit, column=ColRstInit,
|
||||
conf, d.sharedState)
|
||||
d.modDescPre = @[ItemFragment(isRst: true, rst: rst)]
|
||||
finishGenerateDoc(d)
|
||||
writeOutput(d)
|
||||
generateIndex(d)
|
||||
try:
|
||||
let rst = parseRst(readFile(filen.string),
|
||||
line=LineRstInit, column=ColRstInit,
|
||||
conf, d.sharedState)
|
||||
d.modDescPre = @[ItemFragment(isRst: true, rst: rst)]
|
||||
finishGenerateDoc(d)
|
||||
writeOutput(d)
|
||||
generateIndex(d)
|
||||
except ERecoverableError:
|
||||
discard "already reported the error"
|
||||
|
||||
proc commandRst2Html*(cache: IdentCache, conf: ConfigRef,
|
||||
preferMarkdown=false) =
|
||||
@@ -1734,7 +1871,7 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) =
|
||||
status: int; content: string) {.gcsafe.} =
|
||||
localError(conf, newLineInfo(conf, AbsoluteFile d.filename, -1, -1),
|
||||
warnUser, "the ':test:' attribute is not supported by this backend")
|
||||
generateJson(d, ast)
|
||||
generateJson(d, ast, conf)
|
||||
finishGenerateDoc(d)
|
||||
let json = d.jEntriesFinal
|
||||
let content = pretty(json)
|
||||
@@ -1746,7 +1883,7 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) =
|
||||
let filename = getOutFile(conf, RelativeFile conf.projectName, JsonExt)
|
||||
try:
|
||||
writeFile(filename, content)
|
||||
except:
|
||||
except IOError:
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
proc commandTags*(cache: IdentCache, conf: ConfigRef) =
|
||||
@@ -1768,10 +1905,12 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) =
|
||||
let filename = getOutFile(conf, RelativeFile conf.projectName, TagsExt)
|
||||
try:
|
||||
writeFile(filename, content)
|
||||
except:
|
||||
except IOError:
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") =
|
||||
if optGenIndexOnly in conf.globalOptions:
|
||||
return
|
||||
var content = mergeIndexes(dir)
|
||||
|
||||
var outFile = outFile
|
||||
@@ -1784,12 +1923,12 @@ proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"")
|
||||
"title", "Index",
|
||||
"subtitle", "", "tableofcontents", "", "moduledesc", "",
|
||||
"date", getDateStr(), "time", getClockStr(),
|
||||
"content", content, "author", "", "version", "", "analytics", ""]
|
||||
"content", content, "author", "", "version", "", "analytics", "", "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch]
|
||||
# no analytics because context is not available
|
||||
|
||||
try:
|
||||
writeFile(filename, code)
|
||||
except:
|
||||
except IOError:
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
proc commandBuildIndexJson*(conf: ConfigRef, dir: string, outFile = RelativeFile"") =
|
||||
@@ -1803,5 +1942,5 @@ proc commandBuildIndexJson*(conf: ConfigRef, dir: string, outFile = RelativeFile
|
||||
|
||||
try:
|
||||
writeFile(filename, $body)
|
||||
except:
|
||||
except IOError:
|
||||
rawMessage(conf, errCannotOpenFile, filename.string)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# semantic checking.
|
||||
|
||||
import
|
||||
options, ast, msgs, passes, docgen, lineinfos, pathutils, packages
|
||||
options, ast, msgs, docgen, lineinfos, pathutils, packages
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
|
||||
@@ -38,25 +38,27 @@ template closeImpl(body: untyped) {.dirty.} =
|
||||
except IOError:
|
||||
discard
|
||||
|
||||
proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
|
||||
proc closeDoc*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
|
||||
result = nil
|
||||
closeImpl:
|
||||
writeOutput(g.doc, useWarning, groupedToc)
|
||||
|
||||
proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
|
||||
proc closeJson*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
|
||||
result = nil
|
||||
closeImpl:
|
||||
writeOutputJson(g.doc, useWarning)
|
||||
|
||||
proc processNode(c: PPassContext, n: PNode): PNode =
|
||||
proc processNode*(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
var g = PGen(c)
|
||||
if shouldProcess(g):
|
||||
generateDoc(g.doc, n, n)
|
||||
generateDoc(g.doc, n, n, g.config)
|
||||
|
||||
proc processNodeJson(c: PPassContext, n: PNode): PNode =
|
||||
proc processNodeJson*(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
var g = PGen(c)
|
||||
if shouldProcess(g):
|
||||
generateJson(g.doc, n, false)
|
||||
generateJson(g.doc, n, g.config, false)
|
||||
|
||||
template myOpenImpl(ext: untyped) {.dirty.} =
|
||||
var g: PGen
|
||||
@@ -68,20 +70,11 @@ template myOpenImpl(ext: untyped) {.dirty.} =
|
||||
g.doc = d
|
||||
result = g
|
||||
|
||||
proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
proc openHtml*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
myOpenImpl(HtmlExt)
|
||||
|
||||
proc myOpenTex(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
proc openTex*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
myOpenImpl(TexExt)
|
||||
|
||||
proc myOpenJson(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
proc openJson*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
myOpenImpl(JsonExt)
|
||||
|
||||
const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
|
||||
const docgen2TexPass* = makePass(open = myOpenTex, process = processNode,
|
||||
close = close)
|
||||
const docgen2JsonPass* = makePass(open = myOpenJson, process = processNodeJson,
|
||||
close = closeJson)
|
||||
|
||||
proc finishDoc2Pass*(project: string) =
|
||||
discard
|
||||
|
||||
@@ -6,12 +6,12 @@ when defined(nimPreviewSlimSystem):
|
||||
|
||||
|
||||
proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym =
|
||||
result = newSym(skProc, getIdent(g.cache, "$"), nextSymId idgen, t.owner, info)
|
||||
result = newSym(skProc, getIdent(g.cache, "$"), idgen, t.owner, info)
|
||||
|
||||
let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info)
|
||||
let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info)
|
||||
dest.typ = t
|
||||
|
||||
let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info)
|
||||
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
|
||||
res.typ = getSysType(g, info, tyString)
|
||||
|
||||
result.typ = newType(tyProc, nextTypeId idgen, t.owner)
|
||||
@@ -56,6 +56,7 @@ proc searchObjCaseImpl(obj: PNode; field: PSym): PNode =
|
||||
if obj.kind == nkRecCase and obj[0].kind == nkSym and obj[0].sym == field:
|
||||
result = obj
|
||||
else:
|
||||
result = nil
|
||||
for x in obj:
|
||||
result = searchObjCaseImpl(x, field)
|
||||
if result != nil: break
|
||||
@@ -67,12 +68,12 @@ proc searchObjCase(t: PType; field: PSym): PNode =
|
||||
doAssert result != nil
|
||||
|
||||
proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym =
|
||||
result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), nextSymId idgen, t.owner, info)
|
||||
result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), idgen, t.owner, info)
|
||||
|
||||
let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info)
|
||||
let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info)
|
||||
dest.typ = field.typ
|
||||
|
||||
let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info)
|
||||
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
|
||||
res.typ = getSysType(g, info, tyUInt8)
|
||||
|
||||
result.typ = newType(tyProc, nextTypeId idgen, t.owner)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import ast, types, options, tables, dynlib, msgs, lineinfos
|
||||
from os import getAppFilename
|
||||
import pkg/libffi
|
||||
import libffi/libffi
|
||||
|
||||
when defined(windows):
|
||||
const libcDll = "msvcrt.dll"
|
||||
@@ -37,9 +37,10 @@ else:
|
||||
var gExeHandle = loadLib()
|
||||
|
||||
proc getDll(conf: ConfigRef, cache: var TDllCache; dll: string; info: TLineInfo): pointer =
|
||||
result = nil
|
||||
if dll in cache:
|
||||
return cache[dll]
|
||||
var libs: seq[string]
|
||||
var libs: seq[string] = @[]
|
||||
libCandidates(dll, libs)
|
||||
for c in libs:
|
||||
result = loadLib(c)
|
||||
@@ -61,7 +62,7 @@ proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode =
|
||||
let lib = sym.annex
|
||||
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
|
||||
globalError(conf, sym.info, "dynlib needs to be a string lit")
|
||||
var theAddr: pointer
|
||||
var theAddr: pointer = nil
|
||||
if (lib.isNil or lib.kind == libHeader) and not gExeHandle.isNil:
|
||||
libPathMsg = "current exe: " & getAppFilename() & " nor libc: " & libcDll
|
||||
# first try this exe itself:
|
||||
@@ -77,7 +78,7 @@ proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode =
|
||||
theAddr = dllhandle.symAddr(name.cstring)
|
||||
if theAddr.isNil: globalError(conf, sym.info,
|
||||
"cannot import symbol: " & name & " from " & libPathMsg)
|
||||
result.intVal = cast[ByteAddress](theAddr)
|
||||
result.intVal = cast[int](theAddr)
|
||||
|
||||
proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type =
|
||||
if t == nil: return addr libffi.type_void
|
||||
@@ -108,12 +109,13 @@ proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI
|
||||
of ccStdCall: result = when defined(windows) and defined(x86): STDCALL else: DEFAULT_ABI
|
||||
of ccCDecl: result = DEFAULT_ABI
|
||||
else:
|
||||
result = default(TABI)
|
||||
globalError(conf, info, "cannot map calling convention to FFI")
|
||||
|
||||
template rd(typ, p: untyped): untyped = (cast[ptr typ](p))[]
|
||||
template wr(typ, p, v: untyped): untyped = (cast[ptr typ](p))[] = v
|
||||
template `+!`(x, y: untyped): untyped =
|
||||
cast[pointer](cast[ByteAddress](x) + y)
|
||||
cast[pointer](cast[int](x) + y)
|
||||
|
||||
proc packSize(conf: ConfigRef, v: PNode, typ: PType): int =
|
||||
## computes the size of the blob
|
||||
@@ -132,6 +134,8 @@ proc packSize(conf: ConfigRef, v: PNode, typ: PType): int =
|
||||
result = sizeof(pointer)
|
||||
elif v.len != 0:
|
||||
result = v.len * packSize(conf, v[0], typ[1])
|
||||
else:
|
||||
result = 0
|
||||
else:
|
||||
result = getSize(conf, typ).int
|
||||
|
||||
@@ -140,6 +144,7 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer)
|
||||
proc getField(conf: ConfigRef, n: PNode; position: int): PSym =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
result = nil
|
||||
for i in 0..<n.len:
|
||||
result = getField(conf, n[i], position)
|
||||
if result != nil: return
|
||||
@@ -154,7 +159,8 @@ proc getField(conf: ConfigRef, n: PNode; position: int): PSym =
|
||||
else: internalError(conf, n.info, "getField(record case branch)")
|
||||
of nkSym:
|
||||
if n.sym.position == position: result = n.sym
|
||||
else: discard
|
||||
else: result = nil
|
||||
else: result = nil
|
||||
|
||||
proc packObject(conf: ConfigRef, x: PNode, typ: PType, res: pointer) =
|
||||
internalAssert conf, x.kind in {nkObjConstr, nkPar, nkTupleConstr}
|
||||
@@ -356,6 +362,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
of 4: awi(nkIntLit, rd(int32, x).BiggestInt)
|
||||
of 8: awi(nkIntLit, rd(int64, x).BiggestInt)
|
||||
else:
|
||||
result = nil
|
||||
globalError(conf, n.info, "cannot map value from FFI (tyEnum, tySet)")
|
||||
of tyFloat: awf(nkFloatLit, rd(float, x))
|
||||
of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
|
||||
@@ -369,18 +376,19 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
# in their unboxed representation so nothing it to be unpacked:
|
||||
result = n
|
||||
else:
|
||||
awi(nkPtrLit, cast[ByteAddress](p))
|
||||
awi(nkPtrLit, cast[int](p))
|
||||
of tyPtr, tyRef, tyVar, tyLent:
|
||||
let p = rd(pointer, x)
|
||||
if p.isNil:
|
||||
setNil()
|
||||
elif n == nil or n.kind == nkPtrLit:
|
||||
awi(nkPtrLit, cast[ByteAddress](p))
|
||||
awi(nkPtrLit, cast[int](p))
|
||||
elif n != nil and n.len == 1:
|
||||
internalAssert(conf, n.kind == nkRefTy)
|
||||
n[0] = unpack(conf, p, typ.lastSon, n[0])
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
globalError(conf, n.info, "cannot map value from FFI " & typeToString(typ))
|
||||
of tyObject, tyTuple:
|
||||
result = unpackObject(conf, x, typ, n)
|
||||
@@ -398,6 +406,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
result = unpack(conf, x, typ.lastSon, n)
|
||||
else:
|
||||
# XXX what to do with 'array' here?
|
||||
result = nil
|
||||
globalError(conf, n.info, "cannot map value from FFI " & typeToString(typ))
|
||||
|
||||
proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode =
|
||||
@@ -424,7 +433,7 @@ proc callForeignFunction*(conf: ConfigRef, call: PNode): PNode =
|
||||
internalAssert conf, call[0].kind == nkPtrLit
|
||||
|
||||
var cif: TCif
|
||||
var sig: ParamList
|
||||
var sig: ParamList = default(ParamList)
|
||||
# use the arguments' types for varargs support:
|
||||
for i in 1..<call.len:
|
||||
sig[i-1] = mapType(conf, call[i].typ)
|
||||
@@ -436,7 +445,7 @@ proc callForeignFunction*(conf: ConfigRef, call: PNode): PNode =
|
||||
mapType(conf, typ[0]), sig) != OK:
|
||||
globalError(conf, call.info, "error in FFI call")
|
||||
|
||||
var args: ArgList
|
||||
var args: ArgList = default(ArgList)
|
||||
let fn = cast[pointer](call[0].intVal)
|
||||
for i in 1..<call.len:
|
||||
var t = call[i].typ
|
||||
@@ -464,7 +473,7 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
|
||||
internalAssert conf, fn.kind == nkPtrLit
|
||||
|
||||
var cif: TCif
|
||||
var sig: ParamList
|
||||
var sig: ParamList = default(ParamList)
|
||||
for i in 0..len-1:
|
||||
var aTyp = args[i+start].typ
|
||||
if aTyp.isNil:
|
||||
@@ -478,7 +487,7 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
|
||||
mapType(conf, fntyp[0]), sig) != OK:
|
||||
globalError(conf, info, "error in FFI call")
|
||||
|
||||
var cargs: ArgList
|
||||
var cargs: ArgList = default(ArgList)
|
||||
let fn = cast[pointer](fn.intVal)
|
||||
for i in 0..len-1:
|
||||
let t = args[i+start].typ
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Template evaluation engine. Now hygienic.
|
||||
|
||||
import
|
||||
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents
|
||||
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents, trees
|
||||
|
||||
type
|
||||
TemplCtx = object
|
||||
@@ -49,7 +49,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
internalAssert c.config, sfGenSym in s.flags or s.kind == skType
|
||||
var x = PSym(idTableGet(c.mapping, s))
|
||||
if x == nil:
|
||||
x = copySym(s, nextSymId(c.idgen))
|
||||
x = copySym(s, c.idgen)
|
||||
# sem'check needs to set the owner properly later, see bug #9476
|
||||
x.owner = nil # c.genSymOwner
|
||||
#if x.kind == skParam and x.owner.kind == skModule:
|
||||
@@ -187,7 +187,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
|
||||
ctx.genSymOwner = genSymOwner
|
||||
ctx.config = conf
|
||||
ctx.ic = ic
|
||||
initIdTable(ctx.mapping)
|
||||
ctx.mapping = initIdTable()
|
||||
ctx.instID = instID[]
|
||||
ctx.idgen = idgen
|
||||
|
||||
|
||||
@@ -14,13 +14,15 @@
|
||||
|
||||
import ropes, platform, condsyms, options, msgs, lineinfos, pathutils, modulepaths
|
||||
|
||||
import std/[os, osproc, sha1, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils]
|
||||
import std/[os, osproc, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils]
|
||||
|
||||
import std / strutils except addf
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/syncio
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
|
||||
type
|
||||
TInfoCCProp* = enum # properties of the C compiler:
|
||||
hasSwitchRange, # CC allows ranges in switch statements (GNU C)
|
||||
@@ -328,7 +330,9 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
|
||||
platform.OS[conf.target.targetOS].name & '.' &
|
||||
CC[c].name & fullSuffix
|
||||
result = getConfigVar(conf, fullCCname)
|
||||
if result.len == 0:
|
||||
if existsConfigVar(conf, fullCCname):
|
||||
result = getConfigVar(conf, fullCCname)
|
||||
else:
|
||||
# not overridden for this cross compilation setting?
|
||||
result = getConfigVar(conf, CC[c].name & fullSuffix)
|
||||
else:
|
||||
@@ -482,6 +486,10 @@ proc vccplatform(conf: ConfigRef): string =
|
||||
of cpuArm: " --platform:arm"
|
||||
of cpuAmd64: " --platform:amd64"
|
||||
else: ""
|
||||
else:
|
||||
result = ""
|
||||
else:
|
||||
result = ""
|
||||
|
||||
proc getLinkOptions(conf: ConfigRef): string =
|
||||
result = conf.linkOptions & " " & conf.linkOptionsCmd & " "
|
||||
@@ -528,9 +536,9 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool =
|
||||
var exe = getConfigVar(conf, conf.cCompiler, ".exe")
|
||||
if exe.len == 0: exe = CC[conf.cCompiler].compilerExe
|
||||
# NOTE: should we need the full version, use -dumpfullversion
|
||||
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except: ("", 1)
|
||||
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except IOError, OSError, ValueError: ("", 1)
|
||||
if exitCode == 0:
|
||||
var major: int
|
||||
var major: int = 0
|
||||
discard parseInt(s, major)
|
||||
result = major >= 5
|
||||
else:
|
||||
@@ -576,7 +584,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
|
||||
|
||||
compilePattern = joinPath(conf.cCompilerPath, exe)
|
||||
else:
|
||||
compilePattern = getCompilerExe(conf, c, isCpp)
|
||||
compilePattern = exe
|
||||
|
||||
includeCmd.add(join([CC[c].includeCmd, quoteShell(conf.projectPath.string)]))
|
||||
|
||||
@@ -640,7 +648,7 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
|
||||
|
||||
let hashFile = toGeneratedFile(conf, conf.mangleModuleName(cfile.cname).AbsoluteFile, "sha1")
|
||||
let currentHash = footprint(conf, cfile)
|
||||
var f: File
|
||||
var f: File = default(File)
|
||||
if open(f, hashFile.string, fmRead):
|
||||
let oldHash = parseSecureHash(f.readLine())
|
||||
close(f)
|
||||
@@ -775,6 +783,7 @@ template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body
|
||||
raise
|
||||
|
||||
proc getExtraCmds(conf: ConfigRef; output: AbsoluteFile): seq[string] =
|
||||
result = @[]
|
||||
when defined(macosx):
|
||||
if optCDebug in conf.globalOptions and optGenStaticLib notin conf.globalOptions:
|
||||
# if needed, add an option to skip or override location
|
||||
@@ -830,10 +839,22 @@ proc linkViaResponseFile(conf: ConfigRef; cmd: string) =
|
||||
else:
|
||||
writeFile(linkerArgs, args)
|
||||
try:
|
||||
execLinkCmd(conf, cmd.substr(0, last) & " @" & linkerArgs)
|
||||
when defined(macosx):
|
||||
execLinkCmd(conf, "xargs " & cmd.substr(0, last) & " < " & linkerArgs)
|
||||
else:
|
||||
execLinkCmd(conf, cmd.substr(0, last) & " @" & linkerArgs)
|
||||
finally:
|
||||
removeFile(linkerArgs)
|
||||
|
||||
proc linkViaShellScript(conf: ConfigRef; cmd: string) =
|
||||
let linkerScript = conf.projectName & "_" & "linkerScript.sh"
|
||||
writeFile(linkerScript, cmd)
|
||||
let shell = getEnv("SHELL")
|
||||
try:
|
||||
execLinkCmd(conf, shell & " " & linkerScript)
|
||||
finally:
|
||||
removeFile(linkerScript)
|
||||
|
||||
proc getObjFilePath(conf: ConfigRef, f: Cfile): string =
|
||||
if noAbsolutePaths(conf): f.obj.extractFilename
|
||||
else: f.obj.string
|
||||
@@ -845,23 +866,38 @@ proc hcrLinkTargetName(conf: ConfigRef, objFile: string, isMain = false): Absolu
|
||||
result = conf.getNimcacheDir / RelativeFile(targetName)
|
||||
|
||||
proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string =
|
||||
result = ""
|
||||
if conf.hasHint(hintCC):
|
||||
if optListCmd in conf.globalOptions or conf.verbosity > 1:
|
||||
result = MsgKindToStr[hintCC] % (demangleModuleName(path.splitFile.name) & ": " & compileCmd)
|
||||
else:
|
||||
result = MsgKindToStr[hintCC] % demangleModuleName(path.splitFile.name)
|
||||
|
||||
proc preventLinkCmdMaxCmdLen(conf: ConfigRef, linkCmd: string) =
|
||||
# Prevent linkcmd from exceeding the maximum command line length.
|
||||
# Windows's command line limit is about 8K (8191 characters) so C compilers on
|
||||
# Windows support a feature where the command line can be passed via ``@linkcmd``
|
||||
# to them.
|
||||
const MaxCmdLen = when defined(windows): 8_000 elif defined(macosx): 260_000 else: 32_000
|
||||
if linkCmd.len > MaxCmdLen:
|
||||
when defined(macosx):
|
||||
linkViaShellScript(conf, linkCmd)
|
||||
else:
|
||||
linkViaResponseFile(conf, linkCmd)
|
||||
else:
|
||||
execLinkCmd(conf, linkCmd)
|
||||
|
||||
proc callCCompiler*(conf: ConfigRef) =
|
||||
var
|
||||
linkCmd: string
|
||||
linkCmd: string = ""
|
||||
extraCmds: seq[string]
|
||||
if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
|
||||
return # speed up that call if only compiling and no script shall be
|
||||
# generated
|
||||
#var c = cCompiler
|
||||
var script: Rope = ""
|
||||
var cmds: TStringSeq
|
||||
var prettyCmds: TStringSeq
|
||||
var cmds: TStringSeq = default(TStringSeq)
|
||||
var prettyCmds: TStringSeq = default(TStringSeq)
|
||||
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
|
||||
|
||||
for idx, it in conf.toCompile:
|
||||
@@ -927,14 +963,7 @@ proc callCCompiler*(conf: ConfigRef) =
|
||||
linkCmd = getLinkCmd(conf, mainOutput, objfiles, removeStaticFile = true)
|
||||
extraCmds = getExtraCmds(conf, mainOutput)
|
||||
if optCompileOnly notin conf.globalOptions:
|
||||
const MaxCmdLen = when defined(windows): 8_000 else: 32_000
|
||||
if linkCmd.len > MaxCmdLen:
|
||||
# Windows's command line limit is about 8K (don't laugh...) so C compilers on
|
||||
# Windows support a feature where the command line can be passed via ``@linkcmd``
|
||||
# to them.
|
||||
linkViaResponseFile(conf, linkCmd)
|
||||
else:
|
||||
execLinkCmd(conf, linkCmd)
|
||||
preventLinkCmdMaxCmdLen(conf, linkCmd)
|
||||
for cmd in extraCmds:
|
||||
execExternalProgram(conf, cmd, hintExecuting)
|
||||
else:
|
||||
@@ -999,8 +1028,9 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
|
||||
conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty)
|
||||
|
||||
proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile): bool =
|
||||
result = false
|
||||
if not fileExists(jsonFile) or not fileExists(conf.absOutFile): return true
|
||||
var bcache: BuildCache
|
||||
var bcache: BuildCache = default(BuildCache)
|
||||
try: bcache.fromJson(jsonFile.string.parseFile)
|
||||
except IOError, OSError, ValueError:
|
||||
stderr.write "Warning: JSON processing failed for: $#\n" % jsonFile.string
|
||||
@@ -1016,9 +1046,9 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
|
||||
if $secureHashFile(file) != hash: return true
|
||||
|
||||
proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
|
||||
var bcache: BuildCache
|
||||
var bcache: BuildCache = default(BuildCache)
|
||||
try: bcache.fromJson(jsonFile.string.parseFile)
|
||||
except:
|
||||
except ValueError, KeyError, JsonKindError:
|
||||
let e = getCurrentException()
|
||||
conf.quitOrRaise "\ncaught exception:\n$#\nstacktrace:\n$#error evaluating JSON file: $#" %
|
||||
[e.msg, e.getStackTrace(), jsonFile.string]
|
||||
@@ -1029,16 +1059,18 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
|
||||
globalError(conf, gCmdLineInfo,
|
||||
"jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " %
|
||||
[outputCurrent, output, jsonFile.string])
|
||||
var cmds, prettyCmds: TStringSeq
|
||||
var cmds: TStringSeq = default(TStringSeq)
|
||||
var prettyCmds: TStringSeq= default(TStringSeq)
|
||||
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
|
||||
for (name, cmd) in bcache.compile:
|
||||
cmds.add cmd
|
||||
prettyCmds.add displayProgressCC(conf, name, cmd)
|
||||
execCmdsInParallel(conf, cmds, prettyCb)
|
||||
execLinkCmd(conf, bcache.linkcmd)
|
||||
preventLinkCmdMaxCmdLen(conf, bcache.linkcmd)
|
||||
for cmd in bcache.extraCmds: execExternalProgram(conf, cmd, hintExecuting)
|
||||
|
||||
proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope =
|
||||
result = ""
|
||||
for it in list:
|
||||
result.addf("--file:r\"$1\"$N", [rope(it.cname.string)])
|
||||
|
||||
|
||||
@@ -201,17 +201,15 @@ proc parseLine(p: var TTmplParser) =
|
||||
|
||||
proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile,
|
||||
call: PNode): PLLStream =
|
||||
var p: TTmplParser
|
||||
p.config = conf
|
||||
p.info = newLineInfo(conf, filename, 0, 0)
|
||||
p.outp = llStreamOpen("")
|
||||
p.inp = stdin
|
||||
p.subsChar = charArg(conf, call, "subschar", 1, '$')
|
||||
p.nimDirective = charArg(conf, call, "metachar", 2, '#')
|
||||
p.emit = strArg(conf, call, "emit", 3, "result.add")
|
||||
p.conc = strArg(conf, call, "conc", 4, " & ")
|
||||
p.toStr = strArg(conf, call, "tostring", 5, "$")
|
||||
p.x = newStringOfCap(120)
|
||||
var p = TTmplParser(config: conf, info: newLineInfo(conf, filename, 0, 0),
|
||||
outp: llStreamOpen(""), inp: stdin,
|
||||
subsChar: charArg(conf, call, "subschar", 1, '$'),
|
||||
nimDirective: charArg(conf, call, "metachar", 2, '#'),
|
||||
emit: strArg(conf, call, "emit", 3, "result.add"),
|
||||
conc: strArg(conf, call, "conc", 4, " & "),
|
||||
toStr: strArg(conf, call, "tostring", 5, "$"),
|
||||
x: newStringOfCap(120)
|
||||
)
|
||||
# do not process the first line which contains the directive:
|
||||
if llStreamReadLine(p.inp, p.x):
|
||||
inc p.info.line
|
||||
|
||||
@@ -29,23 +29,30 @@ proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode =
|
||||
return n[i]
|
||||
|
||||
proc charArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: char): char =
|
||||
|
||||
var x = getArg(conf, n, name, pos)
|
||||
if x == nil: result = default
|
||||
elif x.kind == nkCharLit: result = chr(int(x.intVal))
|
||||
else: invalidPragma(conf, n)
|
||||
else:
|
||||
result = default(char)
|
||||
invalidPragma(conf, n)
|
||||
|
||||
proc strArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: string): string =
|
||||
var x = getArg(conf, n, name, pos)
|
||||
if x == nil: result = default
|
||||
elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal
|
||||
else: invalidPragma(conf, n)
|
||||
else:
|
||||
result = ""
|
||||
invalidPragma(conf, n)
|
||||
|
||||
proc boolArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: bool): bool =
|
||||
var x = getArg(conf, n, name, pos)
|
||||
if x == nil: result = default
|
||||
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "true") == 0: result = true
|
||||
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false
|
||||
else: invalidPragma(conf, n)
|
||||
else:
|
||||
result = false
|
||||
invalidPragma(conf, n)
|
||||
|
||||
proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, call: PNode): PLLStream =
|
||||
var pattern = strArg(conf, call, "startswith", 1, "")
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
|
||||
## Module that implements ``gorge`` for the compiler.
|
||||
|
||||
import msgs, std / sha1, os, osproc, streams, options,
|
||||
import msgs, os, osproc, streams, options,
|
||||
lineinfos, pathutils
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/syncio
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
|
||||
proc readOutput(p: Process): (string, int) =
|
||||
result[0] = ""
|
||||
var output = p.outputStream
|
||||
@@ -27,10 +29,11 @@ proc readOutput(p: Process): (string, int) =
|
||||
|
||||
proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (string, int) =
|
||||
let workingDir = parentDir(toFullPath(conf, info))
|
||||
result = ("", 0)
|
||||
if cache.len > 0:
|
||||
let h = secureHash(cmd & "\t" & input & "\t" & cache)
|
||||
let filename = toGeneratedFile(conf, AbsoluteFile("gorge_" & $h), "txt").string
|
||||
var f: File
|
||||
var f: File = default(File)
|
||||
if optForceFullMake notin conf.globalOptions and open(f, filename):
|
||||
result = (f.readAll, 0)
|
||||
f.close
|
||||
|
||||
@@ -51,6 +51,10 @@ proc isLet(n: PNode): bool =
|
||||
elif n.sym.kind == skParam and skipTypes(n.sym.typ,
|
||||
abstractInst).kind notin {tyVar}:
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc isVar(n: PNode): bool =
|
||||
n.kind == nkSym and n.sym.kind in {skResult, skVar} and
|
||||
@@ -136,6 +140,8 @@ proc neg(n: PNode; o: Operators): PNode =
|
||||
result = a
|
||||
elif b != nil:
|
||||
result = b
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
# leave not (a == 4) as it is
|
||||
result = newNodeI(nkCall, n.info, 2)
|
||||
@@ -330,6 +336,8 @@ proc usefulFact(n: PNode; o: Operators): PNode =
|
||||
result = n
|
||||
elif n[1].getMagic in someLen or n[2].getMagic in someLen:
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
of someLe+someLt:
|
||||
if isLetLocation(n[1], true) or isLetLocation(n[2], true):
|
||||
# XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1'
|
||||
@@ -337,12 +345,18 @@ proc usefulFact(n: PNode; o: Operators): PNode =
|
||||
elif n[1].getMagic in someLen or n[2].getMagic in someLen:
|
||||
# XXX Rethink this whole idea of 'usefulFact' for semparallel
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
of mIsNil:
|
||||
if isLetLocation(n[1], false) or isVar(n[1]):
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
of someIn:
|
||||
if isLetLocation(n[1], true):
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
of mAnd:
|
||||
let
|
||||
a = usefulFact(n[1], o)
|
||||
@@ -356,10 +370,14 @@ proc usefulFact(n: PNode; o: Operators): PNode =
|
||||
result = a
|
||||
elif b != nil:
|
||||
result = b
|
||||
else:
|
||||
result = nil
|
||||
of mNot:
|
||||
let a = usefulFact(n[1], o)
|
||||
if a != nil:
|
||||
result = a.neg(o)
|
||||
else:
|
||||
result = nil
|
||||
of mOr:
|
||||
# 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
|
||||
# with that knowledge...
|
||||
@@ -376,6 +394,8 @@ proc usefulFact(n: PNode; o: Operators): PNode =
|
||||
result[1] = a
|
||||
result[2] = b
|
||||
result = result.neg(o)
|
||||
else:
|
||||
result = nil
|
||||
elif n.kind == nkSym and n.sym.kind == skLet:
|
||||
# consider:
|
||||
# let a = 2 < x
|
||||
@@ -384,8 +404,12 @@ proc usefulFact(n: PNode; o: Operators): PNode =
|
||||
# We make can easily replace 'a' by '2 < x' here:
|
||||
if n.sym.astdef != nil:
|
||||
result = usefulFact(n.sym.astdef, o)
|
||||
else:
|
||||
result = nil
|
||||
elif n.kind == nkStmtListExpr:
|
||||
result = usefulFact(n.lastSon, o)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
type
|
||||
TModel* = object
|
||||
@@ -451,8 +475,9 @@ proc hasSubTree(n, x: PNode): bool =
|
||||
of nkEmpty..nkNilLit:
|
||||
result = n.sameTree(x)
|
||||
of nkFormalParams:
|
||||
discard
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
for i in 0..<n.len:
|
||||
if hasSubTree(n[i], x): return true
|
||||
|
||||
@@ -483,6 +508,8 @@ proc invalidateFacts*(m: var TModel, n: PNode) =
|
||||
proc valuesUnequal(a, b: PNode): bool =
|
||||
if a.isValue and b.isValue:
|
||||
result = not sameValue(a, b)
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc impliesEq(fact, eq: PNode): TImplication =
|
||||
let (loc, val) = if isLocation(eq[1]): (1, 2) else: (2, 1)
|
||||
@@ -493,16 +520,26 @@ proc impliesEq(fact, eq: PNode): TImplication =
|
||||
# this is not correct; consider: a == b; a == 1 --> unknown!
|
||||
if sameTree(fact[2], eq[val]): result = impYes
|
||||
elif valuesUnequal(fact[2], eq[val]): result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
elif sameTree(fact[2], eq[loc]):
|
||||
if sameTree(fact[1], eq[val]): result = impYes
|
||||
elif valuesUnequal(fact[1], eq[val]): result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
of mInSet:
|
||||
# remember: mInSet is 'contains' so the set comes first!
|
||||
if sameTree(fact[2], eq[loc]) and isValue(eq[val]):
|
||||
if inSet(fact[1], eq[val]): result = impYes
|
||||
else: result = impNo
|
||||
of mNot, mOr, mAnd: assert(false, "impliesEq")
|
||||
else: discard
|
||||
else:
|
||||
result = impUnknown
|
||||
of mNot, mOr, mAnd:
|
||||
result = impUnknown
|
||||
assert(false, "impliesEq")
|
||||
else: result = impUnknown
|
||||
|
||||
proc leImpliesIn(x, c, aSet: PNode): TImplication =
|
||||
if c.kind in {nkCharLit..nkUInt64Lit}:
|
||||
@@ -512,13 +549,19 @@ proc leImpliesIn(x, c, aSet: PNode): TImplication =
|
||||
var value = newIntNode(c.kind, firstOrd(nil, x.typ))
|
||||
# don't iterate too often:
|
||||
if c.intVal - value.intVal < 1000:
|
||||
var i, pos, neg: int
|
||||
var i, pos, neg: int = 0
|
||||
while value.intVal <= c.intVal:
|
||||
if inSet(aSet, value): inc pos
|
||||
else: inc neg
|
||||
inc i; inc value.intVal
|
||||
if pos == i: result = impYes
|
||||
elif neg == i: result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
|
||||
proc geImpliesIn(x, c, aSet: PNode): TImplication =
|
||||
if c.kind in {nkCharLit..nkUInt64Lit}:
|
||||
@@ -529,17 +572,23 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication =
|
||||
let max = lastOrd(nil, x.typ)
|
||||
# don't iterate too often:
|
||||
if max - getInt(value) < toInt128(1000):
|
||||
var i, pos, neg: int
|
||||
var i, pos, neg: int = 0
|
||||
while value.intVal <= max:
|
||||
if inSet(aSet, value): inc pos
|
||||
else: inc neg
|
||||
inc i; inc value.intVal
|
||||
if pos == i: result = impYes
|
||||
elif neg == i: result = impNo
|
||||
else: result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
|
||||
proc compareSets(a, b: PNode): TImplication =
|
||||
if equalSets(nil, a, b): result = impYes
|
||||
elif intersectSets(nil, a, b).len == 0: result = impNo
|
||||
else: result = impUnknown
|
||||
|
||||
proc impliesIn(fact, loc, aSet: PNode): TImplication =
|
||||
case fact[0].sym.magic
|
||||
@@ -550,22 +599,32 @@ proc impliesIn(fact, loc, aSet: PNode): TImplication =
|
||||
elif sameTree(fact[2], loc):
|
||||
if inSet(aSet, fact[1]): result = impYes
|
||||
else: result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
of mInSet:
|
||||
if sameTree(fact[2], loc):
|
||||
result = compareSets(fact[1], aSet)
|
||||
else:
|
||||
result = impUnknown
|
||||
of someLe:
|
||||
if sameTree(fact[1], loc):
|
||||
result = leImpliesIn(fact[1], fact[2], aSet)
|
||||
elif sameTree(fact[2], loc):
|
||||
result = geImpliesIn(fact[2], fact[1], aSet)
|
||||
else:
|
||||
result = impUnknown
|
||||
of someLt:
|
||||
if sameTree(fact[1], loc):
|
||||
result = leImpliesIn(fact[1], fact[2].pred, aSet)
|
||||
elif sameTree(fact[2], loc):
|
||||
# 4 < x --> 3 <= x
|
||||
result = geImpliesIn(fact[2], fact[1].pred, aSet)
|
||||
of mNot, mOr, mAnd: assert(false, "impliesIn")
|
||||
else: discard
|
||||
else:
|
||||
result = impUnknown
|
||||
of mNot, mOr, mAnd:
|
||||
result = impUnknown
|
||||
assert(false, "impliesIn")
|
||||
else: result = impUnknown
|
||||
|
||||
proc valueIsNil(n: PNode): TImplication =
|
||||
if n.kind == nkNilLit: impYes
|
||||
@@ -577,13 +636,19 @@ proc impliesIsNil(fact, eq: PNode): TImplication =
|
||||
of mIsNil:
|
||||
if sameTree(fact[1], eq[1]):
|
||||
result = impYes
|
||||
else:
|
||||
result = impUnknown
|
||||
of someEq:
|
||||
if sameTree(fact[1], eq[1]):
|
||||
result = valueIsNil(fact[2].skipConv)
|
||||
elif sameTree(fact[2], eq[1]):
|
||||
result = valueIsNil(fact[1].skipConv)
|
||||
of mNot, mOr, mAnd: assert(false, "impliesIsNil")
|
||||
else: discard
|
||||
else:
|
||||
result = impUnknown
|
||||
of mNot, mOr, mAnd:
|
||||
result = impUnknown
|
||||
assert(false, "impliesIsNil")
|
||||
else: result = impUnknown
|
||||
|
||||
proc impliesGe(fact, x, c: PNode): TImplication =
|
||||
assert isLocation(x)
|
||||
@@ -594,32 +659,57 @@ proc impliesGe(fact, x, c: PNode): TImplication =
|
||||
# fact: x = 4; question x >= 56? --> true iff 4 >= 56
|
||||
if leValue(c, fact[2]): result = impYes
|
||||
else: result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
elif sameTree(fact[2], x):
|
||||
if isValue(fact[1]) and isValue(c):
|
||||
if leValue(c, fact[1]): result = impYes
|
||||
else: result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
of someLt:
|
||||
if sameTree(fact[1], x):
|
||||
if isValue(fact[2]) and isValue(c):
|
||||
# fact: x < 4; question N <= x? --> false iff N <= 4
|
||||
if leValue(fact[2], c): result = impNo
|
||||
else: result = impUnknown
|
||||
# fact: x < 4; question 2 <= x? --> we don't know
|
||||
else:
|
||||
result = impUnknown
|
||||
elif sameTree(fact[2], x):
|
||||
# fact: 3 < x; question: N-1 < x ? --> true iff N-1 <= 3
|
||||
if isValue(fact[1]) and isValue(c):
|
||||
if leValue(c.pred, fact[1]): result = impYes
|
||||
else: result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
of someLe:
|
||||
if sameTree(fact[1], x):
|
||||
if isValue(fact[2]) and isValue(c):
|
||||
# fact: x <= 4; question x >= 56? --> false iff 4 <= 56
|
||||
if leValue(fact[2], c): result = impNo
|
||||
# fact: x <= 4; question x >= 2? --> we don't know
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
elif sameTree(fact[2], x):
|
||||
# fact: 3 <= x; question: x >= 2 ? --> true iff 2 <= 3
|
||||
if isValue(fact[1]) and isValue(c):
|
||||
if leValue(c, fact[1]): result = impYes
|
||||
of mNot, mOr, mAnd: assert(false, "impliesGe")
|
||||
else: discard
|
||||
else: result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
of mNot, mOr, mAnd:
|
||||
result = impUnknown
|
||||
assert(false, "impliesGe")
|
||||
else: result = impUnknown
|
||||
|
||||
proc impliesLe(fact, x, c: PNode): TImplication =
|
||||
if not isLocation(x):
|
||||
@@ -634,35 +724,59 @@ proc impliesLe(fact, x, c: PNode): TImplication =
|
||||
# fact: x = 4; question x <= 56? --> true iff 4 <= 56
|
||||
if leValue(fact[2], c): result = impYes
|
||||
else: result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
elif sameTree(fact[2], x):
|
||||
if isValue(fact[1]) and isValue(c):
|
||||
if leValue(fact[1], c): result = impYes
|
||||
else: result = impNo
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
of someLt:
|
||||
if sameTree(fact[1], x):
|
||||
if isValue(fact[2]) and isValue(c):
|
||||
# fact: x < 4; question x <= N? --> true iff N-1 <= 4
|
||||
if leValue(fact[2], c.pred): result = impYes
|
||||
else:
|
||||
result = impUnknown
|
||||
# fact: x < 4; question x <= 2? --> we don't know
|
||||
else:
|
||||
result = impUnknown
|
||||
elif sameTree(fact[2], x):
|
||||
# fact: 3 < x; question: x <= 1 ? --> false iff 1 <= 3
|
||||
if isValue(fact[1]) and isValue(c):
|
||||
if leValue(c, fact[1]): result = impNo
|
||||
|
||||
else: result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
of someLe:
|
||||
if sameTree(fact[1], x):
|
||||
if isValue(fact[2]) and isValue(c):
|
||||
# fact: x <= 4; question x <= 56? --> true iff 4 <= 56
|
||||
if leValue(fact[2], c): result = impYes
|
||||
else: result = impUnknown
|
||||
# fact: x <= 4; question x <= 2? --> we don't know
|
||||
else:
|
||||
result = impUnknown
|
||||
|
||||
elif sameTree(fact[2], x):
|
||||
# fact: 3 <= x; question: x <= 2 ? --> false iff 2 < 3
|
||||
if isValue(fact[1]) and isValue(c):
|
||||
if leValue(c, fact[1].pred): result = impNo
|
||||
else:result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
else:
|
||||
result = impUnknown
|
||||
|
||||
of mNot, mOr, mAnd: assert(false, "impliesLe")
|
||||
else: discard
|
||||
of mNot, mOr, mAnd:
|
||||
result = impUnknown
|
||||
assert(false, "impliesLe")
|
||||
else: result = impUnknown
|
||||
|
||||
proc impliesLt(fact, x, c: PNode): TImplication =
|
||||
# x < 3 same as x <= 2:
|
||||
@@ -674,6 +788,8 @@ proc impliesLt(fact, x, c: PNode): TImplication =
|
||||
let q = x.pred
|
||||
if q != x:
|
||||
result = impliesLe(fact, q, c)
|
||||
else:
|
||||
result = impUnknown
|
||||
|
||||
proc `~`(x: TImplication): TImplication =
|
||||
case x
|
||||
@@ -725,6 +841,7 @@ proc factImplies(fact, prop: PNode): TImplication =
|
||||
|
||||
proc doesImply*(facts: TModel, prop: PNode): TImplication =
|
||||
assert prop.kind in nkCallKinds
|
||||
result = impUnknown
|
||||
for f in facts.s:
|
||||
# facts can be invalidated, in which case they are 'nil':
|
||||
if not f.isNil:
|
||||
@@ -900,6 +1017,7 @@ proc applyReplacements(n: PNode; rep: TReplacements): PNode =
|
||||
|
||||
proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
|
||||
# now check for inferrable facts: a <= b and b <= c implies a <= c
|
||||
result = impUnknown
|
||||
for i in 0..m.s.high:
|
||||
let fact = m.s[i]
|
||||
if fact != nil and fact.getMagic in someLe:
|
||||
@@ -981,7 +1099,7 @@ proc addFactLt*(m: var TModel; a, b: PNode) =
|
||||
|
||||
proc settype(n: PNode): PType =
|
||||
result = newType(tySet, ItemId(module: -1, item: -1), n.typ.owner)
|
||||
var idgen: IdGenerator
|
||||
var idgen: IdGenerator = nil
|
||||
addSonSkipIntLit(result, n.typ, idgen)
|
||||
|
||||
proc buildOf(it, loc: PNode; o: Operators): PNode =
|
||||
|
||||
@@ -20,9 +20,11 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
|
||||
# we need to ensure that the resulting AST is semchecked. However, it's
|
||||
# awful to semcheck before macro invocation, so we don't and treat
|
||||
# templates and macros as immediate in this context.
|
||||
var rule: string
|
||||
if c.config.hasHint(hintPattern):
|
||||
rule = renderTree(n, {renderNoComments})
|
||||
var rule: string =
|
||||
if c.config.hasHint(hintPattern):
|
||||
renderTree(n, {renderNoComments})
|
||||
else:
|
||||
""
|
||||
let s = n[0].sym
|
||||
case s.kind
|
||||
of skMacro:
|
||||
@@ -73,7 +75,7 @@ proc hlo(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
if n.kind in {nkFastAsgn, nkAsgn, nkSinkAsgn, nkIdentDefs, nkVarTuple} and
|
||||
n[0].kind == nkSym and
|
||||
{sfGlobal, sfPure} * n[0].sym.flags == {sfGlobal, sfPure}:
|
||||
{sfGlobal, sfPure} <= n[0].sym.flags:
|
||||
# do not optimize 'var g {.global} = re(...)' again!
|
||||
return n
|
||||
result = applyPatterns(c, n)
|
||||
|
||||
@@ -50,7 +50,10 @@ proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var Alive
|
||||
let n = unpackTree(g, m.module.position, m.fromDisk.topLevel, p)
|
||||
cgen.genTopLevelStmt(bmod, n)
|
||||
|
||||
finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
|
||||
let disps = finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
|
||||
if disps != nil:
|
||||
for disp in disps:
|
||||
genProcAux(bmod, disp.sym)
|
||||
m.fromDisk.backendFlags = cgen.whichInitProcs(bmod)
|
||||
|
||||
proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) =
|
||||
@@ -98,7 +101,7 @@ proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool
|
||||
var f2 = rodfiles.open(asymFile.string)
|
||||
f2.loadHeader()
|
||||
f2.loadSection aliveSymsSection
|
||||
var oldData: seq[int32]
|
||||
var oldData: seq[int32] = @[]
|
||||
f2.loadSeq(oldData)
|
||||
f2.close
|
||||
if f2.err == ok and oldData == s:
|
||||
|
||||
@@ -40,10 +40,14 @@ proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): boo
|
||||
if ({sfExportc, sfCompilerProc} * flags != {}) or
|
||||
(symPtr.kind == skMethod):
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
# XXX: This used to be a condition to:
|
||||
# (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
|
||||
if sfCompilerProc in flags:
|
||||
c.compilerProcs[g[c.thisModule].fromDisk.strings[symPtr.name]] = (c.thisModule, symId)
|
||||
else:
|
||||
result = false
|
||||
|
||||
template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty
|
||||
|
||||
|
||||
@@ -7,13 +7,15 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import hashes, tables, intsets, std/sha1
|
||||
import hashes, tables, intsets
|
||||
import packed_ast, bitabs, rodfiles
|
||||
import ".." / [ast, idents, lineinfos, msgs, ropes, options,
|
||||
pathutils, condsyms, packages, modulepaths]
|
||||
#import ".." / [renderer, astalgo]
|
||||
from os import removeFile, isAbsolute
|
||||
|
||||
import ../../dist/checksums/src/checksums/sha1
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions, formatfloat]
|
||||
|
||||
@@ -357,7 +359,7 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI
|
||||
paddingAtEnd: t.paddingAtEnd)
|
||||
storeNode(p, t, n)
|
||||
p.typeInst = t.typeInst.storeType(c, m)
|
||||
for kid in items t.sons:
|
||||
for kid in items t:
|
||||
p.types.add kid.storeType(c, m)
|
||||
c.addMissing t.sym
|
||||
p.sym = t.sym.safeItemId(c, m)
|
||||
@@ -372,7 +374,7 @@ proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib
|
||||
if l.isNil: return
|
||||
result.kind = l.kind
|
||||
result.generated = l.generated
|
||||
result.isOverriden = l.isOverriden
|
||||
result.isOverridden = l.isOverridden
|
||||
result.name = toLitId($l.name, m)
|
||||
storeNode(result, l, path)
|
||||
|
||||
@@ -390,7 +392,7 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
|
||||
assert sfForward notin s.flags
|
||||
|
||||
var p = PackedSym(kind: s.kind, flags: s.flags, info: s.info.toPackedInfo(c, m), magic: s.magic,
|
||||
position: s.position, offset: s.offset, options: s.options,
|
||||
position: s.position, offset: s.offset, disamb: s.disamb, options: s.options,
|
||||
name: s.name.s.toLitId(m))
|
||||
|
||||
storeNode(p, s, ast)
|
||||
@@ -811,6 +813,7 @@ proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; thisModule:
|
||||
|
||||
proc loadProcBody(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
|
||||
tree: PackedTree; n: NodePos): PNode =
|
||||
result = nil
|
||||
var i = 0
|
||||
for n0 in sonsReadonly(tree, n):
|
||||
if i == bodyPos:
|
||||
@@ -830,6 +833,7 @@ proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
|
||||
options: s.options,
|
||||
position: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position,
|
||||
offset: if s.kind in routineKinds: defaultOffset else: s.offset,
|
||||
disamb: s.disamb,
|
||||
name: getIdent(c.cache, g[si].fromDisk.strings[s.name])
|
||||
)
|
||||
|
||||
@@ -847,7 +851,7 @@ proc loadLib(c: var PackedDecoder; g: var PackedModuleGraph;
|
||||
if l.name.int == 0:
|
||||
result = nil
|
||||
else:
|
||||
result = PLib(generated: l.generated, isOverriden: l.isOverriden,
|
||||
result = PLib(generated: l.generated, isOverridden: l.isOverridden,
|
||||
kind: l.kind, name: rope g[si].fromDisk.strings[l.name])
|
||||
loadAstBody(l, path)
|
||||
|
||||
@@ -913,7 +917,7 @@ proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
|
||||
result.attachedOps[op] = loadSym(c, g, si, item)
|
||||
result.typeInst = loadType(c, g, si, t.typeInst)
|
||||
for son in items t.types:
|
||||
result.sons.add loadType(c, g, si, son)
|
||||
result.addSon loadType(c, g, si, son)
|
||||
loadAstBody(t, n)
|
||||
when false:
|
||||
for gen, id in items t.methods:
|
||||
@@ -1144,6 +1148,8 @@ proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache;
|
||||
if it.i < it.values.len:
|
||||
result = loadSym(it.decoder, g, int(module), it.values[it.i])
|
||||
inc it.i
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
|
||||
g: var PackedModuleGraph; module: FileIndex, importHidden: bool): PSym =
|
||||
@@ -1161,11 +1167,15 @@ proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
|
||||
if it.i < it.values.len:
|
||||
result = loadSym(it.decoder, g, int(module), it.values[it.i])
|
||||
inc it.i
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc nextRodIter*(it: var RodIter; g: var PackedModuleGraph): PSym =
|
||||
if it.i < it.values.len:
|
||||
result = loadSym(it.decoder, g, it.module, it.values[it.i])
|
||||
inc it.i
|
||||
else:
|
||||
result = nil
|
||||
|
||||
iterator interfaceSymbols*(config: ConfigRef, cache: IdentCache;
|
||||
g: var PackedModuleGraph; module: FileIndex;
|
||||
@@ -1198,7 +1208,7 @@ proc searchForCompilerproc*(m: LoadedModule; name: string): int32 =
|
||||
# ------------------------- .rod file viewer ---------------------------------
|
||||
|
||||
proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
|
||||
var m: PackedModule
|
||||
var m: PackedModule = PackedModule()
|
||||
let err = loadRodFile(rodfile, m, config, ignoreConfig=true)
|
||||
if err != ok:
|
||||
config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err
|
||||
|
||||
@@ -34,7 +34,11 @@ proc isTracked(current, trackPos: PackedLineInfo, tokenLen: int): bool =
|
||||
if current.file == trackPos.file and current.line == trackPos.line:
|
||||
let col = trackPos.col
|
||||
if col >= current.col and col < current.col+tokenLen:
|
||||
return true
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool =
|
||||
result = s.name != LitId(0) and
|
||||
|
||||
@@ -45,7 +45,7 @@ type
|
||||
PackedLib* = object
|
||||
kind*: TLibKind
|
||||
generated*: bool
|
||||
isOverriden*: bool
|
||||
isOverridden*: bool
|
||||
name*: LitId
|
||||
path*: NodeId
|
||||
|
||||
@@ -63,7 +63,8 @@ type
|
||||
alignment*: int # for alignment
|
||||
options*: TOptions
|
||||
position*: int
|
||||
offset*: int
|
||||
offset*: int32
|
||||
disamb*: int32
|
||||
externalName*: LitId # instead of TLoc
|
||||
locFlags*: TLocFlags
|
||||
annex*: PackedLib
|
||||
@@ -304,6 +305,7 @@ proc sons3*(tree: PackedTree; n: NodePos): (NodePos, NodePos, NodePos) =
|
||||
result = (NodePos a, NodePos b, NodePos c)
|
||||
|
||||
proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos =
|
||||
result = default(NodePos)
|
||||
if tree.nodes[n.int].kind > nkNilLit:
|
||||
var count = 0
|
||||
for child in sonsReadonly(tree, n):
|
||||
|
||||
@@ -24,7 +24,7 @@ when defined(nimPreviewSlimSystem):
|
||||
## `RodFile` represents a Rod File (versioned binary format), and the
|
||||
## associated data for common interactions such as IO and error tracking
|
||||
## (`RodFileError`). The file format broken up into sections (`RodSection`)
|
||||
## and preceeded by a header (see: `cookie`). The precise layout, section
|
||||
## 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`.
|
||||
##
|
||||
@@ -215,7 +215,7 @@ proc storeHeader*(f: var RodFile) =
|
||||
proc loadHeader*(f: var RodFile) =
|
||||
## Loads the header which is described by `cookie`.
|
||||
if f.err != ok: return
|
||||
var thisCookie: array[cookie.len, byte]
|
||||
var thisCookie: array[cookie.len, byte] = default(array[cookie.len, byte])
|
||||
if f.f.readBytes(thisCookie, 0, thisCookie.len) != thisCookie.len:
|
||||
setError f, ioFailure
|
||||
elif thisCookie != cookie:
|
||||
@@ -231,13 +231,14 @@ proc storeSection*(f: var RodFile; s: RodSection) =
|
||||
proc loadSection*(f: var RodFile; expected: RodSection) =
|
||||
## read the bytes value of s, sets and error if the section is incorrect.
|
||||
if f.err != ok: return
|
||||
var s: RodSection
|
||||
var s: RodSection = default(RodSection)
|
||||
loadPrim(f, s)
|
||||
if expected != s and f.err == ok:
|
||||
setError f, wrongSection
|
||||
|
||||
proc create*(filename: string): RodFile =
|
||||
## create the file and open it for writing
|
||||
result = default(RodFile)
|
||||
if not open(result.f, filename, fmWrite):
|
||||
setError result, cannotOpen
|
||||
|
||||
@@ -245,5 +246,6 @@ proc close*(f: var RodFile) = close(f.f)
|
||||
|
||||
proc open*(filename: string): RodFile =
|
||||
## open the file for reading
|
||||
result = default(RodFile)
|
||||
if not open(result.f, filename, fmRead):
|
||||
setError result, cannotOpen
|
||||
|
||||
@@ -113,6 +113,7 @@ proc rawImportSymbol(c: PContext, s, origin: PSym; importSet: var IntSet) =
|
||||
|
||||
proc splitPragmas(c: PContext, n: PNode): (PNode, seq[TSpecialWord]) =
|
||||
template bail = globalError(c.config, n.info, "invalid pragma")
|
||||
result = (nil, @[])
|
||||
if n.kind == nkPragmaExpr:
|
||||
if n.len == 2 and n[1].kind == nkPragma:
|
||||
result[0] = n[0]
|
||||
@@ -228,10 +229,15 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; im
|
||||
for i in 0..n.safeLen-1:
|
||||
importForwarded(c, n[i], exceptSet, fromMod, importSet)
|
||||
|
||||
proc addUnique[T](x: var seq[T], y: sink T) {.noSideEffect.} =
|
||||
for i in 0..high(x):
|
||||
if x[i] == y: return
|
||||
x.add y
|
||||
|
||||
proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym =
|
||||
result = realModule
|
||||
template createModuleAliasImpl(ident): untyped =
|
||||
createModuleAlias(realModule, nextSymId c.idgen, ident, n.info, c.config.options)
|
||||
createModuleAlias(realModule, c.idgen, ident, n.info, c.config.options)
|
||||
if n.kind != nkImportAs: discard
|
||||
elif n.len != 2 or n[1].kind != nkIdent:
|
||||
localError(c.config, n.info, "module alias must be an identifier")
|
||||
@@ -245,6 +251,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool)
|
||||
result.options.incl optImportHidden
|
||||
c.unusedImports.add((result, n.info))
|
||||
c.importModuleMap[result.id] = realModule.id
|
||||
c.importModuleLookup.mgetOrPut(result.name.id, @[]).addUnique realModule.id
|
||||
|
||||
proc transformImportAs(c: PContext; n: PNode): tuple[node: PNode, importHidden: bool] =
|
||||
var ret: typeof(result)
|
||||
@@ -301,6 +308,8 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
|
||||
suggestSym(c.graph, n.info, result, c.graph.usageSym, false)
|
||||
importStmtResult.add newSymNode(result, n.info)
|
||||
#newStrNode(toFullPath(c.config, f), n.info)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc afterImport(c: PContext, m: PSym) =
|
||||
# fixes bug #17510, for re-exported symbols
|
||||
@@ -323,22 +332,24 @@ proc evalImport*(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkImportStmt, n.info)
|
||||
for i in 0..<n.len:
|
||||
let it = n[i]
|
||||
if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
|
||||
let sep = it[0]
|
||||
let dir = it[1]
|
||||
var imp = newNodeI(nkInfix, it.info)
|
||||
imp.add sep
|
||||
imp.add dir
|
||||
imp.add sep # dummy entry, replaced in the loop
|
||||
for x in it[2]:
|
||||
if it.kind in {nkInfix, nkPrefix} and it[^1].kind == nkBracket:
|
||||
let lastPos = it.len - 1
|
||||
var imp = copyNode(it)
|
||||
newSons(imp, it.len)
|
||||
for i in 0 ..< lastPos: imp[i] = it[i]
|
||||
imp[lastPos] = imp[0] # dummy entry, replaced in the loop
|
||||
for x in it[lastPos]:
|
||||
# transform `a/b/[c as d]` to `/a/b/c as d`
|
||||
if x.kind == nkInfix and x[0].ident.s == "as":
|
||||
let impAs = copyTree(x)
|
||||
imp[2] = x[1]
|
||||
var impAs = copyNode(x)
|
||||
newSons(impAs, 3)
|
||||
impAs[0] = x[0]
|
||||
imp[lastPos] = x[1]
|
||||
impAs[1] = imp
|
||||
impMod(c, imp, result)
|
||||
impAs[2] = x[2]
|
||||
impMod(c, impAs, result)
|
||||
else:
|
||||
imp[2] = x
|
||||
imp[lastPos] = x
|
||||
impMod(c, imp, result)
|
||||
else:
|
||||
impMod(c, it, result)
|
||||
|
||||
@@ -17,12 +17,12 @@ import
|
||||
intsets, strtabs, ast, astalgo, msgs, renderer, magicsys, types, idents,
|
||||
strutils, options, lowerings, tables, modulegraphs,
|
||||
lineinfos, parampatterns, sighashes, liftdestructors, optimizer,
|
||||
varpartitions, aliasanalysis, dfa
|
||||
varpartitions, aliasanalysis, dfa, wordrecg
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
from trees import exprStructuralEquivalent, getRoot
|
||||
from trees import exprStructuralEquivalent, getRoot, whichPragma
|
||||
|
||||
type
|
||||
Con = object
|
||||
@@ -35,6 +35,8 @@ type
|
||||
idgen: IdGenerator
|
||||
body: PNode
|
||||
otherUsage: TLineInfo
|
||||
inUncheckedAssignSection: int
|
||||
inEnsureMove: int
|
||||
|
||||
Scope = object # we do scope-based memory management.
|
||||
# a scope is comparable to an nkStmtListExpr like
|
||||
@@ -65,11 +67,11 @@ 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}:
|
||||
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): PNode =
|
||||
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), nextSymId c.idgen, c.owner, info)
|
||||
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.idgen, c.owner, info)
|
||||
sym.typ = typ
|
||||
s.vars.add(sym)
|
||||
result = newSymNode(sym)
|
||||
@@ -77,11 +79,11 @@ proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
|
||||
proc nestedScope(parent: var Scope; body: PNode): Scope =
|
||||
Scope(vars: @[], locals: @[], wasMoved: @[], final: @[], body: body, needsTry: false, parent: addr(parent))
|
||||
|
||||
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode
|
||||
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode
|
||||
|
||||
type
|
||||
MoveOrCopyFlag = enum
|
||||
IsDecl, IsExplicitSink
|
||||
IsDecl, IsExplicitSink, IsReturn
|
||||
|
||||
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; flags: set[MoveOrCopyFlag] = {}): PNode
|
||||
|
||||
@@ -183,11 +185,16 @@ proc isCursor(n: PNode): bool =
|
||||
template isUnpackedTuple(n: PNode): bool =
|
||||
## we move out all elements of unpacked tuples,
|
||||
## hence unpacked tuples themselves don't need to be destroyed
|
||||
(n.kind == nkSym and n.sym.kind == skTemp and n.sym.typ.kind == tyTuple)
|
||||
## except it's already a cursor
|
||||
(n.kind == nkSym and n.sym.kind == skTemp and
|
||||
n.sym.typ.kind == tyTuple and sfCursor notin n.sym.flags)
|
||||
|
||||
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) =
|
||||
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFromCopy = false) =
|
||||
var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">"
|
||||
if (opname == "=" or opname == "=copy") and ri != nil:
|
||||
if inferredFromCopy:
|
||||
m.add ", which is inferred from unavailable '=copy'"
|
||||
|
||||
if (opname == "=" or opname == "=copy" or opname == "=dup") and ri != nil:
|
||||
m.add "; requires a copy because it's not the last read of '"
|
||||
m.add renderTree(ri)
|
||||
m.add '\''
|
||||
@@ -209,15 +216,19 @@ proc makePtrType(c: var Con, baseType: PType): PType =
|
||||
addSonSkipIntLit(result, baseType, c.idgen)
|
||||
|
||||
proc genOp(c: var Con; op: PSym; dest: PNode): PNode =
|
||||
let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
|
||||
addrExp.add(dest)
|
||||
var addrExp: PNode
|
||||
if op.typ != nil and op.typ.len > 1 and op.typ[1].kind != tyVar:
|
||||
addrExp = dest
|
||||
else:
|
||||
addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
|
||||
addrExp.add(dest)
|
||||
result = newTree(nkCall, newSymNode(op), addrExp)
|
||||
|
||||
proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
|
||||
var op = getAttachedOp(c.graph, t, kind)
|
||||
if op == nil or op.ast.isGenericRoutine:
|
||||
# give up and find the canonical type instead:
|
||||
let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let h = sighashes.hashType(t, c.graph.config, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let canon = c.graph.canonTypes.getOrDefault(h)
|
||||
if canon != nil:
|
||||
op = getAttachedOp(c.graph, canon, kind)
|
||||
@@ -248,10 +259,20 @@ proc canBeMoved(c: Con; t: PType): bool {.inline.} =
|
||||
proc isNoInit(dest: PNode): bool {.inline.} =
|
||||
result = dest.kind == nkSym and sfNoInit in dest.sym.flags
|
||||
|
||||
proc genSink(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
|
||||
proc deepAliases(dest, ri: PNode): bool =
|
||||
case ri.kind
|
||||
of nkCallKinds, nkStmtListExpr, nkBracket, nkTupleConstr, nkObjConstr,
|
||||
nkCast, nkConv, nkObjUpConv, nkObjDownConv:
|
||||
for r in ri:
|
||||
if deepAliases(dest, r): return true
|
||||
return false
|
||||
else:
|
||||
return aliases(dest, ri) != no
|
||||
|
||||
proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
|
||||
if (c.inLoopCond == 0 and (isUnpackedTuple(dest) or IsDecl in flags or
|
||||
(isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)))) or
|
||||
isNoInit(dest):
|
||||
isNoInit(dest) or IsReturn in flags:
|
||||
# optimize sink call into a bitwise memcopy
|
||||
result = newTree(nkFastAsgn, dest, ri)
|
||||
else:
|
||||
@@ -262,7 +283,14 @@ proc genSink(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNod
|
||||
else:
|
||||
# the default is to use combination of `=destroy(dest)` and
|
||||
# and copyMem(dest, source). This is efficient.
|
||||
result = newTree(nkStmtList, c.genDestroy(dest), newTree(nkFastAsgn, dest, ri))
|
||||
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)
|
||||
result = newTree(nkStmtList, newTree(nkFastAsgn, tmp, dest), newTree(nkFastAsgn, dest, ri),
|
||||
c.genDestroy(tmp))
|
||||
else:
|
||||
result = newTree(nkStmtList, c.genDestroy(dest), newTree(nkFastAsgn, dest, ri))
|
||||
|
||||
proc isCriticalLink(dest: PNode): bool {.inline.} =
|
||||
#[
|
||||
@@ -287,13 +315,13 @@ proc isCriticalLink(dest: PNode): bool {.inline.} =
|
||||
proc finishCopy(c: var Con; result, dest: PNode; isFromSink: bool) =
|
||||
if c.graph.config.selectedGC == gcOrc:
|
||||
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
|
||||
if cyclicType(t):
|
||||
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 == gcOrc:
|
||||
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
|
||||
if cyclicType(t):
|
||||
if cyclicType(c.graph, t):
|
||||
if t.kind == tyRef:
|
||||
result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest)
|
||||
else:
|
||||
@@ -307,6 +335,9 @@ proc genCopyNoCheck(c: var Con; dest, ri: PNode; a: TTypeAttachedOp): PNode =
|
||||
assert ri.typ != nil
|
||||
|
||||
proc genCopy(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag]): PNode =
|
||||
if c.inEnsureMove > 0:
|
||||
localError(c.graph.config, ri.info, errFailedMove, "cannot move '" & $ri &
|
||||
"', which introduces an implicit copy")
|
||||
let t = dest.typ
|
||||
if tfHasOwned in t.flags and ri.kind != nkNilLit:
|
||||
# try to improve the error message here:
|
||||
@@ -335,30 +366,38 @@ proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode =
|
||||
|
||||
if hasDestructor(c, objType):
|
||||
if getAttachedOp(c.graph, objType, attachedDestructor) != nil and
|
||||
sfOverriden in getAttachedOp(c.graph, objType, attachedDestructor).flags:
|
||||
sfOverridden in getAttachedOp(c.graph, objType, attachedDestructor).flags:
|
||||
localError(c.graph.config, n.info, errGenerated, """Assignment to discriminant for objects with user defined destructor is not supported, object must have default destructor.
|
||||
It is best to factor out piece of object that needs custom destructor into separate object or not use discriminator assignment""")
|
||||
result.add newTree(nkFastAsgn, le, tmp)
|
||||
return
|
||||
|
||||
# generate: if le != tmp: `=destroy`(le)
|
||||
let branchDestructor = produceDestructorForDiscriminator(c.graph, objType, leDotExpr[1].sym, n.info, c.idgen)
|
||||
let cond = newNodeIT(nkInfix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
|
||||
cond.add newSymNode(getMagicEqSymForType(c.graph, le.typ, n.info))
|
||||
cond.add le
|
||||
cond.add tmp
|
||||
let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
|
||||
notExpr.add newSymNode(createMagic(c.graph, c.idgen, "not", mNot))
|
||||
notExpr.add cond
|
||||
result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, c.genOp(branchDestructor, le)))
|
||||
if c.inUncheckedAssignSection != 0:
|
||||
let branchDestructor = produceDestructorForDiscriminator(c.graph, objType, leDotExpr[1].sym, n.info, c.idgen)
|
||||
let cond = newNodeIT(nkInfix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
|
||||
cond.add newSymNode(getMagicEqSymForType(c.graph, le.typ, n.info))
|
||||
cond.add le
|
||||
cond.add tmp
|
||||
let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
|
||||
notExpr.add newSymNode(createMagic(c.graph, c.idgen, "not", mNot))
|
||||
notExpr.add cond
|
||||
result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, c.genOp(branchDestructor, le)))
|
||||
result.add newTree(nkFastAsgn, le, tmp)
|
||||
|
||||
proc genWasMoved(c: var Con, n: PNode): PNode =
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add(newSymNode(createMagic(c.graph, c.idgen, "wasMoved", mWasMoved)))
|
||||
result.add copyTree(n) #mWasMoved does not take the address
|
||||
#if n.kind != nkSym:
|
||||
# message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")")
|
||||
let typ = n.typ.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
let op = getAttachedOp(c.graph, n.typ, attachedWasMoved)
|
||||
if op != nil:
|
||||
if sfError in op.flags:
|
||||
c.checkForErrorPragma(n.typ, n, "=wasMoved")
|
||||
result = genOp(c, op, n)
|
||||
else:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add(newSymNode(createMagic(c.graph, c.idgen, "`=wasMoved`", mWasMoved)))
|
||||
result.add copyTree(n) #mWasMoved does not take the address
|
||||
#if n.kind != nkSym:
|
||||
# message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")")
|
||||
|
||||
proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
|
||||
result = newNodeI(nkCall, info)
|
||||
@@ -367,13 +406,13 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
|
||||
|
||||
proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
# generate: (let tmp = v; reset(v); tmp)
|
||||
if not hasDestructor(c, n.typ):
|
||||
if (not hasDestructor(c, n.typ)) and c.inEnsureMove == 0:
|
||||
assert n.kind != nkSym or not hasDestructor(c, n.sym.typ)
|
||||
result = copyTree(n)
|
||||
else:
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
|
||||
var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), nextSymId c.idgen, c.owner, n.info)
|
||||
var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.idgen, c.owner, n.info)
|
||||
temp.typ = n.typ
|
||||
var v = newNodeI(nkLetSection, n.info)
|
||||
let tempAsNode = newSymNode(temp)
|
||||
@@ -386,7 +425,8 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
|
||||
result.add v
|
||||
let nn = skipConv(n)
|
||||
c.genMarkCyclic(result, nn)
|
||||
if hasDestructor(c, n.typ):
|
||||
c.genMarkCyclic(result, nn)
|
||||
let wasMovedCall = c.genWasMoved(nn)
|
||||
result.add wasMovedCall
|
||||
result.add tempAsNode
|
||||
@@ -394,22 +434,47 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
proc isCapturedVar(n: PNode): bool =
|
||||
let root = getRoot(n)
|
||||
if root != nil: result = root.name.s[0] == ':'
|
||||
else: result = false
|
||||
|
||||
proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
let tmp = c.getTemp(s, n.typ, n.info)
|
||||
if hasDestructor(c, n.typ):
|
||||
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
|
||||
let typ = n.typ.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(n.typ, 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(n.typ, 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 n.typ.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}:
|
||||
if c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
assert(not containsManagedMemory(n.typ))
|
||||
if n.typ.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")
|
||||
@@ -445,14 +510,14 @@ proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode =
|
||||
# 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)
|
||||
result.add c.genSink(tmp, arg, {IsDecl})
|
||||
result.add c.genSink(s, tmp, arg, {IsDecl})
|
||||
result.add tmp
|
||||
s.final.add c.genDestroy(tmp)
|
||||
else:
|
||||
result = arg
|
||||
|
||||
proc cycleCheck(n: PNode; c: var Con) =
|
||||
if c.graph.config.selectedGC != gcArc: return
|
||||
if c.graph.config.selectedGC notin {gcArc, gcAtomicArc}: return
|
||||
var value = n[1]
|
||||
if value.kind == nkClosure:
|
||||
value = value[1]
|
||||
@@ -653,7 +718,27 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false,
|
||||
of nkWhen: # This should be a "when nimvm" node.
|
||||
result = copyTree(n)
|
||||
result[1][0] = processCall(n[1][0], s)
|
||||
else: assert(false)
|
||||
|
||||
of nkPragmaBlock:
|
||||
var inUncheckedAssignSection = 0
|
||||
let pragmaList = n[0]
|
||||
for pi in pragmaList:
|
||||
if whichPragma(pi) == wCast:
|
||||
case whichPragma(pi[1])
|
||||
of wUncheckedAssign:
|
||||
inUncheckedAssignSection = 1
|
||||
else:
|
||||
discard
|
||||
result = shallowCopy(n)
|
||||
inc c.inUncheckedAssignSection, inUncheckedAssignSection
|
||||
for i in 0 ..< n.len-1:
|
||||
result[i] = p(n[i], c, s, normal)
|
||||
result[^1] = maybeVoid(n[^1], s)
|
||||
dec c.inUncheckedAssignSection, inUncheckedAssignSection
|
||||
|
||||
else:
|
||||
result = nil
|
||||
assert(false)
|
||||
|
||||
proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
|
||||
if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty:
|
||||
@@ -680,9 +765,9 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
|
||||
result.add copyNode(n[0])
|
||||
s.needsTry = true
|
||||
|
||||
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode =
|
||||
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode =
|
||||
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt,
|
||||
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt}:
|
||||
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}:
|
||||
template process(child, s): untyped = p(child, c, s, mode)
|
||||
handleNestedTempl(n, process, tmpFlags = tmpFlags)
|
||||
elif mode == sinkArg:
|
||||
@@ -693,7 +778,15 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
result = passCopyToSink(n, c, s)
|
||||
elif n.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkClosure, nkNilLit} +
|
||||
nkCallKinds + nkLiterals:
|
||||
result = p(n, c, s, consumed)
|
||||
if n.kind in nkCallKinds and n[0].kind == nkSym:
|
||||
if n[0].sym.magic == mEnsureMove:
|
||||
inc c.inEnsureMove
|
||||
result = p(n[1], c, s, sinkArg)
|
||||
dec c.inEnsureMove
|
||||
else:
|
||||
result = p(n, c, s, consumed)
|
||||
else:
|
||||
result = p(n, c, s, consumed)
|
||||
elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and
|
||||
isLastRead(n, c, s) and not (n.kind == nkSym and isCursor(n)):
|
||||
# Sinked params can be consumed only once. We need to reset the memory
|
||||
@@ -765,6 +858,12 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
if mode == normal and isRefConstr:
|
||||
result = ensureDestruction(result, n, c, s)
|
||||
of nkCallKinds:
|
||||
if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove:
|
||||
inc c.inEnsureMove
|
||||
result = p(n[1], c, s, sinkArg)
|
||||
dec c.inEnsureMove
|
||||
return
|
||||
|
||||
let inSpawn = c.inSpawn
|
||||
if n[0].kind == nkSym and n[0].sym.magic == mSpawn:
|
||||
c.inSpawn.inc
|
||||
@@ -795,7 +894,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, gcOrc}:
|
||||
if c.graph.config.selectedGC in {gcHooks, gcArc, gcAtomicArc, gcOrc}:
|
||||
let destroyOld = c.genDestroy(result[1])
|
||||
result = newTree(nkStmtList, destroyOld, result)
|
||||
else:
|
||||
@@ -829,7 +928,10 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
if ri.kind != nkEmpty:
|
||||
result.add moveOrCopy(v, ri, c, s, if v.kind == nkSym: {IsDecl} else: {})
|
||||
elif ri.kind == nkEmpty and c.inLoop > 0:
|
||||
result.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, if v.kind == nkSym: {IsDecl} else: {})
|
||||
let skipInit = v.kind == nkDotExpr and # Closure var
|
||||
sfNoInit in v[1].sym.flags
|
||||
if not skipInit:
|
||||
result.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, if v.kind == nkSym: {IsDecl} else: {})
|
||||
else: # keep the var but transform 'ri':
|
||||
var v = copyNode(n)
|
||||
var itCopy = copyNode(it)
|
||||
@@ -847,7 +949,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
|
||||
cycleCheck(n, c)
|
||||
assert n[1].kind notin {nkAsgn, nkFastAsgn, nkSinkAsgn}
|
||||
let flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
|
||||
var flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
|
||||
if inReturn:
|
||||
flags.incl(IsReturn)
|
||||
result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s, flags)
|
||||
elif isDiscriminantField(n[0]):
|
||||
result = c.genDiscriminantAsgn(s, n)
|
||||
@@ -867,7 +971,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
|
||||
result = n
|
||||
|
||||
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock:
|
||||
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange:
|
||||
result = shallowCopy(n)
|
||||
for i in 0 ..< n.len:
|
||||
result[i] = p(n[i], c, s, normal)
|
||||
@@ -931,7 +1035,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
of nkReturnStmt:
|
||||
result = shallowCopy(n)
|
||||
for i in 0..<n.len:
|
||||
result[i] = p(n[i], c, s, mode)
|
||||
result[i] = p(n[i], c, s, mode, inReturn=true)
|
||||
s.needsTry = true
|
||||
of nkCast:
|
||||
result = shallowCopy(n)
|
||||
@@ -945,11 +1049,12 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
of nkGotoState, nkState, nkAsmStmt:
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
internalError(c.graph.config, n.info, "cannot inject destructors to node kind: " & $n.kind)
|
||||
|
||||
proc sameLocation*(a, b: PNode): bool =
|
||||
proc sameConstant(a, b: PNode): bool =
|
||||
a.kind in nkLiterals and a.intVal == b.intVal
|
||||
a.kind in nkLiterals and b.kind in nkLiterals and a.intVal == b.intVal
|
||||
|
||||
const nkEndPoint = {nkSym, nkDotExpr, nkCheckedFieldExpr, nkBracketExpr}
|
||||
if a.kind in nkEndPoint and b.kind in nkEndPoint:
|
||||
@@ -973,9 +1078,9 @@ proc sameLocation*(a, b: PNode): bool =
|
||||
of nkHiddenStdConv, nkHiddenSubConv: sameLocation(a[1], b)
|
||||
else: false
|
||||
|
||||
proc genFieldAccessSideEffects(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
|
||||
proc genFieldAccessSideEffects(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
|
||||
# with side effects
|
||||
var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), nextSymId c.idgen, c.owner, ri[1].info)
|
||||
var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), c.idgen, c.owner, ri[1].info)
|
||||
temp.typ = ri[1].typ
|
||||
var v = newNodeI(nkLetSection, ri[1].info)
|
||||
let tempAsNode = newSymNode(temp)
|
||||
@@ -990,14 +1095,22 @@ proc genFieldAccessSideEffects(c: var Con; dest, ri: PNode; flags: set[MoveOrCop
|
||||
newAccess.add ri[0]
|
||||
newAccess.add tempAsNode
|
||||
|
||||
var snk = c.genSink(dest, newAccess, flags)
|
||||
var snk = c.genSink(s, dest, newAccess, flags)
|
||||
result = newTree(nkStmtList, v, snk, c.genWasMoved(newAccess))
|
||||
|
||||
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopyFlag] = {}): PNode =
|
||||
var ri = ri
|
||||
var isEnsureMove = 0
|
||||
if ri.kind in nkCallKinds and ri[0].kind == nkSym and ri[0].sym.magic == mEnsureMove:
|
||||
ri = ri[1]
|
||||
isEnsureMove = 1
|
||||
if sameLocation(dest, ri):
|
||||
# rule (self-assignment-removal):
|
||||
result = newNodeI(nkEmpty, dest.info)
|
||||
elif isCursor(dest):
|
||||
elif isCursor(dest) or dest.typ.kind in {tyOpenArray, tyVarargs}:
|
||||
# hoisted openArray parameters might end up here
|
||||
# openArray types don't have a lifted assignment operation (it's empty)
|
||||
# bug #22132
|
||||
case ri.kind:
|
||||
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
|
||||
template process(child, s): untyped = moveOrCopy(dest, child, c, s, flags)
|
||||
@@ -1006,53 +1119,61 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
|
||||
else:
|
||||
result = newTree(nkFastAsgn, dest, p(ri, c, s, normal))
|
||||
else:
|
||||
case ri.kind
|
||||
let ri2 = if ri.kind == nkWhen: ri[1][0] else: ri
|
||||
case ri2.kind
|
||||
of nkCallKinds:
|
||||
result = c.genSink(dest, p(ri, c, s, consumed), flags)
|
||||
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
|
||||
of nkBracketExpr:
|
||||
if isUnpackedTuple(ri[0]):
|
||||
# unpacking of tuple: take over the elements
|
||||
result = c.genSink(dest, p(ri, c, s, consumed), flags)
|
||||
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
|
||||
elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s):
|
||||
if aliases(dest, ri) == no:
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
if isAtom(ri[1]):
|
||||
var snk = c.genSink(dest, ri, flags)
|
||||
var snk = c.genSink(s, dest, ri, flags)
|
||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||
else:
|
||||
result = genFieldAccessSideEffects(c, dest, ri, flags)
|
||||
result = genFieldAccessSideEffects(c, s, dest, ri, flags)
|
||||
else:
|
||||
result = c.genSink(dest, destructiveMoveVar(ri, c, s), flags)
|
||||
result = c.genSink(s, dest, destructiveMoveVar(ri, c, s), flags)
|
||||
else:
|
||||
inc c.inEnsureMove, isEnsureMove
|
||||
result = c.genCopy(dest, ri, flags)
|
||||
dec c.inEnsureMove, isEnsureMove
|
||||
result.add p(ri, c, s, consumed)
|
||||
c.finishCopy(result, dest, isFromSink = false)
|
||||
of nkBracket:
|
||||
# array constructor
|
||||
if ri.len > 0 and isDangerousSeq(ri.typ):
|
||||
inc c.inEnsureMove, isEnsureMove
|
||||
result = c.genCopy(dest, ri, flags)
|
||||
dec c.inEnsureMove, isEnsureMove
|
||||
result.add p(ri, c, s, consumed)
|
||||
c.finishCopy(result, dest, isFromSink = false)
|
||||
else:
|
||||
result = c.genSink(dest, p(ri, c, s, consumed), flags)
|
||||
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
|
||||
of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
|
||||
result = c.genSink(dest, p(ri, c, s, consumed), flags)
|
||||
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
|
||||
of nkSym:
|
||||
if isSinkParam(ri.sym) and isLastRead(ri, c, s):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
let snk = c.genSink(dest, ri, flags)
|
||||
let snk = c.genSink(s, dest, ri, flags)
|
||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
|
||||
isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri):
|
||||
isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri) and
|
||||
not ({sfGlobal, sfPure} <= ri.sym.flags):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
let snk = c.genSink(dest, ri, flags)
|
||||
let snk = c.genSink(s, dest, ri, flags)
|
||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||
else:
|
||||
inc c.inEnsureMove, isEnsureMove
|
||||
result = c.genCopy(dest, ri, flags)
|
||||
dec c.inEnsureMove, isEnsureMove
|
||||
result.add p(ri, c, s, consumed)
|
||||
c.finishCopy(result, dest, isFromSink = false)
|
||||
of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv, nkCast:
|
||||
result = c.genSink(dest, p(ri, c, s, sinkArg), flags)
|
||||
result = c.genSink(s, dest, p(ri, c, s, sinkArg), flags)
|
||||
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
|
||||
template process(child, s): untyped = moveOrCopy(dest, child, c, s, flags)
|
||||
# We know the result will be a stmt so we use that fact to optimize
|
||||
@@ -1063,10 +1184,12 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
|
||||
if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s) and
|
||||
canBeMoved(c, dest.typ):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
let snk = c.genSink(dest, ri, flags)
|
||||
let snk = c.genSink(s, dest, ri, flags)
|
||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||
else:
|
||||
inc c.inEnsureMove, isEnsureMove
|
||||
result = c.genCopy(dest, ri, flags)
|
||||
dec c.inEnsureMove, isEnsureMove
|
||||
result.add p(ri, c, s, consumed)
|
||||
c.finishCopy(result, dest, isFromSink = false)
|
||||
|
||||
|
||||
@@ -65,11 +65,12 @@ Files: "compiler"
|
||||
Files: "doc"
|
||||
Files: "doc/html"
|
||||
Files: "tools"
|
||||
Files: "tools/nim-gdb.py"
|
||||
Files: "tools/debug/nim-gdb.py"
|
||||
Files: "nimpretty"
|
||||
Files: "testament"
|
||||
Files: "nimsuggest"
|
||||
Files: "nimsuggest/tests/*.nim"
|
||||
Files: "changelogs/*.md"
|
||||
|
||||
[Lib]
|
||||
Files: "lib"
|
||||
@@ -77,6 +78,7 @@ Files: "lib"
|
||||
[Other]
|
||||
Files: "examples"
|
||||
Files: "dist/nimble"
|
||||
Files: "dist/checksums"
|
||||
|
||||
Files: "tests"
|
||||
|
||||
@@ -90,6 +92,7 @@ Files: "bin/nimgrab.exe"
|
||||
Files: "bin/nimpretty.exe"
|
||||
Files: "bin/testament.exe"
|
||||
Files: "bin/nim-gdb.bat"
|
||||
Files: "bin/atlas.exe"
|
||||
|
||||
Files: "koch.exe"
|
||||
Files: "finish.exe"
|
||||
@@ -120,6 +123,7 @@ Files: "bin/nim"
|
||||
InstallScript: "yes"
|
||||
UninstallScript: "yes"
|
||||
Files: "bin/nim-gdb"
|
||||
Files: "build_all.sh"
|
||||
|
||||
|
||||
[InnoSetup]
|
||||
|
||||
@@ -33,26 +33,27 @@ template high*(t: typedesc[Int128]): Int128 = Max
|
||||
proc `$`*(a: Int128): string
|
||||
|
||||
proc toInt128*[T: SomeInteger | bool](arg: T): Int128 =
|
||||
when T is bool: result.sdata(0) = int32(arg)
|
||||
elif T is SomeUnsignedInt:
|
||||
when sizeof(arg) <= 4:
|
||||
result.udata[0] = uint32(arg)
|
||||
{.noSideEffect.}:
|
||||
when T is bool: result.sdata(0) = int32(arg)
|
||||
elif T is SomeUnsignedInt:
|
||||
when sizeof(arg) <= 4:
|
||||
result.udata[0] = uint32(arg)
|
||||
else:
|
||||
result.udata[0] = uint32(arg and T(0xffffffff))
|
||||
result.udata[1] = uint32(arg shr 32)
|
||||
elif sizeof(arg) <= 4:
|
||||
result.sdata(0) = int32(arg)
|
||||
if arg < 0: # sign extend
|
||||
result.sdata(1) = -1
|
||||
result.sdata(2) = -1
|
||||
result.sdata(3) = -1
|
||||
else:
|
||||
result.udata[0] = uint32(arg and T(0xffffffff))
|
||||
result.udata[1] = uint32(arg shr 32)
|
||||
elif sizeof(arg) <= 4:
|
||||
result.sdata(0) = int32(arg)
|
||||
if arg < 0: # sign extend
|
||||
result.sdata(1) = -1
|
||||
result.sdata(2) = -1
|
||||
result.sdata(3) = -1
|
||||
else:
|
||||
let tmp = int64(arg)
|
||||
result.udata[0] = uint32(tmp and 0xffffffff)
|
||||
result.sdata(1) = int32(tmp shr 32)
|
||||
if arg < 0: # sign extend
|
||||
result.sdata(2) = -1
|
||||
result.sdata(3) = -1
|
||||
let tmp = int64(arg)
|
||||
result.udata[0] = uint32(tmp and 0xffffffff)
|
||||
result.sdata(1) = int32(tmp shr 32)
|
||||
if arg < 0: # sign extend
|
||||
result.sdata(2) = -1
|
||||
result.sdata(3) = -1
|
||||
|
||||
template isNegative(arg: Int128): bool =
|
||||
arg.sdata(3) < 0
|
||||
@@ -170,6 +171,7 @@ proc addToHex*(result: var string; arg: Int128) =
|
||||
i -= 1
|
||||
|
||||
proc toHex*(arg: Int128): string =
|
||||
result = ""
|
||||
result.addToHex(arg)
|
||||
|
||||
proc inc*(a: var Int128, y: uint32 = 1) =
|
||||
@@ -329,8 +331,8 @@ proc `*`*(a: Int128, b: int32): Int128 =
|
||||
if b < 0:
|
||||
result = -result
|
||||
|
||||
proc `*=`*(a: var Int128, b: int32): Int128 =
|
||||
result = result * b
|
||||
proc `*=`(a: var Int128, b: int32) =
|
||||
a = a * b
|
||||
|
||||
proc makeInt128(high, low: uint64): Int128 =
|
||||
result.udata[0] = cast[uint32](low)
|
||||
@@ -359,6 +361,7 @@ proc `*=`*(a: var Int128, b: Int128) =
|
||||
import bitops
|
||||
|
||||
proc fastLog2*(a: Int128): int =
|
||||
result = 0
|
||||
if a.udata[3] != 0:
|
||||
return 96 + fastLog2(a.udata[3])
|
||||
if a.udata[2] != 0:
|
||||
|
||||
@@ -21,6 +21,7 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool
|
||||
proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
result = false
|
||||
for i in 0..<n.len:
|
||||
result = canAliasN(arg, n[i], marker)
|
||||
if result: return
|
||||
@@ -36,7 +37,7 @@ proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
|
||||
else: discard
|
||||
of nkSym:
|
||||
result = canAlias(arg, n.sym.typ, marker)
|
||||
else: discard
|
||||
else: result = false
|
||||
|
||||
proc canAlias(arg, ret: PType; marker: var IntSet): bool =
|
||||
if containsOrIncl(marker, ret.id):
|
||||
@@ -56,6 +57,7 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool =
|
||||
else:
|
||||
result = true
|
||||
of tyTuple:
|
||||
result = false
|
||||
for i in 0..<ret.len:
|
||||
result = canAlias(arg, ret[i], marker)
|
||||
if result: break
|
||||
@@ -72,6 +74,69 @@ proc isValueOnlyType(t: PType): bool =
|
||||
proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr, tyVar, tyLent}
|
||||
result = not types.searchTypeFor(t, wrap)
|
||||
|
||||
type
|
||||
SearchResult = enum
|
||||
NotFound, Abort, Found
|
||||
|
||||
proc containsDangerousRefAux(t: PType; marker: var IntSet): SearchResult
|
||||
|
||||
proc containsDangerousRefAux(n: PNode; marker: var IntSet): SearchResult =
|
||||
result = NotFound
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in 0..<n.len:
|
||||
result = containsDangerousRefAux(n[i], marker)
|
||||
if result == Found: return result
|
||||
of nkRecCase:
|
||||
assert(n[0].kind == nkSym)
|
||||
result = containsDangerousRefAux(n[0], marker)
|
||||
if result == Found: return result
|
||||
for i in 1..<n.len:
|
||||
case n[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
result = containsDangerousRefAux(lastSon(n[i]), marker)
|
||||
if result == Found: return result
|
||||
else: discard
|
||||
of nkSym:
|
||||
result = containsDangerousRefAux(n.sym.typ, marker)
|
||||
else: discard
|
||||
|
||||
proc containsDangerousRefAux(t: PType; marker: var IntSet): SearchResult =
|
||||
result = NotFound
|
||||
if t == nil: return result
|
||||
if containsOrIncl(marker, t.id): return result
|
||||
|
||||
if t.kind == tyRef or (t.kind == tyProc and t.callConv == ccClosure):
|
||||
result = Found
|
||||
elif tfSendable in t.flags:
|
||||
result = Abort
|
||||
else:
|
||||
# continue the type traversal:
|
||||
result = NotFound
|
||||
|
||||
if result != NotFound: return result
|
||||
case t.kind
|
||||
of tyObject:
|
||||
if t[0] != nil:
|
||||
result = containsDangerousRefAux(t[0].skipTypes(skipPtrs), marker)
|
||||
if result == NotFound: result = containsDangerousRefAux(t.n, marker)
|
||||
of tyGenericInst, tyDistinct, tyAlias, tySink:
|
||||
result = containsDangerousRefAux(lastSon(t), marker)
|
||||
of tyArray, tySet, tyTuple, tySequence:
|
||||
for i in 0..<t.len:
|
||||
result = containsDangerousRefAux(t[i], marker)
|
||||
if result == Found: return result
|
||||
else:
|
||||
discard
|
||||
|
||||
proc containsDangerousRef(t: PType): bool =
|
||||
# a `ref` type is "dangerous" if it occurs not within a type that is like `Isolated[T]`.
|
||||
# For example:
|
||||
# `ref int` # dangerous
|
||||
# `Isolated[ref int]` # not dangerous
|
||||
var marker = initIntSet()
|
||||
result = containsDangerousRefAux(t, marker) == Found
|
||||
|
||||
proc canAlias*(arg, ret: PType): bool =
|
||||
if isValueOnlyType(arg):
|
||||
# can alias only with addr(arg.x) and we don't care if it is not safe
|
||||
@@ -80,12 +145,15 @@ proc canAlias*(arg, ret: PType): bool =
|
||||
var marker = initIntSet()
|
||||
result = canAlias(arg, ret, marker)
|
||||
|
||||
const
|
||||
SomeVar = {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp}
|
||||
|
||||
proc containsVariable(n: PNode): bool =
|
||||
case n.kind
|
||||
of nodesToIgnoreSet:
|
||||
result = false
|
||||
of nkSym:
|
||||
result = n.sym.kind in {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp}
|
||||
result = n.sym.kind in SomeVar
|
||||
else:
|
||||
for ch in n:
|
||||
if containsVariable(ch): return true
|
||||
@@ -109,7 +177,7 @@ proc checkIsolate*(n: PNode): bool =
|
||||
discard "fine, it is isolated already"
|
||||
else:
|
||||
let argType = n[i].typ
|
||||
if argType != nil and not isCompileTimeOnly(argType) and containsTyRef(argType):
|
||||
if argType != nil and not isCompileTimeOnly(argType) and containsDangerousRef(argType):
|
||||
if argType.canAlias(n.typ) or containsVariable(n[i]):
|
||||
# bug #19013: Alias information is not enough, we need to check for potential
|
||||
# "overlaps". I claim the problem can only happen by reading again from a location
|
||||
@@ -118,10 +186,12 @@ proc checkIsolate*(n: PNode): bool =
|
||||
return false
|
||||
result = true
|
||||
of nkIfStmt, nkIfExpr:
|
||||
result = false
|
||||
for it in n:
|
||||
result = checkIsolate(it.lastSon)
|
||||
if not result: break
|
||||
of nkCaseStmt:
|
||||
result = false
|
||||
for i in 1..<n.len:
|
||||
result = checkIsolate(n[i].lastSon)
|
||||
if not result: break
|
||||
@@ -131,6 +201,7 @@ proc checkIsolate*(n: PNode): bool =
|
||||
result = checkIsolate(n[i].lastSon)
|
||||
if not result: break
|
||||
of nkBracket, nkTupleConstr, nkPar:
|
||||
result = false
|
||||
for it in n:
|
||||
result = checkIsolate(it)
|
||||
if not result: break
|
||||
@@ -143,6 +214,12 @@ proc checkIsolate*(n: PNode): bool =
|
||||
result = checkIsolate(n[^1])
|
||||
else:
|
||||
result = false
|
||||
of nkSym:
|
||||
result = true
|
||||
if n.sym.kind in SomeVar:
|
||||
let argType = n.typ
|
||||
if argType != nil and not isCompileTimeOnly(argType) and containsDangerousRef(argType):
|
||||
result = false
|
||||
else:
|
||||
# unanalysable expression:
|
||||
result = false
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -133,7 +133,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
|
||||
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
|
||||
[result, rope(ord(t.kind))]
|
||||
prepend(p.g.typeInfo, s)
|
||||
of tyVar, tyLent, tyRef, tyPtr, tySequence, tyRange, tySet:
|
||||
of tyVar, tyLent, tyRef, tyPtr, tySequence, tyRange, tySet, tyOpenArray:
|
||||
var s =
|
||||
"var $1 = {size: 0, kind: $2, base: null, node: null, finalizer: null};$n" %
|
||||
[result, rope(ord(t.kind))]
|
||||
|
||||
@@ -140,7 +140,7 @@ proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator)
|
||||
rawAddSon(result, intType)
|
||||
|
||||
proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym =
|
||||
result = newSym(skField, getIdent(g.cache, ":state"), nextSymId(idgen), iter, iter.info)
|
||||
result = newSym(skField, getIdent(g.cache, ":state"), idgen, iter, iter.info)
|
||||
result.typ = createClosureIterStateType(g, iter, idgen)
|
||||
|
||||
proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType =
|
||||
@@ -154,7 +154,7 @@ proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym
|
||||
result = iter.ast[resultPos].sym
|
||||
else:
|
||||
# XXX a bit hacky:
|
||||
result = newSym(skResult, getIdent(g.cache, ":result"), nextSymId(idgen), iter, iter.info, {})
|
||||
result = newSym(skResult, getIdent(g.cache, ":result"), idgen, iter, iter.info, {})
|
||||
result.typ = iter.typ[0]
|
||||
incl(result.flags, sfUsed)
|
||||
iter.ast.add newSymNode(result)
|
||||
@@ -187,6 +187,8 @@ proc getEnvParam*(routine: PSym): PSym =
|
||||
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
|
||||
result = hidden.sym
|
||||
assert sfFromGeneric in result.flags
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc interestingVar(s: PSym): bool {.inline.} =
|
||||
result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and
|
||||
@@ -199,6 +201,8 @@ proc illegalCapture(s: PSym): bool {.inline.} =
|
||||
proc isInnerProc(s: PSym): bool =
|
||||
if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and s.magic == mNone:
|
||||
result = s.skipGenericOwner.kind in routineKinds
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
|
||||
# Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
|
||||
@@ -267,7 +271,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN
|
||||
addUniqueField(it.typ.skipTypes({tyOwned})[0], hp, g.cache, idgen)
|
||||
env = indirectAccess(newSymNode(it), hp, hp.info)
|
||||
else:
|
||||
let e = newSym(skLet, iter.name, nextSymId(idgen), owner, n.info)
|
||||
let e = newSym(skLet, iter.name, idgen, owner, n.info)
|
||||
e.typ = hp.typ
|
||||
e.flags = hp.flags
|
||||
env = newSymNode(e)
|
||||
@@ -293,17 +297,19 @@ proc freshVarForClosureIter*(g: ModuleGraph; s: PSym; idgen: IdGenerator; owner:
|
||||
|
||||
proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
|
||||
let s = n.sym
|
||||
let isEnv = s.name.id == getIdent(g.cache, ":env").id
|
||||
if illegalCapture(s):
|
||||
localError(g.config, n.info,
|
||||
("'$1' is of type <$2> which cannot be captured as it would violate memory" &
|
||||
" safety, declared here: $3; using '-d:nimNoLentIterators' helps in some cases." &
|
||||
" Consider using a <ref $2> which can be captured.") %
|
||||
[s.name.s, typeToString(s.typ), g.config$s.info])
|
||||
elif not (owner.typ.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags):
|
||||
elif not (owner.typ.isClosure or owner.isNimcall and not owner.isExplicitCallConv or isEnv):
|
||||
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
|
||||
[s.name.s, owner.name.s, $owner.typ.callConv])
|
||||
incl(owner.typ.flags, tfCapturesEnv)
|
||||
owner.typ.callConv = ccClosure
|
||||
if not isEnv:
|
||||
owner.typ.callConv = ccClosure
|
||||
|
||||
type
|
||||
DetectionPass = object
|
||||
@@ -314,12 +320,10 @@ type
|
||||
idgen: IdGenerator
|
||||
|
||||
proc initDetectionPass(g: ModuleGraph; fn: PSym; idgen: IdGenerator): DetectionPass =
|
||||
result.processed = initIntSet()
|
||||
result.capturedVars = initIntSet()
|
||||
result.ownerToType = initTable[int, PType]()
|
||||
result.processed.incl(fn.id)
|
||||
result.graph = g
|
||||
result.idgen = idgen
|
||||
result = DetectionPass(processed: toIntSet([fn.id]),
|
||||
capturedVars: initIntSet(), ownerToType: initTable[int, PType](),
|
||||
graph: g, idgen: idgen
|
||||
)
|
||||
|
||||
discard """
|
||||
proc outer =
|
||||
@@ -380,7 +384,7 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
|
||||
if c.graph.config.selectedGC == gcDestructors and sfCursor notin upField.flags:
|
||||
localError(c.graph.config, dep.info, "internal error: up reference is not a .cursor")
|
||||
else:
|
||||
let result = newSym(skField, upIdent, nextSymId(c.idgen), obj.owner, obj.owner.info)
|
||||
let result = newSym(skField, upIdent, c.idgen, obj.owner, obj.owner.info)
|
||||
result.typ = fieldType
|
||||
when false:
|
||||
if c.graph.config.selectedGC == gcDestructors:
|
||||
@@ -418,7 +422,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
|
||||
let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner
|
||||
let t = c.getEnvTypeForOwner(owner, info)
|
||||
if cp == nil:
|
||||
cp = newSym(skParam, getIdent(c.graph.cache, paramName), nextSymId(c.idgen), fn, fn.info)
|
||||
cp = newSym(skParam, getIdent(c.graph.cache, paramName), c.idgen, fn, fn.info)
|
||||
incl(cp.flags, sfFromGeneric)
|
||||
cp.typ = t
|
||||
addHiddenParam(fn, cp)
|
||||
@@ -444,6 +448,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
let body = transformBody(c.graph, c.idgen, s, useCache)
|
||||
detectCapturedVars(body, s, c)
|
||||
let ow = s.skipGenericOwner
|
||||
let innerClosure = innerProc and s.typ.callConv == ccClosure and not s.isIterator
|
||||
let interested = interestingVar(s)
|
||||
if ow == owner:
|
||||
if owner.isIterator:
|
||||
c.somethingToDo = true
|
||||
@@ -458,7 +464,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
else:
|
||||
discard addField(obj, s, c.graph.cache, c.idgen)
|
||||
# direct or indirect dependency:
|
||||
elif (innerProc and not s.isIterator and s.typ.callConv == ccClosure) or interestingVar(s):
|
||||
elif innerClosure or interested:
|
||||
discard """
|
||||
proc outer() =
|
||||
var x: int
|
||||
@@ -522,9 +528,8 @@ type
|
||||
unownedEnvVars: Table[int, PNode] # only required for --newruntime
|
||||
|
||||
proc initLiftingPass(fn: PSym): LiftingPass =
|
||||
result.processed = initIntSet()
|
||||
result.processed.incl(fn.id)
|
||||
result.envVars = initTable[int, PNode]()
|
||||
result = LiftingPass(processed: toIntSet([fn.id]),
|
||||
envVars: initTable[int, PNode]())
|
||||
|
||||
proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
let s = n.sym
|
||||
@@ -545,7 +550,7 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
result = n
|
||||
|
||||
proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo; idgen: IdGenerator): PNode =
|
||||
var v = newSym(skVar, getIdent(cache, envName), nextSymId(idgen), owner, info)
|
||||
var v = newSym(skVar, getIdent(cache, envName), idgen, owner, info)
|
||||
v.flags = {sfShadowed, sfGeneratedOp}
|
||||
v.typ = typ
|
||||
result = newSymNode(v)
|
||||
@@ -569,7 +574,7 @@ proc setupEnvVar(owner: PSym; d: var DetectionPass;
|
||||
result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info, d.idgen)
|
||||
c.envVars[owner.id] = result
|
||||
if optOwnedRefs in d.graph.config.globalOptions:
|
||||
var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), nextSymId d.idgen, owner, info)
|
||||
var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), d.idgen, owner, info)
|
||||
v.flags = {sfShadowed, sfGeneratedOp}
|
||||
v.typ = envVarType
|
||||
c.unownedEnvVars[owner.id] = newSymNode(v)
|
||||
@@ -653,7 +658,7 @@ proc closureCreationForIter(iter: PNode;
|
||||
d: var DetectionPass; c: var LiftingPass): PNode =
|
||||
result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ)
|
||||
let owner = iter.sym.skipGenericOwner
|
||||
var v = newSym(skVar, getIdent(d.graph.cache, envName), nextSymId(d.idgen), owner, iter.info)
|
||||
var v = newSym(skVar, getIdent(d.graph.cache, envName), d.idgen, owner, iter.info)
|
||||
incl(v.flags, sfShadowed)
|
||||
v.typ = asOwnedRef(d, getHiddenParam(d.graph, iter.sym).typ)
|
||||
var vnode: PNode
|
||||
@@ -711,6 +716,7 @@ proc symToClosure(n: PNode; owner: PSym; d: var DetectionPass;
|
||||
# direct dependency, so use the outer's env variable:
|
||||
result = makeClosure(d.graph, d.idgen, s, setupEnvVar(owner, d, c, n.info), n.info)
|
||||
else:
|
||||
result = nil
|
||||
let available = getHiddenParam(d.graph, owner)
|
||||
let wanted = getHiddenParam(d.graph, s).typ
|
||||
# ugh: call through some other inner proc;
|
||||
@@ -859,7 +865,7 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType;
|
||||
fn.typ.callConv = oldCC
|
||||
|
||||
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
|
||||
idgen: IdGenerator): PNode =
|
||||
idgen: IdGenerator, force: bool): PNode =
|
||||
# XXX backend == backendJs does not suffice! The compiletime stuff needs
|
||||
# the transformation even when compiling to JS ...
|
||||
|
||||
@@ -868,7 +874,7 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
|
||||
|
||||
if body.kind == nkEmpty or (
|
||||
g.config.backend == backendJs and not isCompileTime) or
|
||||
fn.skipGenericOwner.kind != skModule:
|
||||
(fn.skipGenericOwner.kind != skModule and not force):
|
||||
|
||||
# ignore forward declaration:
|
||||
result = body
|
||||
@@ -936,14 +942,14 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
|
||||
result = newNodeI(nkStmtList, body.info)
|
||||
|
||||
# static binding?
|
||||
var env: PSym
|
||||
var env: PSym = nil
|
||||
let op = call[0]
|
||||
if op.kind == nkSym and op.sym.isIterator:
|
||||
# createClosure()
|
||||
let iter = op.sym
|
||||
|
||||
let hp = getHiddenParam(g, iter)
|
||||
env = newSym(skLet, iter.name, nextSymId(idgen), owner, body.info)
|
||||
env = newSym(skLet, iter.name, idgen, owner, body.info)
|
||||
env.typ = hp.typ
|
||||
env.flags = hp.flags
|
||||
|
||||
|
||||
@@ -510,7 +510,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
|
||||
rememberSplit(splitComma)
|
||||
wrSpace em
|
||||
of openPars:
|
||||
if tok.strongSpaceA and not em.endsInWhite and
|
||||
if tsLeading in tok.spacing and not em.endsInWhite and
|
||||
(not em.wasExportMarker or tok.tokType == tkCurlyDotLe):
|
||||
wrSpace em
|
||||
wr(em, $tok.tokType, ltSomeParLe)
|
||||
@@ -528,7 +528,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
|
||||
wr(em, $tok.tokType, ltOther)
|
||||
if not em.inquote: wrSpace(em)
|
||||
of tkOpr, tkDotDot:
|
||||
if em.inquote or (((not tok.strongSpaceA) and tok.strongSpaceB == tsNone) and
|
||||
if em.inquote or (tok.spacing == {} and
|
||||
tok.ident.s notin ["<", ">", "<=", ">=", "==", "!="]):
|
||||
# bug #9504: remember to not spacify a keyword:
|
||||
lastTokWasTerse = true
|
||||
@@ -538,7 +538,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
|
||||
if not em.endsInWhite: wrSpace(em)
|
||||
wr(em, tok.ident.s, ltOpr)
|
||||
template isUnary(tok): bool =
|
||||
tok.strongSpaceB == tsNone and tok.strongSpaceA
|
||||
tok.spacing == {tsLeading}
|
||||
|
||||
if not isUnary(tok):
|
||||
rememberSplit(splitBinary)
|
||||
|
||||
@@ -23,7 +23,6 @@ when defined(nimPreviewSlimSystem):
|
||||
import std/[assertions, formatfloat]
|
||||
|
||||
const
|
||||
MaxLineLength* = 80 # lines longer than this lead to a warning
|
||||
numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'}
|
||||
SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
|
||||
SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
|
||||
@@ -94,19 +93,18 @@ type
|
||||
base2, base8, base16
|
||||
|
||||
TokenSpacing* = enum
|
||||
tsNone, tsTrailing, tsEof
|
||||
tsLeading, tsTrailing, tsEof
|
||||
|
||||
Token* = object # a Nim token
|
||||
tokType*: TokType # the type of the token
|
||||
base*: NumericalBase # the numerical base; only valid for int
|
||||
# or float literals
|
||||
spacing*: set[TokenSpacing] # spaces around token
|
||||
indent*: int # the indentation; != -1 if the token has been
|
||||
# preceded with indentation
|
||||
ident*: PIdent # the parsed identifier
|
||||
iNumber*: BiggestInt # the parsed integer literal
|
||||
fNumber*: BiggestFloat # the parsed floating point literal
|
||||
base*: NumericalBase # the numerical base; only valid for int
|
||||
# or float literals
|
||||
strongSpaceA*: bool # leading spaces of an operator
|
||||
strongSpaceB*: TokenSpacing # trailing spaces of an operator
|
||||
literal*: string # the parsed (string) literal; and
|
||||
# documentation comments are here too
|
||||
line*, col*: int
|
||||
@@ -127,6 +125,8 @@ type
|
||||
cache*: IdentCache
|
||||
when defined(nimsuggest):
|
||||
previousToken: TLineInfo
|
||||
tokenEnd*: TLineInfo
|
||||
previousTokenEnd*: TLineInfo
|
||||
config*: ConfigRef
|
||||
|
||||
proc getLineInfo*(L: Lexer, tok: Token): TLineInfo {.inline.} =
|
||||
@@ -148,9 +148,11 @@ proc isNimIdentifier*(s: string): bool =
|
||||
var i = 1
|
||||
while i < sLen:
|
||||
if s[i] == '_': inc(i)
|
||||
if i < sLen and s[i] notin SymChars: return
|
||||
if i < sLen and s[i] notin SymChars: return false
|
||||
inc(i)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc `$`*(tok: Token): string =
|
||||
case tok.tokType
|
||||
@@ -176,7 +178,7 @@ proc initToken*(L: var Token) =
|
||||
L.tokType = tkInvalid
|
||||
L.iNumber = 0
|
||||
L.indent = 0
|
||||
L.strongSpaceA = false
|
||||
L.spacing = {}
|
||||
L.literal = ""
|
||||
L.fNumber = 0.0
|
||||
L.base = base10
|
||||
@@ -189,7 +191,7 @@ proc fillToken(L: var Token) =
|
||||
L.tokType = tkInvalid
|
||||
L.iNumber = 0
|
||||
L.indent = 0
|
||||
L.strongSpaceA = false
|
||||
L.spacing = {}
|
||||
setLen(L.literal, 0)
|
||||
L.fNumber = 0.0
|
||||
L.base = base10
|
||||
@@ -537,8 +539,8 @@ proc getNumber(L: var Lexer, result: var Token) =
|
||||
of floatTypes:
|
||||
result.fNumber = parseFloat(result.literal)
|
||||
of tkUInt64Lit, tkUIntLit:
|
||||
var iNumber: uint64
|
||||
var len: int
|
||||
var iNumber: uint64 = uint64(0)
|
||||
var len: int = 0
|
||||
try:
|
||||
len = parseBiggestUInt(result.literal, iNumber)
|
||||
except ValueError:
|
||||
@@ -547,8 +549,8 @@ proc getNumber(L: var Lexer, result: var Token) =
|
||||
raise newException(ValueError, "invalid integer: " & result.literal)
|
||||
result.iNumber = cast[int64](iNumber)
|
||||
else:
|
||||
var iNumber: int64
|
||||
var len: int
|
||||
var iNumber: int64 = int64(0)
|
||||
var len: int = 0
|
||||
try:
|
||||
len = parseBiggestInt(result.literal, iNumber)
|
||||
except ValueError:
|
||||
@@ -735,10 +737,6 @@ proc handleCRLF(L: var Lexer, pos: int): int =
|
||||
template registerLine =
|
||||
let col = L.getColNumber(pos)
|
||||
|
||||
when not defined(nimpretty):
|
||||
if col > MaxLineLength:
|
||||
lexMessagePos(L, hintLineTooLong, pos)
|
||||
|
||||
case L.buf[pos]
|
||||
of CR:
|
||||
registerLine()
|
||||
@@ -958,13 +956,15 @@ proc getOperator(L: var Lexer, tok: var Token) =
|
||||
tokenEnd(tok, pos-1)
|
||||
# advance pos but don't store it in L.bufpos so the next token (which might
|
||||
# be an operator too) gets the preceding spaces:
|
||||
tok.strongSpaceB = tsNone
|
||||
tok.spacing = tok.spacing - {tsTrailing, tsEof}
|
||||
var trailing = false
|
||||
while L.buf[pos] == ' ':
|
||||
inc pos
|
||||
if tok.strongSpaceB != tsTrailing:
|
||||
tok.strongSpaceB = tsTrailing
|
||||
trailing = true
|
||||
if L.buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
|
||||
tok.strongSpaceB = tsEof
|
||||
tok.spacing.incl(tsEof)
|
||||
elif trailing:
|
||||
tok.spacing.incl(tsTrailing)
|
||||
|
||||
proc getPrecedence*(tok: Token): int =
|
||||
## Calculates the precedence of the given token.
|
||||
@@ -1009,6 +1009,7 @@ proc getPrecedence*(tok: Token): int =
|
||||
else: return -10
|
||||
|
||||
proc newlineFollows*(L: Lexer): bool =
|
||||
result = false
|
||||
var pos = L.bufpos
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
@@ -1075,7 +1076,6 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
|
||||
when defined(nimpretty): tok.literal.add "\L"
|
||||
if isDoc:
|
||||
when not defined(nimpretty): tok.literal.add "\n"
|
||||
inc tok.iNumber
|
||||
var c = toStrip
|
||||
while L.buf[pos] == ' ' and c > 0:
|
||||
inc pos
|
||||
@@ -1094,8 +1094,6 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
|
||||
proc scanComment(L: var Lexer, tok: var Token) =
|
||||
var pos = L.bufpos
|
||||
tok.tokType = tkComment
|
||||
# iNumber contains the number of '\n' in the token
|
||||
tok.iNumber = 0
|
||||
assert L.buf[pos+1] == '#'
|
||||
when defined(nimpretty):
|
||||
tok.commentOffsetA = L.offsetBase + pos
|
||||
@@ -1138,7 +1136,6 @@ proc scanComment(L: var Lexer, tok: var Token) =
|
||||
while L.buf[pos] == ' ' and c > 0:
|
||||
inc pos
|
||||
dec c
|
||||
inc tok.iNumber
|
||||
else:
|
||||
if L.buf[pos] > ' ':
|
||||
L.indentAhead = indent
|
||||
@@ -1151,7 +1148,7 @@ proc scanComment(L: var Lexer, tok: var Token) =
|
||||
proc skip(L: var Lexer, tok: var Token) =
|
||||
var pos = L.bufpos
|
||||
tokenBegin(tok, pos)
|
||||
tok.strongSpaceA = false
|
||||
tok.spacing.excl(tsLeading)
|
||||
when defined(nimpretty):
|
||||
var hasComment = false
|
||||
var commentIndent = L.currLineIndent
|
||||
@@ -1162,8 +1159,7 @@ proc skip(L: var Lexer, tok: var Token) =
|
||||
case L.buf[pos]
|
||||
of ' ':
|
||||
inc(pos)
|
||||
if not tok.strongSpaceA:
|
||||
tok.strongSpaceA = true
|
||||
tok.spacing.incl(tsLeading)
|
||||
of '\t':
|
||||
if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead")
|
||||
inc(pos)
|
||||
@@ -1185,7 +1181,7 @@ proc skip(L: var Lexer, tok: var Token) =
|
||||
pos = L.bufpos
|
||||
else:
|
||||
break
|
||||
tok.strongSpaceA = false
|
||||
tok.spacing.excl(tsLeading)
|
||||
when defined(nimpretty):
|
||||
if L.buf[pos] == '#' and tok.line < 0: commentIndent = indent
|
||||
if L.buf[pos] > ' ' and (L.buf[pos] != '#' or L.buf[pos+1] == '#'):
|
||||
@@ -1224,6 +1220,10 @@ proc skip(L: var Lexer, tok: var Token) =
|
||||
proc rawGetTok*(L: var Lexer, tok: var Token) =
|
||||
template atTokenEnd() {.dirty.} =
|
||||
when defined(nimsuggest):
|
||||
L.previousTokenEnd.line = L.tokenEnd.line
|
||||
L.previousTokenEnd.col = L.tokenEnd.col
|
||||
L.tokenEnd.line = tok.line.uint16
|
||||
L.tokenEnd.col = getColNumber(L, L.bufpos).int16
|
||||
# we attach the cursor to the last *strong* token
|
||||
if tok.tokType notin weakTokens:
|
||||
L.previousToken.line = tok.line.uint16
|
||||
@@ -1397,8 +1397,9 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
|
||||
|
||||
proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
|
||||
cache: IdentCache; config: ConfigRef): int =
|
||||
var lex: Lexer
|
||||
var tok: Token
|
||||
result = 0
|
||||
var lex: Lexer = default(Lexer)
|
||||
var tok: Token = default(Token)
|
||||
initToken(tok)
|
||||
openLexer(lex, fileIdx, inputstream, cache, config)
|
||||
var prevToken = tkEof
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
|
||||
## This module implements lifting for type-bound operations
|
||||
## (``=sink``, ``=``, ``=destroy``, ``=deepCopy``).
|
||||
## (`=sink`, `=copy`, `=destroy`, `=deepCopy`, `=wasMoved`, `=dup`).
|
||||
|
||||
import modulegraphs, lineinfos, idents, ast, renderer, semdata,
|
||||
sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils
|
||||
@@ -34,6 +34,7 @@ type
|
||||
|
||||
template destructor*(t: PType): PSym = getAttachedOp(c.g, t, attachedDestructor)
|
||||
template assignment*(t: PType): PSym = getAttachedOp(c.g, t, attachedAsgn)
|
||||
template dup*(t: PType): PSym = getAttachedOp(c.g, t, attachedDup)
|
||||
template asink*(t: PType): PSym = getAttachedOp(c.g, t, attachedSink)
|
||||
|
||||
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode)
|
||||
@@ -49,9 +50,9 @@ proc at(a, i: PNode, elemType: PType): PNode =
|
||||
result[1] = i
|
||||
result.typ = elemType
|
||||
|
||||
proc destructorOverriden(g: ModuleGraph; t: PType): bool =
|
||||
proc destructorOverridden(g: ModuleGraph; t: PType): bool =
|
||||
let op = getAttachedOp(g, t, attachedDestructor)
|
||||
op != nil and sfOverriden in op.flags
|
||||
op != nil and sfOverridden in op.flags
|
||||
|
||||
proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
for i in 0..<t.len:
|
||||
@@ -82,12 +83,14 @@ proc genBuiltin(c: var TLiftCtx; magic: TMagic; name: string; i: PNode): PNode =
|
||||
result = genBuiltin(c.g, c.idgen, magic, name, i)
|
||||
|
||||
proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
|
||||
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink, attachedDup}:
|
||||
body.add newAsgnStmt(x, y)
|
||||
elif c.kind == attachedDestructor and c.addMemReset:
|
||||
let call = genBuiltin(c, mDefault, "default", x)
|
||||
call.typ = t
|
||||
body.add newAsgnStmt(x, call)
|
||||
elif c.kind == attachedWasMoved:
|
||||
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc genAddr(c: var TLiftCtx; x: PNode): PNode =
|
||||
if x.kind == nkHiddenDeref:
|
||||
@@ -137,14 +140,22 @@ proc genContainerOf(c: var TLiftCtx; objType: PType, field, x: PSym): PNode =
|
||||
proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
|
||||
var destroy = newNodeIT(nkCall, x.info, op.typ[0])
|
||||
destroy.add(newSymNode(op))
|
||||
destroy.add genAddr(c, x)
|
||||
if op.typ[1].kind != tyVar:
|
||||
destroy.add x
|
||||
else:
|
||||
destroy.add genAddr(c, x)
|
||||
if sfNeverRaises notin op.flags:
|
||||
c.canRaise = true
|
||||
if c.addMemReset:
|
||||
result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "wasMoved", x))
|
||||
result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "`=wasMoved`", x))
|
||||
else:
|
||||
result = destroy
|
||||
|
||||
proc genWasMovedCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
|
||||
result = newNodeIT(nkCall, x.info, op.typ[0])
|
||||
result.add(newSymNode(op))
|
||||
result.add genAddr(c, x)
|
||||
|
||||
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
@@ -152,7 +163,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
|
||||
let f = n.sym
|
||||
let b = if c.kind == attachedTrace: y else: y.dotField(f)
|
||||
if (sfCursor in f.flags and f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and
|
||||
c.g.config.selectedGC in {gcArc, gcOrc, gcHooks}) or
|
||||
c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
|
||||
enforceDefaultOp:
|
||||
defaultOp(c, f.typ, body, x.dotField(f), b)
|
||||
else:
|
||||
@@ -236,7 +247,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
|
||||
# for every field (dependent on dest.kind):
|
||||
# `=` dest.field, src.field
|
||||
# =destroy(blob)
|
||||
var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info)
|
||||
var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
|
||||
dummy.typ = y.typ
|
||||
if ccgIntroducedPtr(c.g.config, dummy, y.typ):
|
||||
# Because of potential aliasing when the src param is passed by ref, we need to check for equality here,
|
||||
@@ -245,7 +256,7 @@ proc fillBodyObjT(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, 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), nextSymId c.idgen, c.fn, c.info)
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
|
||||
temp.typ = x.typ
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
var v = newNodeI(nkVarSection, c.info)
|
||||
@@ -255,7 +266,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
|
||||
#body.add newAsgnStmt(blob, x)
|
||||
|
||||
var wasMovedCall = newNodeI(nkCall, c.info)
|
||||
wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "wasMoved", mWasMoved)))
|
||||
wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "`=wasMoved`", mWasMoved)))
|
||||
wasMovedCall.add x # mWasMoved does not take the address
|
||||
body.add wasMovedCall
|
||||
|
||||
@@ -276,7 +287,7 @@ proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
|
||||
result.typ = getSysType(g, info, tyBool)
|
||||
|
||||
proc getCycleParam(c: TLiftCtx): PNode =
|
||||
assert c.kind == attachedAsgn
|
||||
assert c.kind in {attachedAsgn, attachedDup}
|
||||
if c.fn.typ.len == 4:
|
||||
result = c.fn.typ.n.lastSon
|
||||
assert result.kind == nkSym
|
||||
@@ -291,7 +302,7 @@ proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
|
||||
result.add newSymNode(op)
|
||||
if sfNeverRaises notin op.flags:
|
||||
c.canRaise = true
|
||||
if op.typ.sons[1].kind == tyVar:
|
||||
if op.typ[1].kind == tyVar:
|
||||
result.add genAddr(c, x)
|
||||
else:
|
||||
result.add x
|
||||
@@ -315,6 +326,9 @@ proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
|
||||
proc newDeepCopyCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
|
||||
result = newAsgnStmt(x, newOpCall(c, op, y))
|
||||
|
||||
proc newDupCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
|
||||
result = newAsgnStmt(x, newOpCall(c, op, y))
|
||||
|
||||
proc usesBuiltinArc(t: PType): bool =
|
||||
proc wrap(t: PType): bool {.nimcall.} = ast.isGCedMem(t)
|
||||
result = types.searchTypeFor(t, wrap)
|
||||
@@ -339,9 +353,9 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
field: var PSym): bool =
|
||||
if optSeqDestructors in c.g.config.globalOptions:
|
||||
var op = field
|
||||
let destructorOverriden = destructorOverriden(c.g, t)
|
||||
let destructorOverridden = destructorOverridden(c.g, t)
|
||||
if op != nil and op != c.fn and
|
||||
(sfOverriden in op.flags or destructorOverriden):
|
||||
(sfOverridden in op.flags or destructorOverridden):
|
||||
if sfError in op.flags:
|
||||
incl c.fn.flags, sfError
|
||||
#else:
|
||||
@@ -349,10 +363,12 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
onUse(c.info, op)
|
||||
body.add newHookCall(c, op, x, y)
|
||||
result = true
|
||||
elif op == nil and destructorOverriden:
|
||||
elif op == nil and destructorOverridden:
|
||||
op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen)
|
||||
body.add newHookCall(c, op, x, y)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
elif tfHasAsgn in t.flags:
|
||||
var op: PSym
|
||||
if sameType(t, c.asgnForType):
|
||||
@@ -382,12 +398,14 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
assert op.ast[genericParamsPos].kind == nkEmpty
|
||||
body.add newHookCall(c, op, x, y)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
|
||||
let t = orig.skipTypes(abstractInst - {tyDistinct})
|
||||
var op = t.destructor
|
||||
|
||||
if op != nil and sfOverriden in op.flags:
|
||||
if op != nil and sfOverridden in op.flags:
|
||||
if op.ast.isGenericRoutine:
|
||||
# patch generic destructor:
|
||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||
@@ -410,7 +428,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
case c.kind
|
||||
of attachedDestructor:
|
||||
var op = t.destructor
|
||||
if op != nil and sfOverriden in op.flags:
|
||||
if op != nil and sfOverridden in op.flags:
|
||||
|
||||
if op.ast.isGenericRoutine:
|
||||
# patch generic destructor:
|
||||
@@ -421,10 +439,12 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
onUse(c.info, op)
|
||||
body.add destructorCall(c, op, x)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
#result = addDestructorCall(c, t, body, x)
|
||||
of attachedAsgn, attachedSink, attachedTrace:
|
||||
var op = getAttachedOp(c.g, t, c.kind)
|
||||
if op != nil and sfOverriden in op.flags:
|
||||
if op != nil and sfOverridden in op.flags:
|
||||
if op.ast.isGenericRoutine:
|
||||
# patch generic =trace:
|
||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||
@@ -441,9 +461,43 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
onUse(c.info, op)
|
||||
body.add newDeepCopyCall(c, op, x, y)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
of attachedWasMoved:
|
||||
var op = getAttachedOp(c.g, t, attachedWasMoved)
|
||||
if op != nil and sfOverridden in op.flags:
|
||||
|
||||
if op.ast.isGenericRoutine:
|
||||
# patch generic destructor:
|
||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||
setAttachedOp(c.g, c.idgen.module, t, attachedWasMoved, op)
|
||||
|
||||
#markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op)
|
||||
body.add genWasMovedCall(c, op, x)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
of attachedDup:
|
||||
var op = getAttachedOp(c.g, t, attachedDup)
|
||||
if op != nil and sfOverridden in op.flags:
|
||||
|
||||
if op.ast.isGenericRoutine:
|
||||
# patch generic destructor:
|
||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||
setAttachedOp(c.g, c.idgen.module, t, attachedDup, op)
|
||||
|
||||
#markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op)
|
||||
body.add newDupCall(c, op, x, y)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info)
|
||||
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.flags, sfFromGeneric)
|
||||
|
||||
@@ -453,7 +507,7 @@ proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
|
||||
body.add v
|
||||
|
||||
proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode =
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info)
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
|
||||
temp.typ = value.typ
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
|
||||
@@ -502,6 +556,9 @@ proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
|
||||
proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case c.kind
|
||||
of attachedDup:
|
||||
body.add setLenSeqCall(c, t, x, y)
|
||||
forallElements(c, t, body, x, y)
|
||||
of attachedAsgn, attachedDeepCopy:
|
||||
# we generate:
|
||||
# setLen(dest, y.len)
|
||||
@@ -521,17 +578,18 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
forallElements(c, t, body, x, y)
|
||||
body.add genBuiltin(c, mDestroy, "destroy", x)
|
||||
of attachedTrace:
|
||||
if canFormAcycle(t.elemType):
|
||||
if canFormAcycle(c.g, t.elemType):
|
||||
# follow all elements:
|
||||
forallElements(c, t, body, x, y)
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
createTypeBoundOps(c.g, c.c, t, body.info, c.idgen)
|
||||
# recursions are tricky, so we might need to forward the generated
|
||||
# operation here:
|
||||
var t = t
|
||||
if t.assignment == nil or t.destructor == nil:
|
||||
let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct})
|
||||
if t.assignment == nil or t.destructor == nil or t.dup == nil:
|
||||
let h = sighashes.hashType(t,c.g.config, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let canon = c.g.canonTypes.getOrDefault(h)
|
||||
if canon != nil: t = canon
|
||||
|
||||
@@ -556,15 +614,22 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
doAssert t.destructor != nil
|
||||
body.add destructorCall(c, t.destructor, x)
|
||||
of attachedTrace:
|
||||
if t.kind != tyString and canFormAcycle(t.elemType):
|
||||
if t.kind != tyString and canFormAcycle(c.g, t.elemType):
|
||||
let op = getAttachedOp(c.g, t, c.kind)
|
||||
if op == nil:
|
||||
return # protect from recursion
|
||||
body.add newHookCall(c, op, x, y)
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
of attachedDup:
|
||||
# XXX: replace these with assertions.
|
||||
let op = getAttachedOp(c.g, t, c.kind)
|
||||
if op == nil:
|
||||
return # protect from recursion
|
||||
body.add newDupCall(c, op, x, y)
|
||||
|
||||
proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case c.kind
|
||||
of attachedAsgn, attachedDeepCopy:
|
||||
of attachedAsgn, attachedDeepCopy, attachedDup:
|
||||
body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c, x), y)
|
||||
of attachedSink:
|
||||
let moveCall = genBuiltin(c, mMove, "move", x)
|
||||
@@ -576,10 +641,11 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.add genBuiltin(c, mDestroy, "destroy", x)
|
||||
of attachedTrace:
|
||||
discard "strings are atomic and have no inner elements that are to trace"
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc cyclicType*(t: PType): bool =
|
||||
proc cyclicType*(g: ModuleGraph, t: PType): bool =
|
||||
case t.kind
|
||||
of tyRef: result = types.canFormAcycle(t.lastSon)
|
||||
of tyRef: result = types.canFormAcycle(g, t.lastSon)
|
||||
of tyProc: result = t.callConv == ccClosure
|
||||
else: result = false
|
||||
|
||||
@@ -607,10 +673,15 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let elemType = t.lastSon
|
||||
|
||||
createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen)
|
||||
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType)
|
||||
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(c.g, elemType)
|
||||
|
||||
let isInheritableAcyclicRef = c.g.config.selectedGC == gcOrc and
|
||||
(not isPureObject(elemType)) and
|
||||
tfAcyclic in skipTypes(elemType, abstractInst+{tyOwned}-{tyTypeDesc}).flags
|
||||
# dynamic Acyclic refs need to use dyn decRef
|
||||
|
||||
let tmp =
|
||||
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
|
||||
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
|
||||
declareTempOf(c, body, x)
|
||||
else:
|
||||
x
|
||||
@@ -632,6 +703,8 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo)
|
||||
else:
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp)
|
||||
elif isInheritableAcyclicRef:
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLastDyn", c.info, x)
|
||||
else:
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x)
|
||||
cond.typ = getSysType(c.g, x.info, tyBool)
|
||||
@@ -667,6 +740,16 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
# If the ref is polymorphic we have to account for this
|
||||
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x, c.idgen), y)
|
||||
#echo "can follow ", elemType, " static ", isFinal(elemType)
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
of attachedDup:
|
||||
if isCyclic:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, y, callCodegenProc(c.g,
|
||||
"nimIncRefCyclic", c.info, y, getCycleParam(c)))
|
||||
else:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, y, callCodegenProc(c.g,
|
||||
"nimIncRef", c.info, y))
|
||||
|
||||
proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
## Closures are really like refs except they always use a virtual destructor
|
||||
@@ -676,7 +759,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
|
||||
let isCyclic = c.g.config.selectedGC == gcOrc
|
||||
let tmp =
|
||||
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
|
||||
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
|
||||
declareTempOf(c, body, xenv)
|
||||
else:
|
||||
xenv
|
||||
@@ -710,11 +793,21 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
|
||||
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)
|
||||
if isCyclic:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c)))
|
||||
else:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv))
|
||||
of attachedDestructor:
|
||||
body.add genIf(c, cond, actions)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace:
|
||||
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y)
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case c.kind
|
||||
@@ -727,6 +820,9 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y))
|
||||
body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDup:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y))
|
||||
of attachedDestructor:
|
||||
# it's better to prepend the destruction of weak refs in order to
|
||||
# prevent wrong "dangling refs exist" problems:
|
||||
@@ -739,6 +835,7 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.sons.insert(des, 0)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace: discard
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
var actions = newNodeI(nkStmtList, c.info)
|
||||
@@ -760,10 +857,13 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of attachedSink, attachedAsgn:
|
||||
body.add genIf(c, x, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDup:
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDestructor:
|
||||
body.add genIf(c, x, actions)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace: discard
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
if c.kind == attachedDeepCopy:
|
||||
@@ -775,7 +875,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
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, gcOrc}:
|
||||
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)
|
||||
case c.kind
|
||||
@@ -790,6 +890,11 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
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)
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
|
||||
of attachedDestructor:
|
||||
let des = genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
|
||||
if body.len == 0:
|
||||
@@ -798,6 +903,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.sons.insert(des, 0)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace: discard
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
|
||||
@@ -809,10 +915,13 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of attachedSink, attachedAsgn:
|
||||
body.add genIf(c, xx, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDup:
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDestructor:
|
||||
body.add genIf(c, xx, actions)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace: discard
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
|
||||
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case t.kind
|
||||
@@ -821,7 +930,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}:
|
||||
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):
|
||||
@@ -830,7 +939,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}:
|
||||
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
atomicClosureOp(c, t, body, x, y)
|
||||
else:
|
||||
closureOp(c, t, body, x, y)
|
||||
@@ -876,10 +985,25 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyObject:
|
||||
if not considerUserDefinedOp(c, t, body, x, y):
|
||||
if c.kind in {attachedAsgn, attachedSink} and t.sym != nil and sfImportc in t.sym.flags:
|
||||
body.add newAsgnStmt(x, y)
|
||||
if t.sym != nil and sfImportc in t.sym.flags:
|
||||
case c.kind
|
||||
of {attachedAsgn, attachedSink, attachedDup}:
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedWasMoved:
|
||||
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
|
||||
else:
|
||||
fillBodyObjT(c, t, body, x, y)
|
||||
else:
|
||||
fillBodyObjT(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):
|
||||
fillBody(c, t[0], body, x, y)
|
||||
@@ -900,7 +1024,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of tyOrdinal, tyRange, tyInferred,
|
||||
tyGenericInst, tyAlias, tySink:
|
||||
fillBody(c, lastSon(t), body, x, y)
|
||||
of tyConcept, tyIterable: doAssert false
|
||||
of tyConcept, tyIterable: raiseAssert "unreachable"
|
||||
|
||||
proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
|
||||
kind: TTypeAttachedOp; info: TLineInfo;
|
||||
@@ -912,15 +1036,56 @@ proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
|
||||
result = getAttachedOp(g, baseType, kind)
|
||||
setAttachedOp(g, idgen.module, typ, kind, result)
|
||||
|
||||
proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
|
||||
info: TLineInfo; idgen: IdGenerator): PSym =
|
||||
let procname = getIdent(g.cache, AttachedOpToStr[kind])
|
||||
result = newSym(skProc, procname, idgen, owner, info)
|
||||
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
|
||||
let src = newSym(skParam, getIdent(g.cache, "src"),
|
||||
idgen, result, info)
|
||||
res.typ = typ
|
||||
src.typ = typ
|
||||
|
||||
result.typ = newType(tyProc, nextTypeId idgen, owner)
|
||||
result.typ.n = newNodeI(nkFormalParams, info)
|
||||
rawAddSon(result.typ, res.typ)
|
||||
result.typ.n.add newNodeI(nkEffectList, info)
|
||||
|
||||
result.typ.addParam src
|
||||
|
||||
if g.config.selectedGC == gcOrc and
|
||||
cyclicType(g, typ.skipTypes(abstractInst)):
|
||||
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
|
||||
idgen, result, info)
|
||||
cycleParam.typ = getSysType(g, info, tyBool)
|
||||
result.typ.addParam cycleParam
|
||||
|
||||
var n = newNodeI(nkProcDef, info, bodyPos+2)
|
||||
for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
|
||||
n[namePos] = newSymNode(result)
|
||||
n[paramsPos] = result.typ.n
|
||||
n[bodyPos] = newNodeI(nkStmtList, info)
|
||||
n[resultPos] = newSymNode(res)
|
||||
result.ast = n
|
||||
incl result.flags, sfFromGeneric
|
||||
incl result.flags, sfGeneratedOp
|
||||
|
||||
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
|
||||
info: TLineInfo; idgen: IdGenerator): PSym =
|
||||
if kind == attachedDup:
|
||||
return symDupPrototype(g, typ, owner, kind, info, idgen)
|
||||
|
||||
let procname = getIdent(g.cache, AttachedOpToStr[kind])
|
||||
result = newSym(skProc, procname, nextSymId(idgen), owner, info)
|
||||
let dest = newSym(skParam, getIdent(g.cache, "dest"), nextSymId(idgen), result, info)
|
||||
result = newSym(skProc, procname, idgen, owner, info)
|
||||
let dest = newSym(skParam, getIdent(g.cache, "dest"), idgen, result, info)
|
||||
let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"),
|
||||
nextSymId(idgen), result, info)
|
||||
dest.typ = makeVarType(typ.owner, typ, idgen)
|
||||
idgen, result, info)
|
||||
|
||||
if kind == attachedDestructor and typ.kind in {tyRef, tyString, tySequence} and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
dest.typ = typ
|
||||
else:
|
||||
dest.typ = makeVarType(typ.owner, typ, idgen)
|
||||
|
||||
if kind == attachedTrace:
|
||||
src.typ = getSysType(g, info, tyPointer)
|
||||
else:
|
||||
@@ -928,13 +1093,13 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
|
||||
|
||||
result.typ = newProcType(info, nextTypeId(idgen), owner)
|
||||
result.typ.addParam dest
|
||||
if kind != attachedDestructor:
|
||||
if kind notin {attachedDestructor, attachedWasMoved}:
|
||||
result.typ.addParam src
|
||||
|
||||
if kind == attachedAsgn and g.config.selectedGC == gcOrc and
|
||||
cyclicType(typ.skipTypes(abstractInst)):
|
||||
cyclicType(g, typ.skipTypes(abstractInst)):
|
||||
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
|
||||
nextSymId(idgen), result, info)
|
||||
idgen, result, info)
|
||||
cycleParam.typ = getSysType(g, info, tyBool)
|
||||
result.typ.addParam cycleParam
|
||||
|
||||
@@ -946,6 +1111,9 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
|
||||
result.ast = n
|
||||
incl result.flags, sfFromGeneric
|
||||
incl result.flags, sfGeneratedOp
|
||||
if kind == attachedWasMoved:
|
||||
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)
|
||||
@@ -966,22 +1134,25 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType: typ, idgen: idgen,
|
||||
fn: result)
|
||||
|
||||
let dest = result.typ.n[1].sym
|
||||
let d = newDeref(newSymNode(dest))
|
||||
let src = if kind == attachedDestructor: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
|
||||
let dest = if kind == attachedDup: result.ast[resultPos].sym else: result.typ.n[1].sym
|
||||
let d = if result.typ[1].kind == tyVar: newDeref(newSymNode(dest)) else: newSymNode(dest)
|
||||
let src = case kind
|
||||
of {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
|
||||
of attachedDup: newSymNode(result.typ.n[1].sym)
|
||||
else: newSymNode(result.typ.n[2].sym)
|
||||
|
||||
# register this operation already:
|
||||
setAttachedOpPartial(g, idgen.module, typ, kind, result)
|
||||
|
||||
if kind == attachedSink and destructorOverriden(g, typ):
|
||||
if kind == attachedSink and destructorOverridden(g, typ):
|
||||
## compiler can use a combination of `=destroy` and memCopy for sink op
|
||||
dest.flags.incl sfCursor
|
||||
result.ast[bodyPos].add newOpCall(a, getAttachedOp(g, typ, attachedDestructor), d[0])
|
||||
let op = getAttachedOp(g, typ, attachedDestructor)
|
||||
result.ast[bodyPos].add newOpCall(a, op, if op.typ[1].kind == tyVar: d[0] else: d)
|
||||
result.ast[bodyPos].add newAsgnStmt(d, src)
|
||||
else:
|
||||
var tk: TTypeKind
|
||||
if g.config.selectedGC in {gcArc, gcOrc, gcHooks}:
|
||||
if g.config.selectedGC in {gcArc, gcOrc, gcHooks, gcAtomicArc}:
|
||||
tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind
|
||||
else:
|
||||
tk = tyNone # no special casing for strings and seqs
|
||||
@@ -992,7 +1163,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
fillStrOp(a, typ, result.ast[bodyPos], d, src)
|
||||
else:
|
||||
fillBody(a, typ, result.ast[bodyPos], d, src)
|
||||
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy} and not lacksMTypeField(typ):
|
||||
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy, attachedDup} and not lacksMTypeField(typ):
|
||||
# bug #19205: Do not forget to also copy the hidden type field:
|
||||
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
|
||||
|
||||
@@ -1011,7 +1182,7 @@ proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym,
|
||||
a.addMemReset = true
|
||||
let discrimantDest = result.typ.n[1].sym
|
||||
|
||||
let dst = newSym(skVar, getIdent(g.cache, "dest"), nextSymId(idgen), result, info)
|
||||
let dst = newSym(skVar, getIdent(g.cache, "dest"), idgen, result, info)
|
||||
dst.typ = makePtrType(typ.owner, typ, idgen)
|
||||
let dstSym = newSymNode(dst)
|
||||
let d = newDeref(dstSym)
|
||||
@@ -1037,7 +1208,7 @@ proc patchBody(g: ModuleGraph; c: PContext; n: PNode; info: TLineInfo; idgen: Id
|
||||
if op != nil:
|
||||
if op.ast.isGenericRoutine:
|
||||
internalError(g.config, info, "resolved destructor is generic")
|
||||
if op.magic == mDestroy:
|
||||
if op.magic == mDestroy and t.kind != tyString:
|
||||
internalError(g.config, info, "patching mDestroy with mDestroy?")
|
||||
n[0] = newSymNode(op)
|
||||
for x in n: patchBody(g, c, x, info, idgen)
|
||||
@@ -1047,13 +1218,7 @@ proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: I
|
||||
let op = getAttachedOp(g, t, kind)
|
||||
if op != nil and op.ast != nil and op.ast.isGenericRoutine:
|
||||
if t.typeInst != nil:
|
||||
var a: TLiftCtx
|
||||
a.info = info
|
||||
a.g = g
|
||||
a.kind = kind
|
||||
a.c = c
|
||||
a.idgen = idgen
|
||||
|
||||
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, idgen: idgen)
|
||||
let opInst = instantiateGeneric(a, op, t, t.typeInst)
|
||||
if opInst.ast != nil:
|
||||
patchBody(g, c, opInst.ast, info, a.idgen)
|
||||
@@ -1075,7 +1240,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
|
||||
let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
if isEmptyContainer(skipped) or skipped.kind == tyStatic: return
|
||||
|
||||
let h = sighashes.hashType(skipped, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let h = sighashes.hashType(skipped, g.config, {CoType, CoConsiderOwned, CoDistinct})
|
||||
var canon = g.canonTypes.getOrDefault(h)
|
||||
if canon == nil:
|
||||
g.canonTypes[h] = skipped
|
||||
@@ -1096,15 +1261,15 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
|
||||
# bug #15122: We need to produce all prototypes before entering the
|
||||
# mind boggling recursion. Hacks like these imply we should rewrite
|
||||
# this module.
|
||||
var generics: array[attachedDestructor..attachedTrace, bool]
|
||||
for k in attachedDestructor..lastAttached:
|
||||
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]:
|
||||
setAttachedOp(g, idgen.module, canon, k,
|
||||
symPrototype(g, canon, canon.owner, k, info, idgen))
|
||||
|
||||
# we generate the destructor first so that other operators can depend on it:
|
||||
for k in attachedDestructor..lastAttached:
|
||||
for k in attachedWasMoved..lastAttached:
|
||||
if not generics[k]:
|
||||
discard produceSym(g, c, canon, k, info, idgen)
|
||||
else:
|
||||
|
||||
@@ -49,6 +49,7 @@ proc liftLocals(n: PNode; i: int; c: var Ctx) =
|
||||
liftLocals(it, i, c)
|
||||
|
||||
proc lookupParam(params, dest: PNode): PSym =
|
||||
result = nil
|
||||
if dest.kind != nkIdent: return nil
|
||||
for i in 1..<params.len:
|
||||
if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module contains the ``TMsgKind`` enum as well as the
|
||||
## ``TLineInfo`` object.
|
||||
## This module contains the `TMsgKind` enum as well as the
|
||||
## `TLineInfo` object.
|
||||
|
||||
import ropes, tables, pathutils, hashes
|
||||
|
||||
@@ -44,6 +44,7 @@ type
|
||||
errRstSandboxedDirective,
|
||||
errProveInit, # deadcode
|
||||
errGenerated,
|
||||
errFailedMove,
|
||||
errUser,
|
||||
# warnings
|
||||
warnCannotOpenFile = "CannotOpenFile", warnOctalEscape = "OctalEscape",
|
||||
@@ -57,6 +58,7 @@ type
|
||||
warnRstBrokenLink = "BrokenLink",
|
||||
warnRstLanguageXNotSupported = "LanguageXNotSupported",
|
||||
warnRstFieldXNotSupported = "FieldXNotSupported",
|
||||
warnRstUnusedImportdoc = "UnusedImportdoc",
|
||||
warnRstStyle = "warnRstStyle",
|
||||
warnCommentXIgnored = "CommentXIgnored",
|
||||
warnTypelessParam = "TypelessParam",
|
||||
@@ -82,14 +84,17 @@ type
|
||||
warnCstringConv = "CStringConv",
|
||||
warnPtrToCstringConv = "PtrToCstringConv",
|
||||
warnEffect = "Effect",
|
||||
warnCastSizes = "CastSizes"
|
||||
warnTemplateRedefinition = "TemplateRedefinition",
|
||||
warnCastSizes = "CastSizes", # deadcode
|
||||
warnAboveMaxSizeSet = "AboveMaxSizeSet",
|
||||
warnImplicitTemplateRedefinition = "ImplicitTemplateRedefinition",
|
||||
warnUnnamedBreak = "UnnamedBreak",
|
||||
warnStmtListLambda = "StmtListLambda",
|
||||
warnBareExcept = "BareExcept",
|
||||
warnImplicitDefaultValue = "ImplicitDefaultValue",
|
||||
warnUser = "User",
|
||||
# hints
|
||||
hintSuccess = "Success", hintSuccessX = "SuccessX",
|
||||
hintCC = "CC",
|
||||
hintLineTooLong = "LineTooLong",
|
||||
hintXDeclaredButNotUsed = "XDeclaredButNotUsed", hintDuplicateModuleImport = "DuplicateModuleImport",
|
||||
hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded",
|
||||
hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX",
|
||||
@@ -124,6 +129,7 @@ const
|
||||
errRstSandboxedDirective: "disabled directive: '$1'",
|
||||
errProveInit: "Cannot prove that '$1' is initialized.", # deadcode
|
||||
errGenerated: "$1",
|
||||
errFailedMove: "$1",
|
||||
errUser: "$1",
|
||||
warnCannotOpenFile: "cannot open '$1'",
|
||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
|
||||
@@ -140,6 +146,7 @@ const
|
||||
warnRstBrokenLink: "broken link '$1'",
|
||||
warnRstLanguageXNotSupported: "language '$1' not supported",
|
||||
warnRstFieldXNotSupported: "field '$1' not supported",
|
||||
warnRstUnusedImportdoc: "importdoc for '$1' is not used",
|
||||
warnRstStyle: "RST style: $1",
|
||||
warnCommentXIgnored: "comment '$1' ignored",
|
||||
warnTypelessParam: "", # deadcode
|
||||
@@ -180,15 +187,18 @@ const
|
||||
warnCstringConv: "$1",
|
||||
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future",
|
||||
warnEffect: "$1",
|
||||
warnCastSizes: "$1",
|
||||
warnTemplateRedefinition: "template '$1' is implicitly redefined, consider adding an explicit .redefine pragma",
|
||||
warnCastSizes: "$1", # deadcode
|
||||
warnAboveMaxSizeSet: "$1",
|
||||
warnImplicitTemplateRedefinition: "template '$1' is implicitly redefined; this is deprecated, add an explicit .redefine pragma",
|
||||
warnUnnamedBreak: "Using an unnamed break in a block is deprecated; Use a named block with a named break instead",
|
||||
warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead",
|
||||
warnBareExcept: "$1",
|
||||
warnImplicitDefaultValue: "$1",
|
||||
warnUser: "$1",
|
||||
hintSuccess: "operation successful: $#",
|
||||
# keep in sync with `testament.isSuccess`
|
||||
hintSuccessX: "$build\n$loc lines; ${sec}s; $mem; proj: $project; out: $output",
|
||||
hintCC: "CC: $1",
|
||||
hintLineTooLong: "line too long",
|
||||
hintXDeclaredButNotUsed: "'$1' is declared but not used",
|
||||
hintDuplicateModuleImport: "$1",
|
||||
hintXCannotRaiseY: "$1",
|
||||
@@ -238,7 +248,8 @@ type
|
||||
TNoteKinds* = set[TNoteKind]
|
||||
|
||||
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv}
|
||||
result = default(array[0..3, TNoteKinds])
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept}
|
||||
result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
|
||||
result[1] = result[2] - {warnProveField, warnProveIndex,
|
||||
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
|
||||
@@ -269,7 +280,7 @@ type
|
||||
# and parsed; usually "" but is used
|
||||
# for 'nimsuggest'
|
||||
hash*: string # the checksum of the file
|
||||
dirty*: bool # for 'nimfix' / 'nimpretty' like tooling
|
||||
dirty*: bool # for 'nimpretty' like tooling
|
||||
when defined(nimpretty):
|
||||
fullContent*: string
|
||||
FileIndex* = distinct int32
|
||||
@@ -300,7 +311,7 @@ proc `==`*(a, b: FileIndex): bool {.borrow.}
|
||||
proc hash*(i: TLineInfo): Hash =
|
||||
hash (i.line.int, i.col.int, i.fileIndex.int)
|
||||
|
||||
proc raiseRecoverableError*(msg: string) {.noinline.} =
|
||||
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
|
||||
raise newException(ERecoverableError, msg)
|
||||
|
||||
const
|
||||
@@ -331,9 +342,8 @@ type
|
||||
|
||||
|
||||
proc initMsgConfig*(): MsgConfig =
|
||||
result.msgContext = @[]
|
||||
result.lastError = unknownLineInfo
|
||||
result.filenameToIndexTbl = initTable[string, FileIndex]()
|
||||
result.fileInfos = @[]
|
||||
result.errorOutputs = {eStdOut, eStdErr}
|
||||
result = MsgConfig(msgContext: @[], lastError: unknownLineInfo,
|
||||
filenameToIndexTbl: initTable[string, FileIndex](),
|
||||
fileInfos: @[], errorOutputs: {eStdOut, eStdErr}
|
||||
)
|
||||
result.filenameToIndexTbl["???"] = FileIndex(-1)
|
||||
|
||||
@@ -19,10 +19,12 @@ const
|
||||
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
|
||||
|
||||
proc identLen*(line: string, start: int): int =
|
||||
result = 0
|
||||
while start+result < line.len and line[start+result] in Letters:
|
||||
inc result
|
||||
|
||||
proc `=~`(s: string, a: openArray[string]): bool =
|
||||
result = false
|
||||
for x in a:
|
||||
if s.startsWith(x): return true
|
||||
|
||||
@@ -95,7 +97,7 @@ template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind)
|
||||
if optStyleCheck in ctx.config.options and # ignore if styleChecks are off
|
||||
{optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # check only if hint/error is enabled
|
||||
hintName in ctx.config.notes and # ignore if name checks are not requested
|
||||
ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages
|
||||
ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
|
||||
optStyleUsages notin ctx.config.globalOptions and # ignore if requested to only check name usage
|
||||
sym.kind != skResult and # ignore `result`
|
||||
sym.kind != skTemp and # ignore temporary variables created by the compiler
|
||||
@@ -136,7 +138,7 @@ template styleCheckUse*(ctx: PContext; info: TLineInfo; sym: PSym) =
|
||||
## Check symbol uses match their definition's style.
|
||||
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
|
||||
hintName in ctx.config.notes and # ignore if name checks are not requested
|
||||
ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages
|
||||
ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
|
||||
sym.kind != skTemp and # ignore temporary variables created by the compiler
|
||||
sym.name.s[0] in Letters and # ignore operators TODO: what about unicode symbols???
|
||||
sfAnon notin sym.flags: # ignore temporary variables created by the compiler
|
||||
@@ -147,6 +149,10 @@ proc checkPragmaUseImpl(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragm
|
||||
if pragmaName != wanted:
|
||||
lintReport(conf, info, wanted, pragmaName)
|
||||
|
||||
template checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) =
|
||||
if {optStyleHint, optStyleError} * conf.globalOptions != {}:
|
||||
checkPragmaUseImpl(conf, info, w, pragmaName)
|
||||
template checkPragmaUse*(ctx: PContext; info: TLineInfo; w: TSpecialWord; pragmaName: string, sym: PSym) =
|
||||
## Check builtin pragma uses match their definition's style.
|
||||
## Note: This only applies to builtin pragmas, not user pragmas.
|
||||
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
|
||||
hintName in ctx.config.notes and # ignore if name checks are not requested
|
||||
(sym != nil and ctx.config.belongsToProjectPackage(sym)): # ignore foreign packages
|
||||
checkPragmaUseImpl(ctx.config, info, w, pragmaName)
|
||||
|
||||
@@ -40,33 +40,22 @@ type
|
||||
|
||||
PLLStream* = ref TLLStream
|
||||
|
||||
proc llStreamOpen*(data: string): PLLStream =
|
||||
new(result)
|
||||
result.s = data
|
||||
result.kind = llsString
|
||||
proc llStreamOpen*(data: sink string): PLLStream =
|
||||
PLLStream(kind: llsString, s: data)
|
||||
|
||||
proc llStreamOpen*(f: File): PLLStream =
|
||||
new(result)
|
||||
result.f = f
|
||||
result.kind = llsFile
|
||||
PLLStream(kind: llsFile, f: f)
|
||||
|
||||
proc llStreamOpen*(filename: AbsoluteFile, mode: FileMode): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsFile
|
||||
result = PLLStream(kind: llsFile)
|
||||
if not open(result.f, filename.string, mode): result = nil
|
||||
|
||||
proc llStreamOpen*(): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsNone
|
||||
PLLStream(kind: llsNone)
|
||||
|
||||
proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int
|
||||
proc llStreamOpenStdIn*(r: TLLRepl = llReadFromStdin, onPrompt: OnPrompt = nil): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsStdIn
|
||||
result.s = ""
|
||||
result.lineOffset = -1
|
||||
result.repl = r
|
||||
result.onPrompt = onPrompt
|
||||
PLLStream(kind: llsStdIn, s: "", lineOffset: -1, repl: r, onPrompt: onPrompt)
|
||||
|
||||
proc llStreamClose*(s: PLLStream) =
|
||||
case s.kind
|
||||
@@ -89,6 +78,8 @@ proc endsWith*(x: string, s: set[char]): bool =
|
||||
while i >= 0 and x[i] == ' ': dec(i)
|
||||
if i >= 0 and x[i] in s:
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
const
|
||||
LineContinuationOprs = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^',
|
||||
@@ -104,6 +95,7 @@ proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
|
||||
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs))
|
||||
|
||||
proc countTriples(s: string): int =
|
||||
result = 0
|
||||
var i = 0
|
||||
while i+2 < s.len:
|
||||
if s[i] == '"' and s[i+1] == '"' and s[i+2] == '"':
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
#
|
||||
|
||||
# This module implements lookup helpers.
|
||||
import std/[algorithm, strutils]
|
||||
import std/[algorithm, strutils, tables]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, idents, semdata, types, msgs, options,
|
||||
renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs
|
||||
renderer, lineinfos, modulegraphs, astmsgs, sets, wordrecg
|
||||
|
||||
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
|
||||
|
||||
@@ -72,7 +72,7 @@ proc addUniqueSym*(scope: PScope, s: PSym): PSym =
|
||||
|
||||
proc openScope*(c: PContext): PScope {.discardable.} =
|
||||
result = PScope(parent: c.currentScope,
|
||||
symbols: newStrTable(),
|
||||
symbols: initStrTable(),
|
||||
depthLevel: c.scopeDepth + 1)
|
||||
c.currentScope = result
|
||||
|
||||
@@ -94,17 +94,6 @@ iterator localScopesFrom*(c: PContext; scope: PScope): PScope =
|
||||
if s == c.topLevelScope: break
|
||||
yield s
|
||||
|
||||
proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym =
|
||||
if s == nil or s.kind != skAlias:
|
||||
result = s
|
||||
else:
|
||||
result = s.owner
|
||||
if conf.cmd == cmdNimfix:
|
||||
prettybase.replaceDeprecated(conf, n.info, s, result)
|
||||
else:
|
||||
message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " &
|
||||
s.name.s & " is deprecated")
|
||||
|
||||
proc isShadowScope*(s: PScope): bool {.inline.} =
|
||||
s.parent != nil and s.parent.depthLevel == s.depthLevel
|
||||
|
||||
@@ -170,6 +159,7 @@ iterator allSyms*(c: PContext): (PSym, int, bool) =
|
||||
# really iterate over all symbols in all the scopes. This is expensive
|
||||
# and only used by suggest.nim.
|
||||
var isLocal = true
|
||||
|
||||
var scopeN = 0
|
||||
for scope in allScopes(c.currentScope):
|
||||
if scope == c.topLevelScope: isLocal = false
|
||||
@@ -184,6 +174,17 @@ iterator allSyms*(c: PContext): (PSym, int, bool) =
|
||||
assert s != nil
|
||||
yield (s, scopeN, isLocal)
|
||||
|
||||
iterator uniqueSyms*(c: PContext): (PSym, int, bool) =
|
||||
## Like [allSyms] except only returns unique symbols (Uniqueness determined by line + name)
|
||||
# Track seen symbols so we don't duplicate them.
|
||||
# The int is for the symbols name, and line info is
|
||||
# to be able to tell apart symbols with same name but on different lines
|
||||
var seen = initHashSet[(TLineInfo, int)]()
|
||||
for res in allSyms(c):
|
||||
if not seen.containsOrIncl((res[0].info, res[0].name.id)):
|
||||
yield res
|
||||
|
||||
|
||||
proc someSymFromImportTable*(c: PContext; name: PIdent; ambiguous: var bool): PSym =
|
||||
var marked = initIntSet()
|
||||
var symSet = OverloadableSyms
|
||||
@@ -216,6 +217,23 @@ proc debugScopes*(c: PContext; limit=0, max = int.high) {.deprecated.} =
|
||||
if i == limit: return
|
||||
inc i
|
||||
|
||||
proc searchInScopesAllCandidatesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
|
||||
result = @[]
|
||||
for scope in allScopes(c.currentScope):
|
||||
var ti: TIdentIter
|
||||
var candidate = initIdentIter(ti, scope.symbols, s)
|
||||
while candidate != nil:
|
||||
if candidate.kind in filter:
|
||||
result.add candidate
|
||||
candidate = nextIdentIter(ti, scope.symbols)
|
||||
|
||||
if result.len == 0:
|
||||
var marked = initIntSet()
|
||||
for im in c.imports.mitems:
|
||||
for s in symbols(im, marked, s, c.graph):
|
||||
if s.kind in filter:
|
||||
result.add s
|
||||
|
||||
proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
|
||||
result = @[]
|
||||
block outer:
|
||||
@@ -245,7 +263,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
|
||||
considerQuotedIdent(c, m)
|
||||
else:
|
||||
getIdent(c.cache, "err:" & renderTree(m))
|
||||
result = newSym(skError, ident, nextSymId(c.idgen), getCurrOwner(c), n.info, {})
|
||||
result = newSym(skError, ident, c.idgen, getCurrOwner(c), n.info, {})
|
||||
result.typ = errorType(c)
|
||||
incl(result.flags, sfDiscardable)
|
||||
# pretend it's from the top level scope to prevent cascading errors:
|
||||
@@ -280,7 +298,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
|
||||
var it: TTabIter
|
||||
var s = initTabIter(it, scope.symbols)
|
||||
var missingImpls = 0
|
||||
var unusedSyms: seq[tuple[sym: PSym, key: string]]
|
||||
var unusedSyms: seq[tuple[sym: PSym, key: string]] = @[]
|
||||
while s != nil:
|
||||
if sfForward in s.flags and s.kind notin {skType, skModule}:
|
||||
# too many 'implementation of X' errors are annoying
|
||||
@@ -311,15 +329,18 @@ proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string;
|
||||
# xxx pending bootstrap >= 1.4, replace all those overloads with a single one:
|
||||
# proc addDecl*(c: PContext, sym: PSym, info = sym.info, scope = c.currentScope) {.inline.} =
|
||||
proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) =
|
||||
if sym.name.id == ord(wUnderscore): return
|
||||
let conflict = scope.addUniqueSym(sym)
|
||||
if conflict != nil:
|
||||
if sym.kind == skModule and conflict.kind == skModule and sym.owner == conflict.owner:
|
||||
if sym.kind == skModule and conflict.kind == skModule:
|
||||
# e.g.: import foo; import foo
|
||||
# xxx we could refine this by issuing a different hint for the case
|
||||
# where a duplicate import happens inside an include.
|
||||
localError(c.config, info, hintDuplicateModuleImport,
|
||||
"duplicate import of '$1'; previous import here: $2" %
|
||||
[sym.name.s, c.config $ conflict.info])
|
||||
if c.importModuleMap[sym.id] == c.importModuleMap[conflict.id]:
|
||||
#only hints if the conflict is the actual module not just a shared name
|
||||
localError(c.config, info, hintDuplicateModuleImport,
|
||||
"duplicate import of '$1'; previous import here: $2" %
|
||||
[sym.name.s, c.config $ conflict.info])
|
||||
else:
|
||||
wrongRedefinition(c, info, sym.name.s, conflict.info, errGenerated)
|
||||
|
||||
@@ -365,11 +386,12 @@ proc addOverloadableSymAt*(c: PContext; scope: PScope, fn: PSym) =
|
||||
if fn.kind notin OverloadableSyms:
|
||||
internalError(c.config, fn.info, "addOverloadableSymAt")
|
||||
return
|
||||
let check = strTableGet(scope.symbols, fn.name)
|
||||
if check != nil and check.kind notin OverloadableSyms:
|
||||
wrongRedefinition(c, fn.info, fn.name.s, check.info)
|
||||
else:
|
||||
scope.addSym(fn)
|
||||
if fn.name.id != ord(wUnderscore):
|
||||
let check = strTableGet(scope.symbols, fn.name)
|
||||
if check != nil and check.kind notin OverloadableSyms:
|
||||
wrongRedefinition(c, fn.info, fn.name.s, check.info)
|
||||
else:
|
||||
scope.addSym(fn)
|
||||
|
||||
proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||
## adds an overloadable symbol on the scope and the interface if appropriate
|
||||
@@ -382,7 +404,7 @@ proc openShadowScope*(c: PContext) =
|
||||
## opens a shadow scope, just like any other scope except the depth is the
|
||||
## same as the parent -- see `isShadowScope`.
|
||||
c.currentScope = PScope(parent: c.currentScope,
|
||||
symbols: newStrTable(),
|
||||
symbols: initStrTable(),
|
||||
depthLevel: c.scopeDepth)
|
||||
|
||||
proc closeShadowScope*(c: PContext) =
|
||||
@@ -406,13 +428,6 @@ proc mergeShadowScope*(c: PContext) =
|
||||
else:
|
||||
c.addInterfaceDecl(sym)
|
||||
|
||||
when false:
|
||||
# `nimfix` used to call `altSpelling` and prettybase.replaceDeprecated(n.info, ident, alt)
|
||||
proc altSpelling(c: PContext, x: PIdent): PIdent =
|
||||
case x.s[0]
|
||||
of 'A'..'Z': result = getIdent(c.cache, toLowerAscii(x.s[0]) & x.s.substr(1))
|
||||
of 'a'..'z': result = getIdent(c.cache, toLowerAscii(x.s[0]) & x.s.substr(1))
|
||||
else: result = x
|
||||
|
||||
import std/editdistance, heapqueue
|
||||
|
||||
@@ -422,7 +437,7 @@ type SpellCandidate = object
|
||||
msg: string
|
||||
sym: PSym
|
||||
|
||||
template toOrderTup(a: SpellCandidate): auto =
|
||||
template toOrderTup(a: SpellCandidate): (int, int, string) =
|
||||
# `dist` is first, to favor nearby matches
|
||||
# `depth` is next, to favor nearby enclosing scopes among ties
|
||||
# `sym.name.s` is last, to make the list ordered and deterministic among ties
|
||||
@@ -443,36 +458,37 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) =
|
||||
for (sym, depth, isLocal) in allSyms(c):
|
||||
let depth = -depth - 1
|
||||
let dist = editDistance(name0, sym.name.s.nimIdentNormalize)
|
||||
var msg: string
|
||||
var msg: string = ""
|
||||
msg.add "\n ($1, $2): '$3'" % [$dist, $depth, sym.name.s]
|
||||
addDeclaredLoc(msg, c.config, sym) # `msg` needed for deterministic ordering.
|
||||
list.push SpellCandidate(dist: dist, depth: depth, msg: msg, sym: sym)
|
||||
|
||||
if list.len == 0: return
|
||||
let e0 = list[0]
|
||||
var count = 0
|
||||
var
|
||||
count = 0
|
||||
last: PIdent = nil
|
||||
while true:
|
||||
# pending https://github.com/timotheecour/Nim/issues/373 use more efficient `itemsSorted`.
|
||||
if list.len == 0: break
|
||||
let e = list.pop()
|
||||
if c.config.spellSuggestMax == spellSuggestSecretSauce:
|
||||
const
|
||||
smallThres = 2
|
||||
maxCountForSmall = 4
|
||||
# avoids ton of operator matches when mis-matching short symbols such as `i`
|
||||
# other heuristics could be devised, such as only suggesting operators if `name0`
|
||||
# is an operator (likewise with non-operators).
|
||||
if e.dist > e0.dist or (name0.len <= smallThres and count >= maxCountForSmall): break
|
||||
minLengthForSuggestion = 4
|
||||
maxCount = 3 # avoids ton of matches; three counts for equal distances
|
||||
if e.dist > e0.dist or count >= maxCount or name0.len < minLengthForSuggestion: break
|
||||
elif count >= c.config.spellSuggestMax: break
|
||||
if count == 0:
|
||||
result.add "\ncandidates (edit distance, scope distance); see '--spellSuggest': "
|
||||
result.add e.msg
|
||||
count.inc
|
||||
if e.sym.name != last:
|
||||
result.add e.msg
|
||||
count.inc
|
||||
last = e.sym.name
|
||||
|
||||
proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PSym =
|
||||
var err = "ambiguous identifier: '" & s.name.s & "'"
|
||||
var i = 0
|
||||
var ignoredModules = 0
|
||||
result = nil
|
||||
for candidate in importedItems(c, s.name):
|
||||
if i == 0: err.add " -- use one of the following:\n"
|
||||
else: err.add "\n"
|
||||
@@ -512,12 +528,16 @@ proc errorUseQualifier*(c: PContext; info:TLineInfo; choices: PNode) =
|
||||
errorUseQualifier(c, info, candidates, prefix)
|
||||
|
||||
proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extra = "") =
|
||||
var err = "undeclared identifier: '" & name & "'" & extra
|
||||
if c.recursiveDep.len > 0:
|
||||
err.add "\nThis might be caused by a recursive module dependency:\n"
|
||||
err.add c.recursiveDep
|
||||
# prevent excessive errors for 'nim check'
|
||||
c.recursiveDep = ""
|
||||
var err: string
|
||||
if name == "_":
|
||||
err = "the special identifier '_' is ignored in declarations and cannot be used"
|
||||
else:
|
||||
err = "undeclared identifier: '" & name & "'" & extra
|
||||
if c.recursiveDep.len > 0:
|
||||
err.add "\nThis might be caused by a recursive module dependency:\n"
|
||||
err.add c.recursiveDep
|
||||
# prevent excessive errors for 'nim check'
|
||||
c.recursiveDep = ""
|
||||
localError(c.config, info, errGenerated, err)
|
||||
|
||||
proc errorUndeclaredIdentifierHint*(c: PContext; n: PNode, ident: PIdent): PSym =
|
||||
@@ -531,13 +551,13 @@ proc lookUp*(c: PContext, n: PNode): PSym =
|
||||
var amb = false
|
||||
case n.kind
|
||||
of nkIdent:
|
||||
result = searchInScopes(c, n.ident, amb).skipAlias(n, c.config)
|
||||
result = searchInScopes(c, n.ident, amb)
|
||||
if result == nil: result = errorUndeclaredIdentifierHint(c, n, n.ident)
|
||||
of nkSym:
|
||||
result = n.sym
|
||||
of nkAccQuoted:
|
||||
var ident = considerQuotedIdent(c, n)
|
||||
result = searchInScopes(c, ident, amb).skipAlias(n, c.config)
|
||||
result = searchInScopes(c, ident, amb)
|
||||
if result == nil: result = errorUndeclaredIdentifierHint(c, n, ident)
|
||||
else:
|
||||
internalError(c.config, n.info, "lookUp")
|
||||
@@ -559,14 +579,16 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
|
||||
var amb = false
|
||||
var ident = considerQuotedIdent(c, n)
|
||||
if checkModule in flags:
|
||||
result = searchInScopes(c, ident, amb).skipAlias(n, c.config)
|
||||
result = searchInScopes(c, ident, amb)
|
||||
else:
|
||||
let candidates = searchInScopesFilterBy(c, ident, allExceptModule) #.skipAlias(n, c.config)
|
||||
let candidates = searchInScopesFilterBy(c, ident, allExceptModule)
|
||||
if candidates.len > 0:
|
||||
result = candidates[0]
|
||||
amb = candidates.len > 1
|
||||
if amb and checkAmbiguity in flags:
|
||||
errorUseQualifier(c, n.info, candidates)
|
||||
else:
|
||||
result = nil
|
||||
if result == nil:
|
||||
let candidates = allPureEnumFields(c, ident)
|
||||
if candidates.len > 0:
|
||||
@@ -593,13 +615,20 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
|
||||
ident = considerQuotedIdent(c, n[1])
|
||||
if ident != nil:
|
||||
if m == c.module:
|
||||
result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config)
|
||||
result = strTableGet(c.topLevelScope.symbols, ident)
|
||||
else:
|
||||
result = someSym(c.graph, m, ident).skipAlias(n, c.config)
|
||||
if c.importModuleLookup.getOrDefault(m.name.id).len > 1:
|
||||
var amb: bool
|
||||
result = errorUseQualifier(c, n.info, m, amb)
|
||||
else:
|
||||
result = someSym(c.graph, m, ident)
|
||||
if result == nil and checkUndeclared in flags:
|
||||
result = errorUndeclaredIdentifierHint(c, n[1], ident)
|
||||
elif n[1].kind == nkSym:
|
||||
result = n[1].sym
|
||||
if result.owner != nil and result.owner != m and checkUndeclared in flags:
|
||||
# dotExpr in templates can end up here
|
||||
result = errorUndeclaredIdentifierHint(c, n[1], considerQuotedIdent(c, n[1]))
|
||||
elif checkUndeclared in flags and
|
||||
n[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
|
||||
localError(c.config, n[1].info, "identifier expected, but got: " &
|
||||
@@ -615,11 +644,12 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
o.marked = initIntSet()
|
||||
case n.kind
|
||||
of nkIdent, nkAccQuoted:
|
||||
result = nil
|
||||
var ident = considerQuotedIdent(c, n)
|
||||
var scope = c.currentScope
|
||||
o.mode = oimNoQualifier
|
||||
while true:
|
||||
result = initIdentIter(o.it, scope.symbols, ident).skipAlias(n, c.config)
|
||||
result = initIdentIter(o.it, scope.symbols, ident)
|
||||
if result != nil:
|
||||
o.currentScope = scope
|
||||
break
|
||||
@@ -627,7 +657,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
scope = scope.parent
|
||||
if scope == nil:
|
||||
for i in 0..c.imports.high:
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[i], ident, c.graph).skipAlias(n, c.config)
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[i], ident, c.graph)
|
||||
if result != nil:
|
||||
o.currentScope = nil
|
||||
o.importIdx = i
|
||||
@@ -638,6 +668,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
result = n.sym
|
||||
o.mode = oimDone
|
||||
of nkDotExpr:
|
||||
result = nil
|
||||
o.mode = oimOtherModule
|
||||
o.m = qualifiedLookUp(c, n[0], {checkUndeclared, checkModule})
|
||||
if o.m != nil and o.m.kind == skModule:
|
||||
@@ -650,10 +681,10 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
if o.m == c.module:
|
||||
# a module may access its private members:
|
||||
result = initIdentIter(o.it, c.topLevelScope.symbols,
|
||||
ident).skipAlias(n, c.config)
|
||||
ident)
|
||||
o.mode = oimSelfModule
|
||||
else:
|
||||
result = initModuleIter(o.mit, c.graph, o.m, ident).skipAlias(n, c.config)
|
||||
result = initModuleIter(o.mit, c.graph, o.m, ident)
|
||||
else:
|
||||
noidentError(c.config, n[1], n)
|
||||
result = errorSym(c, n[1])
|
||||
@@ -667,7 +698,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
o.symChoiceIndex = 1
|
||||
o.marked = initIntSet()
|
||||
incl(o.marked, result.id)
|
||||
else: discard
|
||||
else: result = nil
|
||||
when false:
|
||||
if result != nil and result.kind == skStub: loadStub(result)
|
||||
|
||||
@@ -682,11 +713,12 @@ proc lastOverloadScope*(o: TOverloadIter): int =
|
||||
else: result = -1
|
||||
|
||||
proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
result = nil
|
||||
assert o.currentScope == nil
|
||||
var idx = o.importIdx+1
|
||||
o.importIdx = c.imports.len # assume the other imported modules lack this symbol too
|
||||
while idx < c.imports.len:
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[idx], o.it.name, c.graph).skipAlias(n, c.config)
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[idx], o.it.name, c.graph)
|
||||
if result != nil:
|
||||
# oh, we were wrong, some other module had the symbol, so remember that:
|
||||
o.importIdx = idx
|
||||
@@ -694,9 +726,10 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym
|
||||
inc idx
|
||||
|
||||
proc symChoiceExtension(o: var TOverloadIter; c: PContext; n: PNode): PSym =
|
||||
result = nil
|
||||
assert o.currentScope == nil
|
||||
while o.importIdx < c.imports.len:
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config)
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph)
|
||||
#while result != nil and result.id in o.marked:
|
||||
# result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx])
|
||||
if result != nil:
|
||||
@@ -711,29 +744,29 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
of oimNoQualifier:
|
||||
if o.currentScope != nil:
|
||||
assert o.importIdx < 0
|
||||
result = nextIdentIter(o.it, o.currentScope.symbols).skipAlias(n, c.config)
|
||||
result = nextIdentIter(o.it, o.currentScope.symbols)
|
||||
while result == nil:
|
||||
o.currentScope = o.currentScope.parent
|
||||
if o.currentScope != nil:
|
||||
result = initIdentIter(o.it, o.currentScope.symbols, o.it.name).skipAlias(n, c.config)
|
||||
result = initIdentIter(o.it, o.currentScope.symbols, o.it.name)
|
||||
# BUGFIX: o.it.name <-> n.ident
|
||||
else:
|
||||
o.importIdx = 0
|
||||
if c.imports.len > 0:
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config)
|
||||
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph)
|
||||
if result == nil:
|
||||
result = nextOverloadIterImports(o, c, n)
|
||||
break
|
||||
elif o.importIdx < c.imports.len:
|
||||
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config)
|
||||
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph)
|
||||
if result == nil:
|
||||
result = nextOverloadIterImports(o, c, n)
|
||||
else:
|
||||
result = nil
|
||||
of oimSelfModule:
|
||||
result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n, c.config)
|
||||
result = nextIdentIter(o.it, c.topLevelScope.symbols)
|
||||
of oimOtherModule:
|
||||
result = nextModuleIter(o.mit, c.graph).skipAlias(n, c.config)
|
||||
result = nextModuleIter(o.mit, c.graph)
|
||||
of oimSymChoice:
|
||||
if o.symChoiceIndex < n.len:
|
||||
result = n[o.symChoiceIndex].sym
|
||||
@@ -744,26 +777,28 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
o.mode = oimSymChoiceLocalLookup
|
||||
o.currentScope = c.currentScope
|
||||
result = firstIdentExcluding(o.it, o.currentScope.symbols,
|
||||
n[0].sym.name, o.marked).skipAlias(n, c.config)
|
||||
n[0].sym.name, o.marked)
|
||||
while result == nil:
|
||||
o.currentScope = o.currentScope.parent
|
||||
if o.currentScope != nil:
|
||||
result = firstIdentExcluding(o.it, o.currentScope.symbols,
|
||||
n[0].sym.name, o.marked).skipAlias(n, c.config)
|
||||
n[0].sym.name, o.marked)
|
||||
else:
|
||||
o.importIdx = 0
|
||||
result = symChoiceExtension(o, c, n)
|
||||
break
|
||||
if result != nil:
|
||||
incl o.marked, result.id
|
||||
else:
|
||||
result = nil
|
||||
of oimSymChoiceLocalLookup:
|
||||
if o.currentScope != nil:
|
||||
result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked).skipAlias(n, c.config)
|
||||
result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked)
|
||||
while result == nil:
|
||||
o.currentScope = o.currentScope.parent
|
||||
if o.currentScope != nil:
|
||||
result = firstIdentExcluding(o.it, o.currentScope.symbols,
|
||||
n[0].sym.name, o.marked).skipAlias(n, c.config)
|
||||
n[0].sym.name, o.marked)
|
||||
else:
|
||||
o.importIdx = 0
|
||||
result = symChoiceExtension(o, c, n)
|
||||
@@ -772,20 +807,23 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
incl o.marked, result.id
|
||||
|
||||
elif o.importIdx < c.imports.len:
|
||||
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config)
|
||||
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph)
|
||||
#assert result.id notin o.marked
|
||||
#while result != nil and result.id in o.marked:
|
||||
# result = nextIdentIter(o.it, c.imports[o.importIdx]).skipAlias(n, c.config)
|
||||
# result = nextIdentIter(o.it, c.imports[o.importIdx])
|
||||
if result == nil:
|
||||
inc o.importIdx
|
||||
result = symChoiceExtension(o, c, n)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
when false:
|
||||
if result != nil and result.kind == skStub: loadStub(result)
|
||||
|
||||
proc pickSym*(c: PContext, n: PNode; kinds: set[TSymKind];
|
||||
flags: TSymFlags = {}): PSym =
|
||||
var o: TOverloadIter
|
||||
result = nil
|
||||
var o: TOverloadIter = default(TOverloadIter)
|
||||
var a = initOverloadIter(o, c, n)
|
||||
while a != nil:
|
||||
if a.kind in kinds and flags <= a.flags:
|
||||
|
||||
@@ -79,7 +79,7 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: P
|
||||
if avoidTemp:
|
||||
tempAsNode = value
|
||||
else:
|
||||
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen),
|
||||
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen,
|
||||
owner, value.info, g.config.options)
|
||||
temp.typ = skipTypes(value.typ, abstractInst)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
@@ -100,7 +100,7 @@ proc evalOnce*(g: ModuleGraph; value: PNode; idgen: IdGenerator; owner: PSym): P
|
||||
## freely, multiple times. This is frequently required and such a builtin would also be
|
||||
## handy to have in macros.nim. The value that can be reused is 'result.lastSon'!
|
||||
result = newNodeIT(nkStmtListExpr, value.info, value.typ)
|
||||
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen),
|
||||
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen,
|
||||
owner, value.info, g.config.options)
|
||||
temp.typ = skipTypes(value.typ, abstractInst)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
@@ -126,13 +126,13 @@ proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; o
|
||||
let value = n.lastSon
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
|
||||
var temp = newSym(skTemp, getIdent(g.cache, "_"), nextSymId(idgen), owner, value.info, owner.options)
|
||||
var temp = newSym(skTemp, getIdent(g.cache, "_"), idgen, owner, value.info, owner.options)
|
||||
var v = newNodeI(nkLetSection, value.info)
|
||||
let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
|
||||
|
||||
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
|
||||
vpart[0] = tempAsNode
|
||||
vpart[1] = newNodeI(nkEmpty, value.info)
|
||||
vpart[1] = newNodeI(nkTupleClassTy, value.info)
|
||||
vpart[2] = value
|
||||
v.add vpart
|
||||
result.add(v)
|
||||
@@ -144,7 +144,7 @@ proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; o
|
||||
proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
# note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
|
||||
var temp = newSym(skVar, getIdent(g.cache, genPrefix), nextSymId(idgen), owner, n.info, owner.options)
|
||||
var temp = newSym(skVar, getIdent(g.cache, genPrefix), idgen, owner, n.info, owner.options)
|
||||
temp.typ = n[1].typ
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
incl(temp.flags, sfGenSym)
|
||||
@@ -171,8 +171,7 @@ proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo
|
||||
rawAddSon(result, getCompilerProc(g, "RootObj").typ)
|
||||
result.n = newNodeI(nkRecList, info)
|
||||
let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s),
|
||||
nextSymId(idgen),
|
||||
owner, info, owner.options)
|
||||
idgen, owner, info, owner.options)
|
||||
incl s.flags, sfAnon
|
||||
s.typ = result
|
||||
result.sym = s
|
||||
@@ -234,10 +233,13 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym
|
||||
# because of 'gensym' support, we have to mangle the name with its ID.
|
||||
# This is hacky but the clean solution is much more complex than it looks.
|
||||
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len),
|
||||
nextSymId(idgen), s.owner, s.info, s.options)
|
||||
idgen, s.owner, s.info, s.options)
|
||||
field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
|
||||
let t = skipIntLit(s.typ, idgen)
|
||||
field.typ = t
|
||||
if s.kind in {skLet, skVar, skField, skForVar}:
|
||||
#field.bitsize = s.bitsize
|
||||
field.alignment = s.alignment
|
||||
assert t.kind != tyTyped
|
||||
propagateToOwner(obj, t)
|
||||
field.position = obj.n.len
|
||||
@@ -250,7 +252,7 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym
|
||||
proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym {.discardable.} =
|
||||
result = lookupInRecord(obj.n, s.itemId)
|
||||
if result == nil:
|
||||
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), nextSymId(idgen),
|
||||
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), idgen,
|
||||
s.owner, s.info, s.options)
|
||||
field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
|
||||
let t = skipIntLit(s.typ, idgen)
|
||||
@@ -347,7 +349,8 @@ proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
|
||||
|
||||
proc callCodegenProc*(g: ModuleGraph; name: string;
|
||||
info: TLineInfo = unknownLineInfo;
|
||||
arg1, arg2, arg3, optionalArgs: PNode = nil): PNode =
|
||||
arg1: PNode = nil, arg2: PNode = nil,
|
||||
arg3: PNode = nil, optionalArgs: PNode = nil): PNode =
|
||||
result = newNodeI(nkCall, info)
|
||||
let sym = magicsys.getCompilerProc(g, name)
|
||||
if sym == nil:
|
||||
|
||||
@@ -26,11 +26,11 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
|
||||
result = systemModuleSym(g, getIdent(g.cache, name))
|
||||
if result == nil:
|
||||
localError(g.config, info, "system module needs: " & name)
|
||||
result = newSym(skError, getIdent(g.cache, name), nextSymId(g.idgen), g.systemModule, g.systemModule.info, {})
|
||||
result = newSym(skError, getIdent(g.cache, name), g.idgen, g.systemModule, g.systemModule.info, {})
|
||||
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
|
||||
if result.kind == skAlias: result = result.owner
|
||||
|
||||
proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
|
||||
result = nil
|
||||
let id = getIdent(g.cache, name)
|
||||
for r in systemModuleSyms(g, id):
|
||||
if r.magic == m:
|
||||
@@ -39,7 +39,7 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy
|
||||
result = r
|
||||
if result != nil: return result
|
||||
localError(g.config, info, "system module needs: " & name)
|
||||
result = newSym(skError, id, nextSymId(g.idgen), g.systemModule, g.systemModule.info, {})
|
||||
result = newSym(skError, id, g.idgen, g.systemModule, g.systemModule.info, {})
|
||||
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
|
||||
|
||||
proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType =
|
||||
@@ -81,8 +81,8 @@ proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType =
|
||||
|
||||
proc resetSysTypes*(g: ModuleGraph) =
|
||||
g.systemModule = nil
|
||||
initStrTable(g.compilerprocs)
|
||||
initStrTable(g.exposed)
|
||||
g.compilerprocs = initStrTable()
|
||||
g.exposed = initStrTable()
|
||||
for i in low(g.sysTypes)..high(g.sysTypes):
|
||||
g.sysTypes[i] = nil
|
||||
|
||||
@@ -100,7 +100,7 @@ proc skipIntLit*(t: PType; id: IdGenerator): PType {.inline.} =
|
||||
|
||||
proc addSonSkipIntLit*(father, son: PType; id: IdGenerator) =
|
||||
let s = son.skipIntLit(id)
|
||||
father.sons.add(s)
|
||||
father.add(s)
|
||||
propagateToOwner(father, s)
|
||||
|
||||
proc getCompilerProc*(g: ModuleGraph; name: string): PSym =
|
||||
@@ -124,7 +124,7 @@ proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) =
|
||||
proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym =
|
||||
strTableGet(g.exposed, getIdent(g.cache, name))
|
||||
|
||||
proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed)
|
||||
proc resetNimScriptSymbols*(g: ModuleGraph) = g.exposed = initStrTable()
|
||||
|
||||
proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
|
||||
case t.kind
|
||||
@@ -146,6 +146,7 @@ proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
|
||||
of tyProc:
|
||||
result = getSysMagic(g, info, "==", mEqProc)
|
||||
else:
|
||||
result = nil
|
||||
globalError(g.config, info,
|
||||
"can't find magic equals operator for type kind " & $t.kind)
|
||||
|
||||
|
||||
@@ -13,12 +13,12 @@ when not defined(nimcore):
|
||||
{.error: "nimcore MUST be defined for Nim's core tooling".}
|
||||
|
||||
import
|
||||
std/[strutils, os, times, tables, sha1, with, json],
|
||||
std/[strutils, os, times, tables, with, json],
|
||||
llstream, ast, lexer, syntaxes, options, msgs,
|
||||
condsyms,
|
||||
sem, idents, passes, extccomp,
|
||||
idents, extccomp,
|
||||
cgen, nversion,
|
||||
platform, nimconf, passaux, depends, vm,
|
||||
platform, nimconf, depends,
|
||||
modules,
|
||||
modulegraphs, lineinfos, pathutils, vmprofiler
|
||||
|
||||
@@ -29,12 +29,12 @@ when defined(nimPreviewSlimSystem):
|
||||
import ic / [cbackend, integrity, navigator]
|
||||
from ic / ic import rodViewer
|
||||
|
||||
when not defined(leanCompiler):
|
||||
import jsgen, docgen, docgen2
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
|
||||
proc semanticPasses(g: ModuleGraph) =
|
||||
registerPass g, verbosePass
|
||||
registerPass g, semPass
|
||||
import pipelines
|
||||
|
||||
when not defined(leanCompiler):
|
||||
import docgen
|
||||
|
||||
proc writeDepsFile(g: ModuleGraph) =
|
||||
let fname = g.config.nimcacheDir / RelativeFile(g.config.projectName & ".deps")
|
||||
@@ -56,7 +56,7 @@ proc writeCMakeDepsFile(conf: ConfigRef) =
|
||||
for it in conf.toCompile: cfiles.add(it.cname.string)
|
||||
let fileset = cfiles.toCountTable()
|
||||
# read old cfiles list
|
||||
var fl: File
|
||||
var fl: File = default(File)
|
||||
var prevset = initCountTable[string]()
|
||||
if open(fl, fname.string, fmRead):
|
||||
for line in fl.lines: prevset.inc(line)
|
||||
@@ -68,12 +68,18 @@ proc writeCMakeDepsFile(conf: ConfigRef) =
|
||||
fl.close()
|
||||
|
||||
proc commandGenDepend(graph: ModuleGraph) =
|
||||
semanticPasses(graph)
|
||||
registerPass(graph, gendependPass)
|
||||
compileProject(graph)
|
||||
setPipeLinePass(graph, GenDependPass)
|
||||
compilePipelineProject(graph)
|
||||
let project = graph.config.projectFull
|
||||
writeDepsFile(graph)
|
||||
generateDot(graph, project)
|
||||
|
||||
# dot in graphivz tool kit is required
|
||||
let graphvizDotPath = findExe("dot")
|
||||
if graphvizDotPath.len == 0:
|
||||
quit("gendepend: Graphviz's tool dot is required," &
|
||||
"see https://graphviz.org/download for downloading")
|
||||
|
||||
execExternalProgram(graph.config, "dot -Tpng -o" &
|
||||
changeFileExt(project, "png").string &
|
||||
' ' & changeFileExt(project, "dot").string)
|
||||
@@ -87,8 +93,8 @@ proc commandCheck(graph: ModuleGraph) =
|
||||
defineSymbol(conf.symbols, "nimconfig")
|
||||
elif conf.backend == backendJs:
|
||||
setTarget(conf.target, osJS, cpuJS)
|
||||
semanticPasses(graph) # use an empty backend for semantic checking only
|
||||
compileProject(graph)
|
||||
setPipeLinePass(graph, SemPass)
|
||||
compilePipelineProject(graph)
|
||||
|
||||
if conf.symbolFiles != disabledSf:
|
||||
case conf.ideCmd
|
||||
@@ -102,22 +108,20 @@ when not defined(leanCompiler):
|
||||
proc commandDoc2(graph: ModuleGraph; ext: string) =
|
||||
handleDocOutputOptions graph.config
|
||||
graph.config.setErrorMaxHighMaybe
|
||||
semanticPasses(graph)
|
||||
case ext:
|
||||
of TexExt: registerPass(graph, docgen2TexPass)
|
||||
of JsonExt: registerPass(graph, docgen2JsonPass)
|
||||
of HtmlExt: registerPass(graph, docgen2Pass)
|
||||
else: doAssert false, $ext
|
||||
compileProject(graph)
|
||||
finishDoc2Pass(graph.config.projectName)
|
||||
of TexExt:
|
||||
setPipeLinePass(graph, Docgen2TexPass)
|
||||
of JsonExt:
|
||||
setPipeLinePass(graph, Docgen2JsonPass)
|
||||
of HtmlExt:
|
||||
setPipeLinePass(graph, Docgen2Pass)
|
||||
else: raiseAssert $ext
|
||||
compilePipelineProject(graph)
|
||||
|
||||
proc commandCompileToC(graph: ModuleGraph) =
|
||||
let conf = graph.config
|
||||
extccomp.initVars(conf)
|
||||
semanticPasses(graph)
|
||||
if conf.symbolFiles == disabledSf:
|
||||
registerPass(graph, cgenPass)
|
||||
|
||||
if {optRun, optForceFullMake} * conf.globalOptions == {optRun} or isDefined(conf, "nimBetterRun"):
|
||||
if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile):
|
||||
# nothing changed
|
||||
@@ -127,7 +131,11 @@ proc commandCompileToC(graph: ModuleGraph) =
|
||||
if not extccomp.ccHasSaneOverflow(conf):
|
||||
conf.symbols.defineSymbol("nimEmulateOverflowChecks")
|
||||
|
||||
compileProject(graph)
|
||||
if conf.symbolFiles == disabledSf:
|
||||
setPipeLinePass(graph, CgenPass)
|
||||
else:
|
||||
setPipeLinePass(graph, SemPass)
|
||||
compilePipelineProject(graph)
|
||||
if graph.config.errorCounter > 0:
|
||||
return # issue #9933
|
||||
if conf.symbolFiles == disabledSf:
|
||||
@@ -160,33 +168,27 @@ proc commandCompileToJS(graph: ModuleGraph) =
|
||||
conf.exc = excCpp
|
||||
setTarget(conf.target, osJS, cpuJS)
|
||||
defineSymbol(conf.symbols, "ecmascript") # For backward compatibility
|
||||
semanticPasses(graph)
|
||||
registerPass(graph, JSgenPass)
|
||||
compileProject(graph)
|
||||
setPipeLinePass(graph, JSgenPass)
|
||||
compilePipelineProject(graph)
|
||||
if optGenScript in conf.globalOptions:
|
||||
writeDepsFile(graph)
|
||||
|
||||
proc interactivePasses(graph: ModuleGraph) =
|
||||
proc commandInteractive(graph: ModuleGraph) =
|
||||
graph.config.setErrorMaxHighMaybe
|
||||
initDefines(graph.config.symbols)
|
||||
defineSymbol(graph.config.symbols, "nimscript")
|
||||
# note: seems redundant with -d:nimHasLibFFI
|
||||
when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
|
||||
registerPass(graph, verbosePass)
|
||||
registerPass(graph, semPass)
|
||||
registerPass(graph, evalPass)
|
||||
|
||||
proc commandInteractive(graph: ModuleGraph) =
|
||||
graph.config.setErrorMaxHighMaybe
|
||||
interactivePasses(graph)
|
||||
compileSystemModule(graph)
|
||||
setPipeLinePass(graph, InterpreterPass)
|
||||
compilePipelineSystemModule(graph)
|
||||
if graph.config.commandArgs.len > 0:
|
||||
discard graph.compileModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
|
||||
discard graph.compilePipelineModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
|
||||
else:
|
||||
var m = graph.makeStdinModule()
|
||||
incl(m.flags, sfMainModule)
|
||||
var idgen = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0)
|
||||
let s = llStreamOpenStdIn(onPrompt = proc() = flushDot(graph.config))
|
||||
processModule(graph, m, idgen, s)
|
||||
discard processPipelineModule(graph, m, idgen, s)
|
||||
|
||||
proc commandScan(cache: IdentCache, config: ConfigRef) =
|
||||
var f = addFileExt(AbsoluteFile mainCommandArg(config), NimExt)
|
||||
@@ -194,7 +196,7 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
|
||||
if stream != nil:
|
||||
var
|
||||
L: Lexer
|
||||
tok: Token
|
||||
tok: Token = default(Token)
|
||||
initToken(tok)
|
||||
openLexer(L, f, stream, cache, config)
|
||||
while true:
|
||||
@@ -241,8 +243,6 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
let conf = graph.config
|
||||
let cache = graph.cache
|
||||
|
||||
# In "nim serve" scenario, each command must reset the registered passes
|
||||
clearPasses(graph)
|
||||
conf.lastCmdTime = epochTime()
|
||||
conf.searchPaths.add(conf.libpath)
|
||||
|
||||
@@ -267,7 +267,7 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
# and it has added this define implictly, so we must undo that here.
|
||||
# A better solution might be to fix system.nim
|
||||
undefSymbol(conf.symbols, "useNimRtl")
|
||||
of backendInvalid: doAssert false
|
||||
of backendInvalid: raiseAssert "unreachable"
|
||||
|
||||
proc compileToBackend() =
|
||||
customizeForBackend(conf.backend)
|
||||
@@ -277,7 +277,7 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
of backendCpp: commandCompileToC(graph)
|
||||
of backendObjc: commandCompileToC(graph)
|
||||
of backendJs: commandCompileToJS(graph)
|
||||
of backendInvalid: doAssert false
|
||||
of backendInvalid: raiseAssert "unreachable"
|
||||
|
||||
template docLikeCmd(body) =
|
||||
when defined(leanCompiler):
|
||||
@@ -417,7 +417,7 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
of cmdJsonscript:
|
||||
setOutFile(graph.config)
|
||||
commandJsonScript(graph)
|
||||
of cmdUnknown, cmdNone, cmdIdeTools, cmdNimfix:
|
||||
of cmdUnknown, cmdNone, cmdIdeTools:
|
||||
rawMessage(conf, errGenerated, "invalid command: " & conf.command)
|
||||
|
||||
if conf.errorCounter == 0 and conf.cmd notin {cmdTcc, cmdDump, cmdNop}:
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# `std/md5` without VM and JavaScript support, to circumvent a bug with
|
||||
# openarrays on Nim < 1.4.
|
||||
|
||||
when defined(nimHasStyleChecks):
|
||||
{.push styleChecks: off.}
|
||||
|
||||
type
|
||||
MD5State = array[0..3, uint32]
|
||||
MD5Block = array[0..15, uint32]
|
||||
MD5CBits = array[0..7, uint8]
|
||||
MD5Digest* = array[0..15, uint8]
|
||||
## MD5 checksum of a string, obtained with the `toMD5 proc <#toMD5,string>`_.
|
||||
MD5Buffer = array[0..63, uint8]
|
||||
MD5Context* {.final.} = object
|
||||
state: MD5State
|
||||
count: array[0..1, uint32]
|
||||
buffer: MD5Buffer
|
||||
|
||||
const
|
||||
padding: array[0..63, uint8] = [
|
||||
0x80'u8, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
]
|
||||
|
||||
proc F(x, y, z: uint32): uint32 {.inline.} =
|
||||
result = (x and y) or ((not x) and z)
|
||||
|
||||
proc G(x, y, z: uint32): uint32 {.inline.} =
|
||||
result = (x and z) or (y and (not z))
|
||||
|
||||
proc H(x, y, z: uint32): uint32 {.inline.} =
|
||||
result = x xor y xor z
|
||||
|
||||
proc I(x, y, z: uint32): uint32 {.inline.} =
|
||||
result = y xor (x or (not z))
|
||||
|
||||
proc rot(x: var uint32, n: uint8) {.inline.} =
|
||||
x = (x shl n) or (x shr (32'u32 - n))
|
||||
|
||||
proc FF(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + F(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a + b
|
||||
|
||||
proc GG(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + G(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a + b
|
||||
|
||||
proc HH(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + H(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a + b
|
||||
|
||||
proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + I(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a + b
|
||||
|
||||
proc encode(dest: var MD5Block, src: openArray[uint8]) =
|
||||
var j = 0
|
||||
for i in 0..high(dest):
|
||||
dest[i] = uint32(ord(src[j])) or
|
||||
uint32(ord(src[j+1])) shl 8 or
|
||||
uint32(ord(src[j+2])) shl 16 or
|
||||
uint32(ord(src[j+3])) shl 24
|
||||
inc(j, 4)
|
||||
|
||||
proc decode(dest: var openArray[uint8], src: openArray[uint32]) =
|
||||
var i = 0
|
||||
for j in 0..high(src):
|
||||
dest[i] = uint8(src[j] and 0xff'u32)
|
||||
dest[i+1] = uint8(src[j] shr 8 and 0xff'u32)
|
||||
dest[i+2] = uint8(src[j] shr 16 and 0xff'u32)
|
||||
dest[i+3] = uint8(src[j] shr 24 and 0xff'u32)
|
||||
inc(i, 4)
|
||||
|
||||
template slice(s: string | cstring, a, b): openArray[uint8] =
|
||||
s.toOpenArrayByte(a, b)
|
||||
|
||||
template slice(s: openArray[uint8], a, b): openArray[uint8] =
|
||||
s.toOpenArray(a, b)
|
||||
|
||||
proc transform(buffer: openArray[uint8], state: var MD5State) =
|
||||
var
|
||||
myBlock: MD5Block
|
||||
encode(myBlock, buffer)
|
||||
var a = state[0]
|
||||
var b = state[1]
|
||||
var c = state[2]
|
||||
var d = state[3]
|
||||
FF(a, b, c, d, myBlock[0], 7'u8, 0xD76AA478'u32)
|
||||
FF(d, a, b, c, myBlock[1], 12'u8, 0xE8C7B756'u32)
|
||||
FF(c, d, a, b, myBlock[2], 17'u8, 0x242070DB'u32)
|
||||
FF(b, c, d, a, myBlock[3], 22'u8, 0xC1BDCEEE'u32)
|
||||
FF(a, b, c, d, myBlock[4], 7'u8, 0xF57C0FAF'u32)
|
||||
FF(d, a, b, c, myBlock[5], 12'u8, 0x4787C62A'u32)
|
||||
FF(c, d, a, b, myBlock[6], 17'u8, 0xA8304613'u32)
|
||||
FF(b, c, d, a, myBlock[7], 22'u8, 0xFD469501'u32)
|
||||
FF(a, b, c, d, myBlock[8], 7'u8, 0x698098D8'u32)
|
||||
FF(d, a, b, c, myBlock[9], 12'u8, 0x8B44F7AF'u32)
|
||||
FF(c, d, a, b, myBlock[10], 17'u8, 0xFFFF5BB1'u32)
|
||||
FF(b, c, d, a, myBlock[11], 22'u8, 0x895CD7BE'u32)
|
||||
FF(a, b, c, d, myBlock[12], 7'u8, 0x6B901122'u32)
|
||||
FF(d, a, b, c, myBlock[13], 12'u8, 0xFD987193'u32)
|
||||
FF(c, d, a, b, myBlock[14], 17'u8, 0xA679438E'u32)
|
||||
FF(b, c, d, a, myBlock[15], 22'u8, 0x49B40821'u32)
|
||||
GG(a, b, c, d, myBlock[1], 5'u8, 0xF61E2562'u32)
|
||||
GG(d, a, b, c, myBlock[6], 9'u8, 0xC040B340'u32)
|
||||
GG(c, d, a, b, myBlock[11], 14'u8, 0x265E5A51'u32)
|
||||
GG(b, c, d, a, myBlock[0], 20'u8, 0xE9B6C7AA'u32)
|
||||
GG(a, b, c, d, myBlock[5], 5'u8, 0xD62F105D'u32)
|
||||
GG(d, a, b, c, myBlock[10], 9'u8, 0x02441453'u32)
|
||||
GG(c, d, a, b, myBlock[15], 14'u8, 0xD8A1E681'u32)
|
||||
GG(b, c, d, a, myBlock[4], 20'u8, 0xE7D3FBC8'u32)
|
||||
GG(a, b, c, d, myBlock[9], 5'u8, 0x21E1CDE6'u32)
|
||||
GG(d, a, b, c, myBlock[14], 9'u8, 0xC33707D6'u32)
|
||||
GG(c, d, a, b, myBlock[3], 14'u8, 0xF4D50D87'u32)
|
||||
GG(b, c, d, a, myBlock[8], 20'u8, 0x455A14ED'u32)
|
||||
GG(a, b, c, d, myBlock[13], 5'u8, 0xA9E3E905'u32)
|
||||
GG(d, a, b, c, myBlock[2], 9'u8, 0xFCEFA3F8'u32)
|
||||
GG(c, d, a, b, myBlock[7], 14'u8, 0x676F02D9'u32)
|
||||
GG(b, c, d, a, myBlock[12], 20'u8, 0x8D2A4C8A'u32)
|
||||
HH(a, b, c, d, myBlock[5], 4'u8, 0xFFFA3942'u32)
|
||||
HH(d, a, b, c, myBlock[8], 11'u8, 0x8771F681'u32)
|
||||
HH(c, d, a, b, myBlock[11], 16'u8, 0x6D9D6122'u32)
|
||||
HH(b, c, d, a, myBlock[14], 23'u8, 0xFDE5380C'u32)
|
||||
HH(a, b, c, d, myBlock[1], 4'u8, 0xA4BEEA44'u32)
|
||||
HH(d, a, b, c, myBlock[4], 11'u8, 0x4BDECFA9'u32)
|
||||
HH(c, d, a, b, myBlock[7], 16'u8, 0xF6BB4B60'u32)
|
||||
HH(b, c, d, a, myBlock[10], 23'u8, 0xBEBFBC70'u32)
|
||||
HH(a, b, c, d, myBlock[13], 4'u8, 0x289B7EC6'u32)
|
||||
HH(d, a, b, c, myBlock[0], 11'u8, 0xEAA127FA'u32)
|
||||
HH(c, d, a, b, myBlock[3], 16'u8, 0xD4EF3085'u32)
|
||||
HH(b, c, d, a, myBlock[6], 23'u8, 0x04881D05'u32)
|
||||
HH(a, b, c, d, myBlock[9], 4'u8, 0xD9D4D039'u32)
|
||||
HH(d, a, b, c, myBlock[12], 11'u8, 0xE6DB99E5'u32)
|
||||
HH(c, d, a, b, myBlock[15], 16'u8, 0x1FA27CF8'u32)
|
||||
HH(b, c, d, a, myBlock[2], 23'u8, 0xC4AC5665'u32)
|
||||
II(a, b, c, d, myBlock[0], 6'u8, 0xF4292244'u32)
|
||||
II(d, a, b, c, myBlock[7], 10'u8, 0x432AFF97'u32)
|
||||
II(c, d, a, b, myBlock[14], 15'u8, 0xAB9423A7'u32)
|
||||
II(b, c, d, a, myBlock[5], 21'u8, 0xFC93A039'u32)
|
||||
II(a, b, c, d, myBlock[12], 6'u8, 0x655B59C3'u32)
|
||||
II(d, a, b, c, myBlock[3], 10'u8, 0x8F0CCC92'u32)
|
||||
II(c, d, a, b, myBlock[10], 15'u8, 0xFFEFF47D'u32)
|
||||
II(b, c, d, a, myBlock[1], 21'u8, 0x85845DD1'u32)
|
||||
II(a, b, c, d, myBlock[8], 6'u8, 0x6FA87E4F'u32)
|
||||
II(d, a, b, c, myBlock[15], 10'u8, 0xFE2CE6E0'u32)
|
||||
II(c, d, a, b, myBlock[6], 15'u8, 0xA3014314'u32)
|
||||
II(b, c, d, a, myBlock[13], 21'u8, 0x4E0811A1'u32)
|
||||
II(a, b, c, d, myBlock[4], 6'u8, 0xF7537E82'u32)
|
||||
II(d, a, b, c, myBlock[11], 10'u8, 0xBD3AF235'u32)
|
||||
II(c, d, a, b, myBlock[2], 15'u8, 0x2AD7D2BB'u32)
|
||||
II(b, c, d, a, myBlock[9], 21'u8, 0xEB86D391'u32)
|
||||
state[0] = state[0] + a
|
||||
state[1] = state[1] + b
|
||||
state[2] = state[2] + c
|
||||
state[3] = state[3] + d
|
||||
|
||||
proc md5Init*(c: var MD5Context) {.raises: [], tags: [], gcsafe.}
|
||||
proc md5Update*(c: var MD5Context, input: openArray[uint8]) {.raises: [],
|
||||
tags: [], gcsafe.}
|
||||
proc md5Final*(c: var MD5Context, digest: var MD5Digest) {.raises: [], tags: [], gcsafe.}
|
||||
|
||||
proc md5Update*(c: var MD5Context, input: cstring, len: int) {.raises: [],
|
||||
tags: [], gcsafe.} =
|
||||
## Updates the `MD5Context` with the `input` data of length `len`.
|
||||
##
|
||||
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
|
||||
## function explicitly.
|
||||
md5Update(c, input.slice(0, len - 1))
|
||||
|
||||
|
||||
proc toMD5*(s: string): MD5Digest =
|
||||
## Computes the `MD5Digest` value for a string `s`.
|
||||
##
|
||||
## **See also:**
|
||||
## * `getMD5 proc <#getMD5,string>`_ which returns a string representation
|
||||
## of the `MD5Digest`
|
||||
## * `$ proc <#$,MD5Digest>`_ for converting MD5Digest to string
|
||||
runnableExamples:
|
||||
assert $toMD5("abc") == "900150983cd24fb0d6963f7d28e17f72"
|
||||
|
||||
var c: MD5Context
|
||||
md5Init(c)
|
||||
md5Update(c, s.slice(0, s.len - 1))
|
||||
md5Final(c, result)
|
||||
|
||||
proc `$`*(d: MD5Digest): string =
|
||||
## Converts a `MD5Digest` value into its string representation.
|
||||
const digits = "0123456789abcdef"
|
||||
result = ""
|
||||
for i in 0..15:
|
||||
add(result, digits[(d[i].int shr 4) and 0xF])
|
||||
add(result, digits[d[i].int and 0xF])
|
||||
|
||||
proc getMD5*(s: string): string =
|
||||
## Computes an MD5 value of `s` and returns its string representation.
|
||||
##
|
||||
## **See also:**
|
||||
## * `toMD5 proc <#toMD5,string>`_ which returns the `MD5Digest` of a string
|
||||
runnableExamples:
|
||||
assert getMD5("abc") == "900150983cd24fb0d6963f7d28e17f72"
|
||||
|
||||
var
|
||||
c: MD5Context
|
||||
d: MD5Digest
|
||||
md5Init(c)
|
||||
md5Update(c, s.slice(0, s.len - 1))
|
||||
md5Final(c, d)
|
||||
result = $d
|
||||
|
||||
proc `==`*(D1, D2: MD5Digest): bool =
|
||||
## Checks if two `MD5Digest` values are identical.
|
||||
for i in 0..15:
|
||||
if D1[i] != D2[i]: return false
|
||||
return true
|
||||
|
||||
|
||||
proc clearBuffer(c: var MD5Context) {.inline.} =
|
||||
zeroMem(addr(c.buffer), sizeof(MD5Buffer))
|
||||
|
||||
proc md5Init*(c: var MD5Context) =
|
||||
## Initializes an `MD5Context`.
|
||||
##
|
||||
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
|
||||
## function explicitly.
|
||||
c.state[0] = 0x67452301'u32
|
||||
c.state[1] = 0xEFCDAB89'u32
|
||||
c.state[2] = 0x98BADCFE'u32
|
||||
c.state[3] = 0x10325476'u32
|
||||
c.count[0] = 0'u32
|
||||
c.count[1] = 0'u32
|
||||
clearBuffer(c)
|
||||
|
||||
proc writeBuffer(c: var MD5Context, index: int,
|
||||
input: openArray[uint8], inputIndex, len: int) {.inline.} =
|
||||
copyMem(addr(c.buffer[index]), unsafeAddr(input[inputIndex]), len)
|
||||
|
||||
proc md5Update*(c: var MD5Context, input: openArray[uint8]) =
|
||||
## Updates the `MD5Context` with the `input` data.
|
||||
##
|
||||
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
|
||||
## function explicitly.
|
||||
var Index = int((c.count[0] shr 3) and 0x3F)
|
||||
c.count[0] = c.count[0] + (uint32(input.len) shl 3)
|
||||
if c.count[0] < (uint32(input.len) shl 3): c.count[1] = c.count[1] + 1'u32
|
||||
c.count[1] = c.count[1] + (uint32(input.len) shr 29)
|
||||
var PartLen = 64 - Index
|
||||
if input.len >= PartLen:
|
||||
writeBuffer(c, Index, input, 0, PartLen)
|
||||
transform(c.buffer, c.state)
|
||||
var i = PartLen
|
||||
while i + 63 < input.len:
|
||||
transform(input.slice(i, i + 63), c.state)
|
||||
inc(i, 64)
|
||||
if i < input.len:
|
||||
writeBuffer(c, 0, input, i, input.len - i)
|
||||
elif input.len > 0:
|
||||
writeBuffer(c, Index, input, 0, input.len)
|
||||
|
||||
proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
|
||||
## Finishes the `MD5Context` and stores the result in `digest`.
|
||||
##
|
||||
## If you use the `toMD5 proc <#toMD5,string>`_, there's no need to call this
|
||||
## function explicitly.
|
||||
var
|
||||
Bits: MD5CBits
|
||||
PadLen: int
|
||||
decode(Bits, c.count)
|
||||
var Index = int((c.count[0] shr 3) and 0x3F)
|
||||
if Index < 56: PadLen = 56 - Index
|
||||
else: PadLen = 120 - Index
|
||||
md5Update(c, padding.slice(0, PadLen - 1))
|
||||
md5Update(c, Bits)
|
||||
decode(digest, c.state)
|
||||
clearBuffer(c)
|
||||
|
||||
|
||||
when defined(nimHasStyleChecks):
|
||||
{.pop.} #{.push styleChecks: off.}
|
||||
@@ -11,7 +11,8 @@
|
||||
## represents a complete Nim project. Single modules can either be kept in RAM
|
||||
## or stored in a rod-file.
|
||||
|
||||
import intsets, tables, hashes, md5_old
|
||||
import intsets, tables, hashes
|
||||
import ../dist/checksums/src/checksums/md5
|
||||
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
|
||||
import ic / [packed_ast, ic]
|
||||
|
||||
@@ -57,6 +58,18 @@ type
|
||||
sym*: PSym
|
||||
info*: TLineInfo
|
||||
|
||||
PipelinePass* = enum
|
||||
NonePass
|
||||
SemPass
|
||||
JSgenPass
|
||||
CgenPass
|
||||
EvalPass
|
||||
InterpreterPass
|
||||
GenDependPass
|
||||
Docgen2TexPass
|
||||
Docgen2JsonPass
|
||||
Docgen2Pass
|
||||
|
||||
ModuleGraph* {.acyclic.} = ref object
|
||||
ifaces*: seq[Iface] ## indexed by int32 fileIdx
|
||||
packed*: PackedModuleGraph
|
||||
@@ -66,6 +79,7 @@ type
|
||||
procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId.
|
||||
attachedOps*: array[TTypeAttachedOp, Table[ItemId, LazySym]] # Type ID, destructors, etc.
|
||||
methodsPerType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods
|
||||
memberProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached member procs (only c++, virtual and ctor so far)
|
||||
enumToStringProcs*: Table[ItemId, LazySym]
|
||||
emittedTypeInfo*: Table[string, FileIndex]
|
||||
|
||||
@@ -104,6 +118,7 @@ type
|
||||
cacheCounters*: Table[string, BiggestInt] # IC: implemented
|
||||
cacheTables*: Table[string, BTree[string, PNode]] # IC: implemented
|
||||
passes*: seq[TPass]
|
||||
pipelinePass*: PipelinePass
|
||||
onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
|
||||
onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
|
||||
onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
|
||||
@@ -127,7 +142,7 @@ type
|
||||
isFrontend: bool]
|
||||
|
||||
proc resetForBackend*(g: ModuleGraph) =
|
||||
initStrTable(g.compilerprocs)
|
||||
g.compilerprocs = initStrTable()
|
||||
g.typeInstCache.clear()
|
||||
g.procInstCache.clear()
|
||||
for a in mitems(g.attachedOps):
|
||||
@@ -181,8 +196,8 @@ template semtabAll*(g: ModuleGraph, m: PSym): TStrTable =
|
||||
g.ifaces[m.position].interfHidden
|
||||
|
||||
proc initStrTables*(g: ModuleGraph, m: PSym) =
|
||||
initStrTable(semtab(g, m))
|
||||
initStrTable(semtabAll(g, m))
|
||||
semtab(g, m) = initStrTable()
|
||||
semtabAll(g, m) = initStrTable()
|
||||
|
||||
proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) =
|
||||
strTableAdd(semtab(g, m), s)
|
||||
@@ -353,6 +368,7 @@ proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) =
|
||||
setAttachedOp(g, module, dest, k, op)
|
||||
|
||||
proc loadCompilerProc*(g: ModuleGraph; name: string): PSym =
|
||||
result = nil
|
||||
if g.config.symbolFiles == disabledSf: return nil
|
||||
|
||||
# slow, linear search, but the results are cached:
|
||||
@@ -398,7 +414,7 @@ proc stopCompile*(g: ModuleGraph): bool {.inline.} =
|
||||
result = g.doStopCompile != nil and g.doStopCompile()
|
||||
|
||||
proc createMagic*(g: ModuleGraph; idgen: IdGenerator; name: string, m: TMagic): PSym =
|
||||
result = newSym(skProc, getIdent(g.cache, name), nextSymId(idgen), nil, unknownLineInfo, {})
|
||||
result = newSym(skProc, getIdent(g.cache, name), idgen, nil, unknownLineInfo, {})
|
||||
result.magic = m
|
||||
result.flags = {sfNeverRaises}
|
||||
|
||||
@@ -443,7 +459,7 @@ proc initModuleGraphFields(result: ModuleGraph) =
|
||||
# A module ID of -1 means that the symbol is not attached to a module at all,
|
||||
# but to the module graph:
|
||||
result.idgen = IdGenerator(module: -1'i32, symId: 0'i32, typeId: 0'i32)
|
||||
initStrTable(result.packageSyms)
|
||||
result.packageSyms = initStrTable()
|
||||
result.deps = initIntSet()
|
||||
result.importDeps = initTable[FileIndex, seq[FileIndex]]()
|
||||
result.ifaces = @[]
|
||||
@@ -453,9 +469,9 @@ proc initModuleGraphFields(result: ModuleGraph) =
|
||||
result.suggestSymbols = initTable[FileIndex, seq[SymInfoPair]]()
|
||||
result.suggestErrors = initTable[FileIndex, seq[Suggest]]()
|
||||
result.methods = @[]
|
||||
initStrTable(result.compilerprocs)
|
||||
initStrTable(result.exposed)
|
||||
initStrTable(result.packageTypes)
|
||||
result.compilerprocs = initStrTable()
|
||||
result.exposed = initStrTable()
|
||||
result.packageTypes = initStrTable()
|
||||
result.emptyNode = newNode(nkEmpty)
|
||||
result.cacheSeqs = initTable[string, PNode]()
|
||||
result.cacheCounters = initTable[string, BiggestInt]()
|
||||
@@ -472,7 +488,7 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
|
||||
initModuleGraphFields(result)
|
||||
|
||||
proc resetAllModules*(g: ModuleGraph) =
|
||||
initStrTable(g.packageSyms)
|
||||
g.packageSyms = initStrTable()
|
||||
g.deps = initIntSet()
|
||||
g.ifaces = @[]
|
||||
g.importStack = @[]
|
||||
@@ -480,11 +496,12 @@ proc resetAllModules*(g: ModuleGraph) =
|
||||
g.usageSym = nil
|
||||
g.owners = @[]
|
||||
g.methods = @[]
|
||||
initStrTable(g.compilerprocs)
|
||||
initStrTable(g.exposed)
|
||||
g.compilerprocs = initStrTable()
|
||||
g.exposed = initStrTable()
|
||||
initModuleGraphFields(g)
|
||||
|
||||
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
result = nil
|
||||
if fileIdx.int32 >= 0:
|
||||
if isCachedModule(g, fileIdx.int32):
|
||||
result = g.packed[fileIdx.int32].module
|
||||
@@ -590,6 +607,7 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
||||
|
||||
proc needsCompilation*(g: ModuleGraph): bool =
|
||||
# every module that *depends* on this file is also dirty:
|
||||
result = false
|
||||
for i in 0i32..<g.ifaces.len.int32:
|
||||
let m = g.ifaces[i].module
|
||||
if m != nil:
|
||||
@@ -597,6 +615,7 @@ proc needsCompilation*(g: ModuleGraph): bool =
|
||||
return true
|
||||
|
||||
proc needsCompilation*(g: ModuleGraph, fileIdx: FileIndex): bool =
|
||||
result = false
|
||||
let module = g.getModule(fileIdx)
|
||||
if module != nil and g.isDirty(module):
|
||||
return true
|
||||
@@ -618,6 +637,8 @@ proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex;
|
||||
## Returns 'nil' if the module needs to be recompiled.
|
||||
if g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}:
|
||||
result = moduleFromRodFile(g.packed, g.config, g.cache, fileIdx, cachedModules)
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc configComplete*(g: ModuleGraph) =
|
||||
rememberStartupConfig(g.startupPackedConfig, g.config)
|
||||
|
||||
@@ -11,13 +11,8 @@
|
||||
|
||||
import
|
||||
ast, magicsys, msgs, options,
|
||||
idents, lexer, passes, syntaxes, llstream, modulegraphs,
|
||||
lineinfos, pathutils, tables, packages
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
|
||||
import ic / replayer
|
||||
idents, lexer, syntaxes, modulegraphs,
|
||||
lineinfos, pathutils
|
||||
|
||||
proc resetSystemArtifacts*(g: ModuleGraph) =
|
||||
magicsys.resetSysTypes(g)
|
||||
@@ -25,12 +20,12 @@ proc resetSystemArtifacts*(g: ModuleGraph) =
|
||||
template getModuleIdent(graph: ModuleGraph, filename: AbsoluteFile): PIdent =
|
||||
getIdent(graph.cache, splitFile(filename).name)
|
||||
|
||||
proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) =
|
||||
proc partialInitModule*(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) =
|
||||
let packSym = getPackage(graph, fileIdx)
|
||||
result.owner = packSym
|
||||
result.position = int fileIdx
|
||||
|
||||
proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
proc newModule*(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
|
||||
# We cannot call ``newSym`` here, because we have to circumvent the ID
|
||||
# mechanism, which we do in order to assign each module a persistent ID.
|
||||
@@ -38,103 +33,21 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||
name: getModuleIdent(graph, filename),
|
||||
info: newLineInfo(fileIdx, 1, 1))
|
||||
if not isNimIdentifier(result.name.s):
|
||||
rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s)
|
||||
rawMessage(graph.config, errGenerated, "invalid module name: '" & result.name.s &
|
||||
"'; a module name must be a valid Nim identifier.")
|
||||
partialInitModule(result, graph, fileIdx, filename)
|
||||
graph.registerModule(result)
|
||||
|
||||
proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym =
|
||||
var flags = flags
|
||||
if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule
|
||||
result = graph.getModule(fileIdx)
|
||||
|
||||
template processModuleAux(moduleStatus) =
|
||||
onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule)
|
||||
var s: PLLStream
|
||||
if sfMainModule in flags:
|
||||
if graph.config.projectIsStdin: s = stdin.llStreamOpen
|
||||
elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput)
|
||||
discard processModule(graph, result, idGeneratorFromModule(result), s)
|
||||
if result == nil:
|
||||
var cachedModules: seq[FileIndex]
|
||||
result = moduleFromRodFile(graph, fileIdx, cachedModules)
|
||||
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
|
||||
if result == nil:
|
||||
result = newModule(graph, fileIdx)
|
||||
result.flags.incl flags
|
||||
registerModule(graph, result)
|
||||
processModuleAux("import")
|
||||
else:
|
||||
if sfSystemModule in flags:
|
||||
graph.systemModule = result
|
||||
partialInitModule(result, graph, fileIdx, filename)
|
||||
for m in cachedModules:
|
||||
registerModuleById(graph, m)
|
||||
replayStateChanges(graph.packed[m.int].module, graph)
|
||||
replayGenericCacheInformation(graph, m.int)
|
||||
elif graph.isDirty(result):
|
||||
result.flags.excl sfDirty
|
||||
# reset module fields:
|
||||
initStrTables(graph, result)
|
||||
result.ast = nil
|
||||
processModuleAux("import(dirty)")
|
||||
graph.markClientsDirty(fileIdx)
|
||||
|
||||
proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym =
|
||||
# this is called by the semantic checking phase
|
||||
assert graph.config != nil
|
||||
result = compileModule(graph, fileIdx, {}, s)
|
||||
graph.addDep(s, fileIdx)
|
||||
# keep track of import relationships
|
||||
if graph.config.hcrOn:
|
||||
graph.importDeps.mgetOrPut(FileIndex(s.position), @[]).add(fileIdx)
|
||||
#if sfSystemModule in result.flags:
|
||||
# localError(result.info, errAttemptToRedefine, result.name.s)
|
||||
# restore the notes for outer module:
|
||||
graph.config.notes =
|
||||
if graph.config.belongsToProjectPackage(s) or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
|
||||
else: graph.config.foreignPackageNotes
|
||||
|
||||
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
|
||||
result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
|
||||
graph.addDep(s, fileIdx)
|
||||
graph.addIncludeDep(s.position.FileIndex, fileIdx)
|
||||
|
||||
proc connectCallbacks*(graph: ModuleGraph) =
|
||||
graph.includeFileCallback = includeModule
|
||||
graph.importModuleCallback = importModule
|
||||
|
||||
proc compileSystemModule*(graph: ModuleGraph) =
|
||||
if graph.systemModule == nil:
|
||||
connectCallbacks(graph)
|
||||
graph.config.m.systemFileIdx = fileInfoIdx(graph.config,
|
||||
graph.config.libpath / RelativeFile"system.nim")
|
||||
discard graph.compileModule(graph.config.m.systemFileIdx, {sfSystemModule})
|
||||
|
||||
proc wantMainModule*(conf: ConfigRef) =
|
||||
if conf.projectFull.isEmpty:
|
||||
fatal(conf, gCmdLineInfo, "command expects a filename")
|
||||
conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt))
|
||||
|
||||
proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) =
|
||||
connectCallbacks(graph)
|
||||
let conf = graph.config
|
||||
wantMainModule(conf)
|
||||
configComplete(graph)
|
||||
|
||||
let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim")
|
||||
let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx
|
||||
conf.projectMainIdx2 = projectFile
|
||||
|
||||
let packSym = getPackage(graph, projectFile)
|
||||
graph.config.mainPackageId = packSym.getPackageId
|
||||
graph.importStack.add projectFile
|
||||
|
||||
if projectFile == systemFileIdx:
|
||||
discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule})
|
||||
else:
|
||||
graph.compileSystemModule()
|
||||
discard graph.compileModule(projectFile, {sfMainModule})
|
||||
|
||||
proc makeModule*(graph: ModuleGraph; filename: AbsoluteFile): PSym =
|
||||
result = graph.newModule(fileInfoIdx(graph.config, filename))
|
||||
registerModule(graph, result)
|
||||
|
||||
@@ -128,6 +128,13 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
|
||||
var dummy: bool
|
||||
result = fileInfoIdx(conf, filename, dummy)
|
||||
|
||||
proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile; isKnownFile: var bool): FileIndex =
|
||||
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), isKnownFile)
|
||||
|
||||
proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex =
|
||||
var dummy: bool
|
||||
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy)
|
||||
|
||||
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
|
||||
result.fileIndex = fileInfoIdx
|
||||
if line < int high(uint16):
|
||||
@@ -219,7 +226,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):
|
||||
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)
|
||||
@@ -227,7 +234,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):
|
||||
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)
|
||||
@@ -287,9 +294,11 @@ proc toColumn*(info: TLineInfo): int {.inline.} =
|
||||
result = info.col
|
||||
|
||||
proc toFileLineCol(info: InstantiationInfo): string {.inline.} =
|
||||
result = ""
|
||||
result.toLocation(info.filename, info.line, info.column + ColOffset)
|
||||
|
||||
proc toFileLineCol*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
|
||||
result = ""
|
||||
result.toLocation(toMsgFilename(conf, info), info.line.int, info.col.int + ColOffset)
|
||||
|
||||
proc `$`*(conf: ConfigRef; info: TLineInfo): string = toFileLineCol(conf, info)
|
||||
@@ -401,7 +410,7 @@ proc getMessageStr(msg: TMsgKind, arg: string): string = msgKindToString(msg) %
|
||||
type TErrorHandling* = enum doNothing, doAbort, doRaise
|
||||
|
||||
proc log*(s: string) =
|
||||
var f: File
|
||||
var f: File = default(File)
|
||||
if open(f, getHomeDir() / "nimsuggest.log", fmAppend):
|
||||
f.writeLine(s)
|
||||
close(f)
|
||||
@@ -495,6 +504,8 @@ proc getSurroundingSrc(conf: ConfigRef; info: TLineInfo): string =
|
||||
result = "\n" & indent & $sourceLine(conf, info)
|
||||
if info.col >= 0:
|
||||
result.add "\n" & indent & spaces(info.col) & '^'
|
||||
else:
|
||||
result = ""
|
||||
|
||||
proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||
let title = case msg
|
||||
@@ -504,7 +515,8 @@ proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): s
|
||||
conf.toFileLineCol(info) & " " & title & getMessageStr(msg, arg)
|
||||
|
||||
proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
eh: TErrorHandling, info2: InstantiationInfo, isRaw = false) {.gcsafe, noinline.} =
|
||||
eh: TErrorHandling, info2: InstantiationInfo, isRaw = false,
|
||||
ignoreError = false) {.gcsafe, noinline.} =
|
||||
var
|
||||
title: string
|
||||
color: ForegroundColor
|
||||
@@ -534,10 +546,11 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
ignoreMsg = not conf.hasWarn(msg)
|
||||
if not ignoreMsg and msg in conf.warningAsErrors:
|
||||
title = ErrorTitle
|
||||
color = ErrorColor
|
||||
else:
|
||||
title = WarningTitle
|
||||
color = WarningColor
|
||||
if not ignoreMsg: writeContext(conf, info)
|
||||
color = WarningColor
|
||||
inc(conf.warnCounter)
|
||||
of hintMin..hintMax:
|
||||
sev = Severity.Hint
|
||||
@@ -568,7 +581,8 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
" compiler msg initiated here", KindColor,
|
||||
KindFormat % $hintMsgOrigin,
|
||||
resetStyle, conf.unitSep)
|
||||
handleError(conf, msg, eh, s, ignoreMsg)
|
||||
if not ignoreError:
|
||||
handleError(conf, msg, eh, s, ignoreMsg)
|
||||
if msg in fatalMsgs:
|
||||
# most likely would have died here but just in case, we restore state
|
||||
conf.m.errorOutputs = errorOutputsOld
|
||||
|
||||
@@ -309,6 +309,7 @@ proc symbol(n: PNode): Symbol =
|
||||
# echo "symbol ", n, " ", n.kind, " ", result.int
|
||||
|
||||
func `$`(map: NilMap): string =
|
||||
result = ""
|
||||
var now = map
|
||||
var stack: seq[NilMap] = @[]
|
||||
while not now.isNil:
|
||||
@@ -416,7 +417,7 @@ proc moveOut(ctx: NilCheckerContext, map: NilMap, target: PNode) =
|
||||
if targetSetIndex != noSetIndex:
|
||||
var targetSet = map.sets[targetSetIndex]
|
||||
if targetSet.len > 1:
|
||||
var other: ExprIndex
|
||||
var other: ExprIndex = default(ExprIndex)
|
||||
|
||||
for element in targetSet:
|
||||
if element.ExprIndex != targetIndex:
|
||||
@@ -561,7 +562,7 @@ proc derefWarning(n, ctx, map; kind: Nilability) =
|
||||
if n.info in ctx.warningLocations:
|
||||
return
|
||||
ctx.warningLocations.incl(n.info)
|
||||
var a: seq[History]
|
||||
var a: seq[History] = @[]
|
||||
if n.kind == nkSym:
|
||||
a = history(map, ctx.index(n))
|
||||
var res = ""
|
||||
@@ -765,7 +766,7 @@ proc checkIf(n, ctx, map): Check =
|
||||
# the state of the conditions: negating conditions before the current one
|
||||
var layerHistory = newNilMap(mapIf)
|
||||
# the state after branch effects
|
||||
var afterLayer: NilMap
|
||||
var afterLayer: NilMap = nil
|
||||
# the result nilability for expressions
|
||||
var nilability = Safe
|
||||
|
||||
@@ -862,9 +863,10 @@ proc checkInfix(n, ctx, map): Check =
|
||||
## a or b : map is an union of a and b's
|
||||
## a == b : use checkCondition
|
||||
## else: no change, just check args
|
||||
result = default(Check)
|
||||
if n[0].kind == nkSym:
|
||||
var mapL: NilMap
|
||||
var mapR: NilMap
|
||||
var mapL: NilMap = nil
|
||||
var mapR: NilMap = nil
|
||||
if n[0].sym.magic notin {mAnd, mEqRef}:
|
||||
mapL = checkCondition(n[1], ctx, map, false, false)
|
||||
mapR = checkCondition(n[2], ctx, map, false, false)
|
||||
@@ -909,7 +911,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
|
||||
else: ""
|
||||
|
||||
var cache = newIdentCache()
|
||||
var op = newSym(skVar, cache.getIdent(name), nextSymId ctx.idgen, nil, r.info)
|
||||
var op = newSym(skVar, cache.getIdent(name), ctx.idgen, nil, r.info)
|
||||
|
||||
op.magic = magic
|
||||
result = nkInfix.newTree(
|
||||
@@ -920,7 +922,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
|
||||
|
||||
proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
|
||||
var cache = newIdentCache()
|
||||
var op = newSym(skVar, cache.getIdent("not"), nextSymId ctx.idgen, nil, node.info)
|
||||
var op = newSym(skVar, cache.getIdent("not"), ctx.idgen, nil, node.info)
|
||||
|
||||
op.magic = mNot
|
||||
result = nkPrefix.newTree(
|
||||
@@ -947,7 +949,7 @@ proc checkCase(n, ctx, map): Check =
|
||||
let base = n[0]
|
||||
result.map = map.copyMap()
|
||||
result.nilability = Safe
|
||||
var a: PNode
|
||||
var a: PNode = nil
|
||||
for child in n:
|
||||
case child.kind:
|
||||
of nkOfBranch:
|
||||
@@ -1222,7 +1224,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check =
|
||||
# TODO deeper nested elements?
|
||||
# A(field: B()) #
|
||||
# field: Safe ->
|
||||
var elements: seq[(PNode, Nilability)]
|
||||
var elements: seq[(PNode, Nilability)] = @[]
|
||||
for i, child in n:
|
||||
result = check(child, ctx, result.map)
|
||||
if i > 0:
|
||||
@@ -1333,7 +1335,7 @@ proc preVisit(ctx: NilCheckerContext, s: PSym, body: PNode, conf: ConfigRef) =
|
||||
ctx.symbolIndices = {resultId: resultExprIndex}.toTable()
|
||||
var cache = newIdentCache()
|
||||
ctx.expressions = SeqOfDistinct[ExprIndex, PNode](@[newIdentNode(cache.getIdent("result"), s.ast.info)])
|
||||
var emptySet: IntSet # set[ExprIndex]
|
||||
var emptySet: IntSet = initIntSet() # set[ExprIndex]
|
||||
ctx.dependants = SeqOfDistinct[ExprIndex, IntSet](@[emptySet])
|
||||
for i, arg in s.typ.n.sons:
|
||||
if i > 0:
|
||||
|
||||
@@ -7,6 +7,7 @@ define:nimcore
|
||||
define:nimPreviewFloatRoundtrip
|
||||
define:nimPreviewSlimSystem
|
||||
define:nimPreviewCstringConversion
|
||||
define:nimPreviewProcConversion
|
||||
define:nimPreviewRangeDefault
|
||||
threads:off
|
||||
|
||||
@@ -14,7 +15,6 @@ threads:off
|
||||
|
||||
@if windows:
|
||||
cincludes: "$lib/wrappers/libffi/common"
|
||||
tlsEmulation:off
|
||||
@end
|
||||
|
||||
define:useStdoutAsStdmsg
|
||||
@@ -31,6 +31,7 @@ define:useStdoutAsStdmsg
|
||||
warning[ObservableStores]:off
|
||||
@end
|
||||
|
||||
|
||||
@if nimHasWarningAsError:
|
||||
warningAsError[GcUnsafe2]:on
|
||||
@end
|
||||
@@ -38,3 +39,15 @@ define:useStdoutAsStdmsg
|
||||
@if nimHasWarnUnnamedBreak:
|
||||
warningAserror[UnnamedBreak]:on
|
||||
@end
|
||||
|
||||
@if nimHasWarnBareExcept:
|
||||
warningAserror[BareExcept]:on
|
||||
@end
|
||||
|
||||
|
||||
@if nimUseStrictDefs:
|
||||
experimental:strictDefs
|
||||
warningAsError[Uninit]:on
|
||||
warningAsError[ProveInit]:on
|
||||
@end
|
||||
|
||||
|
||||
@@ -12,10 +12,7 @@ import std/[os, strutils, parseopt]
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
when defined(windows) and not defined(nimKochBootstrap):
|
||||
# remove workaround pending bootstrap >= 1.5.1
|
||||
# refs https://github.com/nim-lang/Nim/issues/18334#issuecomment-867114536
|
||||
# alternative would be to prepend `currentSourcePath.parentDir.quoteShell`
|
||||
when defined(windows):
|
||||
when defined(gcc):
|
||||
when defined(x86):
|
||||
{.link: "../icons/nim.res".}
|
||||
@@ -41,6 +38,15 @@ when defined(profiler) or defined(memProfiler):
|
||||
{.hint: "Profiling support is turned on!".}
|
||||
import nimprof
|
||||
|
||||
proc nimbleLockExists(config: ConfigRef): bool =
|
||||
const nimbleLock = "nimble.lock"
|
||||
let pd = if not config.projectPath.isEmpty: config.projectPath else: AbsoluteDir(getCurrentDir())
|
||||
if optSkipParentConfigFiles notin config.globalOptions:
|
||||
for dir in parentDirs(pd.string, fromRoot=true, inclusive=false):
|
||||
if fileExists(dir / nimbleLock):
|
||||
return true
|
||||
return fileExists(pd.string / nimbleLock)
|
||||
|
||||
proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
|
||||
var p = parseopt.initOptParser(cmd)
|
||||
var argsCount = 0
|
||||
@@ -74,12 +80,20 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
|
||||
config.arguments.len > 0 and config.cmd notin {cmdTcc, cmdNimscript, cmdCrun}:
|
||||
rawMessage(config, errGenerated, errArgsNeedRunOption)
|
||||
|
||||
if config.nimbleLockExists:
|
||||
# disable nimble path if nimble.lock is present.
|
||||
# see https://github.com/nim-lang/nimble/issues/1004
|
||||
disableNimblePath(config)
|
||||
|
||||
proc getNimRunExe(conf: ConfigRef): string =
|
||||
# xxx consider defining `conf.getConfigVar("nimrun.exe")` to allow users to
|
||||
# customize the binary to run the command with, e.g. for custom `nodejs` or `wine`.
|
||||
if conf.isDefined("mingw"):
|
||||
if conf.isDefined("i386"): result = "wine"
|
||||
elif conf.isDefined("amd64"): result = "wine64"
|
||||
else: result = ""
|
||||
else:
|
||||
result = ""
|
||||
|
||||
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
|
||||
let self = NimProg(
|
||||
@@ -126,7 +140,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
|
||||
# tasyncjs_fail` would fail, refs https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode
|
||||
if cmdPrefix.len == 0: cmdPrefix = findNodeJs().quoteShell
|
||||
cmdPrefix.add " --unhandled-rejections=strict"
|
||||
else: doAssert false, $conf.backend
|
||||
else: raiseAssert $conf.backend
|
||||
if cmdPrefix.len > 0: cmdPrefix.add " "
|
||||
# without the `cmdPrefix.len > 0` check, on windows you'd get a cryptic:
|
||||
# `The parameter is incorrect`
|
||||
|
||||
@@ -10,11 +10,13 @@
|
||||
## Implements some helper procs for Nimble (Nim's package manager) support.
|
||||
|
||||
import parseutils, strutils, os, options, msgs, sequtils, lineinfos, pathutils,
|
||||
std/sha1, tables
|
||||
tables
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
|
||||
proc addPath*(conf: ConfigRef; path: AbsoluteDir, info: TLineInfo) =
|
||||
if not conf.searchPaths.contains(path):
|
||||
conf.searchPaths.insert(path, 0)
|
||||
@@ -35,11 +37,16 @@ proc isSpecial(ver: Version): bool =
|
||||
|
||||
proc isValidVersion(v: string): bool =
|
||||
if v.len > 0:
|
||||
if v[0] in {'#'} + Digits: return true
|
||||
if v[0] in {'#'} + Digits:
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc `<`*(ver: Version, ver2: Version): bool =
|
||||
## This is synced from Nimble's version module.
|
||||
|
||||
result = false
|
||||
# Handling for special versions such as "#head" or "#branch".
|
||||
if ver.isSpecial or ver2.isSpecial:
|
||||
if ver2.isSpecial and ($ver2).normalize == "#head":
|
||||
@@ -143,7 +150,7 @@ proc addNimblePath(conf: ConfigRef; p: string, info: TLineInfo) =
|
||||
conf.lazyPaths.insert(AbsoluteDir path, 0)
|
||||
|
||||
proc addPathRec(conf: ConfigRef; dir: string, info: TLineInfo) =
|
||||
var packages: PackageInfo
|
||||
var packages: PackageInfo = initTable[string, tuple[version, checksum: string]]()
|
||||
var pos = dir.len-1
|
||||
if dir[pos] in {DirSep, AltSep}: inc(pos)
|
||||
for k,p in os.walkDir(dir):
|
||||
|
||||
@@ -214,7 +214,7 @@ proc parseAssignment(L: var Lexer, tok: var Token;
|
||||
proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
|
||||
config: ConfigRef): bool =
|
||||
var
|
||||
L: Lexer
|
||||
L: Lexer = default(Lexer)
|
||||
tok: Token
|
||||
stream: PLLStream
|
||||
stream = llStreamOpen(filename, fmRead)
|
||||
@@ -228,6 +228,8 @@ proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
|
||||
if condStack.len > 0: lexMessage(L, errGenerated, "expected @end")
|
||||
closeLexer(L)
|
||||
return true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc getUserConfigPath*(filename: RelativeFile): AbsoluteFile =
|
||||
result = getConfigDir().AbsoluteDir / RelativeDir"nim" / filename
|
||||
@@ -250,7 +252,7 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen:
|
||||
|
||||
template runNimScriptIfExists(path: AbsoluteFile, isMain = false) =
|
||||
let p = path # eval once
|
||||
var s: PLLStream
|
||||
var s: PLLStream = nil
|
||||
if isMain and optWasNimscript in conf.globalOptions:
|
||||
if conf.projectIsStdin: s = stdin.llStreamOpen
|
||||
elif conf.projectIsCmd: s = llStreamOpen(conf.cmdInput)
|
||||
|
||||
@@ -9,10 +9,16 @@
|
||||
|
||||
## exposes the Nim VM to clients.
|
||||
import
|
||||
ast, astalgo, modules, passes, condsyms,
|
||||
options, sem, llstream, lineinfos, vm,
|
||||
ast, modules, condsyms,
|
||||
options, llstream, lineinfos, vm,
|
||||
vmdef, modulegraphs, idents, os, pathutils,
|
||||
passaux, scriptconfig, std/compilesettings
|
||||
scriptconfig, std/[compilesettings, tables]
|
||||
|
||||
import pipelines
|
||||
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[assertions, syncio]
|
||||
|
||||
type
|
||||
Interpreter* = ref object ## Use Nim as an interpreter with this object
|
||||
@@ -72,11 +78,14 @@ proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) =
|
||||
assert i != nil
|
||||
assert i.mainModule != nil, "no main module selected"
|
||||
initStrTables(i.graph, i.mainModule)
|
||||
i.graph.cacheSeqs.clear()
|
||||
i.graph.cacheCounters.clear()
|
||||
i.graph.cacheTables.clear()
|
||||
i.mainModule.ast = nil
|
||||
|
||||
let s = if scriptStream != nil: scriptStream
|
||||
else: llStreamOpen(findFile(i.graph.config, i.scriptName), fmRead)
|
||||
processModule(i.graph, i.mainModule, i.idgen, s)
|
||||
discard processPipelineModule(i.graph, i.mainModule, i.idgen, s)
|
||||
|
||||
proc findNimStdLib*(): string =
|
||||
## Tries to find a path to a valid "system.nim" file.
|
||||
@@ -109,12 +118,10 @@ proc createInterpreter*(scriptName: string;
|
||||
var conf = newConfigRef()
|
||||
var cache = newIdentCache()
|
||||
var graph = newModuleGraph(cache, conf)
|
||||
connectCallbacks(graph)
|
||||
connectPipelineCallbacks(graph)
|
||||
initDefines(conf.symbols)
|
||||
for define in defines:
|
||||
defineSymbol(conf.symbols, define[0], define[1])
|
||||
registerPass(graph, semPass)
|
||||
registerPass(graph, evalPass)
|
||||
|
||||
for p in searchPaths:
|
||||
conf.searchPaths.add(AbsoluteDir p)
|
||||
@@ -129,7 +136,8 @@ proc createInterpreter*(scriptName: string;
|
||||
if registerOps:
|
||||
vm.registerAdditionalOps() # Required to register parts of stdlib modules
|
||||
graph.vm = vm
|
||||
graph.compileSystemModule()
|
||||
setPipeLinePass(graph, EvalPass)
|
||||
graph.compilePipelineSystemModule()
|
||||
result = Interpreter(mainModule: m, graph: graph, scriptName: scriptName, idgen: idgen)
|
||||
|
||||
proc destroyInterpreter*(i: Interpreter) =
|
||||
@@ -159,13 +167,11 @@ proc runRepl*(r: TLLRepl;
|
||||
defineSymbol(conf.symbols, "nimscript")
|
||||
if supportNimscript: defineSymbol(conf.symbols, "nimconfig")
|
||||
when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
|
||||
registerPass(graph, verbosePass)
|
||||
registerPass(graph, semPass)
|
||||
registerPass(graph, evalPass)
|
||||
var m = graph.makeStdinModule()
|
||||
incl(m.flags, sfMainModule)
|
||||
var idgen = idGeneratorFromModule(m)
|
||||
|
||||
if supportNimscript: graph.vm = setupVM(m, cache, "stdin", graph, idgen)
|
||||
graph.compileSystemModule()
|
||||
processModule(graph, m, idgen, llStreamOpenStdIn(r))
|
||||
setPipeLinePass(graph, InterpreterPass)
|
||||
graph.compilePipelineSystemModule()
|
||||
discard processPipelineModule(graph, m, idgen, llStreamOpenStdIn(r))
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Nimfix is a tool that helps to convert old-style Nimrod code to Nim code.
|
||||
|
||||
import strutils, os, parseopt
|
||||
import compiler/[options, commands, modules, sem,
|
||||
passes, passaux, linter,
|
||||
msgs, nimconf,
|
||||
extccomp, condsyms,
|
||||
modulegraphs, idents]
|
||||
|
||||
const Usage = """
|
||||
Nimfix - Tool to patch Nim code
|
||||
Usage:
|
||||
nimfix [options] projectfile.nim
|
||||
|
||||
Options:
|
||||
--overwriteFiles:on|off overwrite the original nim files.
|
||||
DEFAULT is ON!
|
||||
--wholeProject overwrite every processed file.
|
||||
--checkExtern:on|off style check also extern names
|
||||
--styleCheck:on|off|auto performs style checking for identifiers
|
||||
and suggests an alternative spelling;
|
||||
'auto' corrects the spelling.
|
||||
--bestEffort try to fix the code even when there
|
||||
are errors.
|
||||
|
||||
In addition, all command line options of Nim are supported.
|
||||
"""
|
||||
|
||||
proc mainCommand =
|
||||
registerPass verbosePass
|
||||
registerPass semPass
|
||||
conf.setCmd cmdNimfix
|
||||
searchPaths.add options.libpath
|
||||
if gProjectFull.len != 0:
|
||||
# current path is always looked first for modules
|
||||
searchPaths.insert(gProjectPath, 0)
|
||||
|
||||
compileProject(newModuleGraph(), newIdentCache())
|
||||
pretty.overwriteFiles()
|
||||
|
||||
proc processCmdLine*(pass: TCmdLinePass, cmd: string, config: ConfigRef) =
|
||||
var p = parseopt.initOptParser(cmd)
|
||||
var argsCount = 0
|
||||
gOnlyMainfile = true
|
||||
while true:
|
||||
parseopt.next(p)
|
||||
case p.kind
|
||||
of cmdEnd: break
|
||||
of cmdLongoption, cmdShortOption:
|
||||
case p.key.normalize
|
||||
of "overwritefiles":
|
||||
case p.val.normalize
|
||||
of "on": gOverWrite = true
|
||||
of "off": gOverWrite = false
|
||||
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||
of "checkextern":
|
||||
case p.val.normalize
|
||||
of "on": gCheckExtern = true
|
||||
of "off": gCheckExtern = false
|
||||
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||
of "stylecheck":
|
||||
case p.val.normalize
|
||||
of "off": gStyleCheck = StyleCheck.None
|
||||
of "on": gStyleCheck = StyleCheck.Warn
|
||||
of "auto": gStyleCheck = StyleCheck.Auto
|
||||
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||
of "wholeproject": gOnlyMainfile = false
|
||||
of "besteffort": msgs.gErrorMax = high(int) # don't stop after first error
|
||||
else:
|
||||
processSwitch(pass, p, config)
|
||||
of cmdArgument:
|
||||
options.gProjectName = unixToNativePath(p.key)
|
||||
# if processArgument(pass, p, argsCount): break
|
||||
|
||||
proc handleCmdLine(config: ConfigRef) =
|
||||
if paramCount() == 0:
|
||||
stdout.writeLine(Usage)
|
||||
else:
|
||||
processCmdLine(passCmd1, "", config)
|
||||
if gProjectName != "":
|
||||
try:
|
||||
gProjectFull = canonicalizePath(gProjectName)
|
||||
except OSError:
|
||||
gProjectFull = gProjectName
|
||||
var p = splitFile(gProjectFull)
|
||||
gProjectPath = p.dir
|
||||
gProjectName = p.name
|
||||
else:
|
||||
gProjectPath = getCurrentDir()
|
||||
loadConfigs(DefaultConfig, config) # load all config files
|
||||
# now process command line arguments again, because some options in the
|
||||
# command line can overwrite the config file's settings
|
||||
extccomp.initVars()
|
||||
processCmdLine(passCmd2, "", config)
|
||||
mainCommand()
|
||||
|
||||
when compileOption("gc", "refc"):
|
||||
GC_disableMarkAndSweep()
|
||||
|
||||
condsyms.initDefines()
|
||||
defineSymbol "nimfix"
|
||||
handleCmdline newConfigRef()
|
||||
@@ -1,17 +0,0 @@
|
||||
# Special configuration file for the Nim project
|
||||
# gc:markAndSweep
|
||||
|
||||
hint[XDeclaredButNotUsed]:off
|
||||
path:"$projectPath/.."
|
||||
|
||||
path:"$lib/packages/docutils"
|
||||
path:"$nim"
|
||||
|
||||
define:useStdoutAsStdmsg
|
||||
symbol:nimfix
|
||||
define:nimfix
|
||||
|
||||
cs:partial
|
||||
#define:useNodeIds
|
||||
define:booting
|
||||
define:noDocgen
|
||||
@@ -1,45 +0,0 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import strutils except Letters
|
||||
import ".." / [ast, msgs, lineinfos, idents, options, linter]
|
||||
|
||||
proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PIdent) =
|
||||
let line = sourceLine(conf, info)
|
||||
var first = min(info.col.int, line.len)
|
||||
if first < 0: return
|
||||
#inc first, skipIgnoreCase(line, "proc ", first)
|
||||
while first > 0 and line[first-1] in Letters: dec first
|
||||
if first < 0: return
|
||||
if line[first] == '`': inc first
|
||||
|
||||
let last = first+identLen(line, first)-1
|
||||
if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
|
||||
var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x
|
||||
else:
|
||||
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
|
||||
conf.m.fileInfos[info.fileIndex.int32].dirty = true
|
||||
#if newSym.s == "File": writeStackTrace()
|
||||
|
||||
proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PSym) =
|
||||
replaceDeprecated(conf, info, oldSym.name, newSym.name)
|
||||
|
||||
proc replaceComment*(conf: ConfigRef; info: TLineInfo) =
|
||||
let line = sourceLine(conf, info)
|
||||
var first = info.col.int
|
||||
if line[first] != '#': inc first
|
||||
|
||||
var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x
|
||||
else:
|
||||
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
|
||||
conf.m.fileInfos[info.fileIndex.int32].dirty = true
|
||||
@@ -62,7 +62,9 @@ proc someInSet*(s: PNode, a, b: PNode): bool =
|
||||
result = false
|
||||
|
||||
proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet =
|
||||
var first, j: Int128
|
||||
result = @[]
|
||||
var first: Int128 = Zero
|
||||
var j: Int128 = Zero
|
||||
first = firstOrd(conf, s.typ[0])
|
||||
bitSetInit(result, int(getSize(conf, s.typ)))
|
||||
for i in 0..<s.len:
|
||||
|
||||
@@ -7,4 +7,4 @@ proc findNodeJs*(): string {.inline.} =
|
||||
result = findExe("node")
|
||||
if result.len == 0:
|
||||
echo "Please install NodeJS first, see https://nodejs.org/en/download"
|
||||
raise newException(IOError, "NodeJS not found in PATH: " & result)
|
||||
raise newException(IOError, "NodeJS not found in PATH")
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
const
|
||||
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
|
||||
DefaultSetElements* = 1 shl 8
|
||||
## assumed set element count when using int literals
|
||||
VersionAsString* = system.NimVersion
|
||||
RodFileVersion* = "1223" # modify this if the rod-format changes!
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ import
|
||||
|
||||
from trees import exprStructuralEquivalent
|
||||
|
||||
import std/strutils
|
||||
|
||||
const
|
||||
nfMarkForDeletion = nfNone # faster than a lookup table
|
||||
|
||||
@@ -110,16 +112,17 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) =
|
||||
var reverse = false
|
||||
if n[0].kind == nkSym:
|
||||
let s = n[0].sym
|
||||
if s.magic == mWasMoved:
|
||||
let name = s.name.s.normalize
|
||||
if name == "=wasmoved":
|
||||
b.wasMovedLocs.add n
|
||||
special = true
|
||||
elif s.name.s == "=destroy":
|
||||
elif name == "=destroy":
|
||||
if c.inFinally > 0 and (b.hasReturn or b.hasBreak):
|
||||
discard "cannot optimize away the destructor"
|
||||
else:
|
||||
c.wasMovedDestroyPair b, n
|
||||
special = true
|
||||
elif s.name.s == "=sink":
|
||||
elif name == "=sink":
|
||||
reverse = true
|
||||
|
||||
if not special:
|
||||
@@ -276,7 +279,7 @@ proc optimize*(n: PNode): PNode =
|
||||
|
||||
Now assume 'use' raises, then we shouldn't do the 'wasMoved(s)'
|
||||
]#
|
||||
var c: Con
|
||||
var c: Con = Con()
|
||||
var b: BasicBlock
|
||||
analyse(c, b, n)
|
||||
if c.somethingTodo:
|
||||
|
||||
@@ -24,7 +24,7 @@ const
|
||||
useEffectSystem* = true
|
||||
useWriteTracking* = false
|
||||
hasFFI* = defined(nimHasLibFFI)
|
||||
copyrightYear* = "2022"
|
||||
copyrightYear* = "2023"
|
||||
|
||||
nimEnableCovariance* = defined(nimEnableCovariance)
|
||||
|
||||
@@ -49,6 +49,7 @@ type # please make sure we have under 32 options
|
||||
optSinkInference # 'sink T' inference
|
||||
optCursorInference
|
||||
optImportHidden
|
||||
optQuirky
|
||||
|
||||
TOptions* = set[TOption]
|
||||
TGlobalOption* = enum
|
||||
@@ -78,6 +79,8 @@ type # please make sure we have under 32 options
|
||||
optThreadAnalysis, # thread analysis pass
|
||||
optTlsEmulation, # thread var emulation turned on
|
||||
optGenIndex # generate index file for documentation;
|
||||
optGenIndexOnly # generate only index file for documentation
|
||||
optNoImportdoc # disable loading external documentation files
|
||||
optEmbedOrigSrc # embed the original source in the generated code
|
||||
# also: generate header file
|
||||
optIdeDebug # idetools: debug mode
|
||||
@@ -100,12 +103,11 @@ type # please make sure we have under 32 options
|
||||
optBenchmarkVM # Enables cpuTime() in the VM
|
||||
optProduceAsm # produce assembler code
|
||||
optPanics # turn panics (sysFatal) into a process termination
|
||||
optNimV1Emulation # emulate Nim v1.0
|
||||
optNimV12Emulation # emulate Nim v1.2
|
||||
optNimV16Emulation # emulate Nim v1.6
|
||||
optSourcemap
|
||||
optProfileVM # enable VM profiler
|
||||
optEnableDeepCopy # ORC specific: enable 'deepcopy' for all types.
|
||||
optShowNonExportedFields # for documentation: show fields that are not exported
|
||||
optJsBigInt64 # use bigints for 64-bit integers in JS
|
||||
|
||||
TGlobalOptions* = set[TGlobalOption]
|
||||
|
||||
@@ -165,7 +167,6 @@ type
|
||||
cmdInteractive # start interactive session
|
||||
cmdNop
|
||||
cmdJsonscript # compile a .json build file
|
||||
cmdNimfix
|
||||
# old unused: cmdInterpret, cmdDef: def feature (find definition for IDEs)
|
||||
|
||||
const
|
||||
@@ -183,6 +184,7 @@ type
|
||||
gcRegions = "regions"
|
||||
gcArc = "arc"
|
||||
gcOrc = "orc"
|
||||
gcAtomicArc = "atomicArc"
|
||||
gcMarkAndSweep = "markAndSweep"
|
||||
gcHooks = "hooks"
|
||||
gcRefc = "refc"
|
||||
@@ -193,10 +195,9 @@ type
|
||||
IdeCmd* = enum
|
||||
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod,
|
||||
ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols,
|
||||
ideRecompile, ideChanged, ideType, ideDeclaration
|
||||
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand
|
||||
|
||||
Feature* = enum ## experimental features; DO NOT RENAME THESE!
|
||||
implicitDeref, # deadcode; remains here for backwards compatibility
|
||||
dotOperators,
|
||||
callOperator,
|
||||
parallel,
|
||||
@@ -208,7 +209,7 @@ type
|
||||
codeReordering,
|
||||
compiletimeFFI,
|
||||
## This requires building nim with `-d:nimHasLibFFI`
|
||||
## which itself requires `nimble install libffi`, see #10150
|
||||
## which itself requires `koch installdeps libffi`, see #10150
|
||||
## Note: this feature can't be localized with {.push.}
|
||||
vmopsDanger,
|
||||
strictFuncs,
|
||||
@@ -219,7 +220,9 @@ type
|
||||
unicodeOperators, # deadcode
|
||||
flexibleOptionalParams,
|
||||
strictDefs,
|
||||
strictCaseObjects
|
||||
strictCaseObjects,
|
||||
inferGenericTypes
|
||||
noforwardDecl
|
||||
|
||||
LegacyFeature* = enum
|
||||
allowSemcheckedAstModification,
|
||||
@@ -232,6 +235,7 @@ type
|
||||
## are not anymore.
|
||||
laxEffects
|
||||
## Lax effects system prior to Nim 2.0.
|
||||
verboseTypeMismatch
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
|
||||
@@ -276,6 +280,9 @@ type
|
||||
scope*, localUsages*, globalUsages*: int # more usages is better
|
||||
tokenLen*: int
|
||||
version*: int
|
||||
endLine*: uint16
|
||||
endCol*: int
|
||||
|
||||
Suggestions* = seq[Suggest]
|
||||
|
||||
ProfileInfo* = object
|
||||
@@ -329,6 +336,7 @@ type
|
||||
|
||||
cppDefines*: HashSet[string] # (*)
|
||||
headerFile*: string
|
||||
nimbasePattern*: string # pattern to find nimbase.h
|
||||
features*: set[Feature]
|
||||
legacyFeatures*: set[LegacyFeature]
|
||||
arguments*: string ## the arguments to be passed to the program that
|
||||
@@ -406,8 +414,15 @@ type
|
||||
nimMainPrefix*: string
|
||||
vmProfileData*: ProfileData
|
||||
|
||||
expandProgress*: bool
|
||||
expandLevels*: int
|
||||
expandNodeResult*: string
|
||||
expandPosition*: TLineInfo
|
||||
|
||||
|
||||
proc parseNimVersion*(a: string): NimVer =
|
||||
# could be moved somewhere reusable
|
||||
result = default(NimVer)
|
||||
if a.len > 0:
|
||||
let b = a.split(".")
|
||||
assert b.len == 3, a
|
||||
@@ -457,7 +472,7 @@ when false:
|
||||
fn(globalOptions)
|
||||
fn(selectedGC)
|
||||
|
||||
const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel}
|
||||
const oldExperimentalFeatures* = {dotOperators, callOperator, parallel}
|
||||
|
||||
const
|
||||
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck,
|
||||
@@ -468,7 +483,8 @@ const
|
||||
optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck,
|
||||
optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs`
|
||||
optTrMacros, optStyleCheck, optCursorInference}
|
||||
DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace}
|
||||
DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace,
|
||||
optJsBigInt64}
|
||||
|
||||
proc getSrcTimestamp(): DateTime =
|
||||
try:
|
||||
@@ -610,7 +626,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||
osQnx, osAtari, osAix,
|
||||
osHaiku, osVxWorks, osSolaris, osNetbsd,
|
||||
osFreebsd, osOpenbsd, osDragonfly, osMacosx, osIos,
|
||||
osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos, osZephyr}
|
||||
osAndroid, osNintendoSwitch, osFreeRTOS, osCrossos, osZephyr, osNuttX}
|
||||
of "linux":
|
||||
result = conf.target.targetOS in {osLinux, osAndroid}
|
||||
of "bsd":
|
||||
@@ -632,6 +648,8 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||
result = conf.target.targetOS == osFreeRTOS
|
||||
of "zephyr":
|
||||
result = conf.target.targetOS == osZephyr
|
||||
of "nuttx":
|
||||
result = conf.target.targetOS == osNuttX
|
||||
of "littleendian": result = CPU[conf.target.targetCPU].endian == littleEndian
|
||||
of "bigendian": result = CPU[conf.target.targetCPU].endian == bigEndian
|
||||
of "cpu8": result = CPU[conf.target.targetCPU].bit == 8
|
||||
@@ -641,12 +659,12 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||
of "nimrawsetjmp":
|
||||
result = conf.target.targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd,
|
||||
osDragonfly, osMacosx}
|
||||
else: discard
|
||||
else: result = false
|
||||
|
||||
template quitOrRaise*(conf: ConfigRef, msg = "") =
|
||||
# xxx in future work, consider whether to also intercept `msgQuit` calls
|
||||
if conf.isDefined("nimDebug"):
|
||||
doAssert false, msg
|
||||
raiseAssert msg
|
||||
else:
|
||||
quit(msg) # quits with QuitFailure
|
||||
|
||||
@@ -706,22 +724,24 @@ proc getPrefixDir*(conf: ConfigRef): AbsoluteDir =
|
||||
## clone or using installed nim, so that these exist: `result/doc/advopt.txt`
|
||||
## and `result/lib/system.nim`
|
||||
if not conf.prefixDir.isEmpty: result = conf.prefixDir
|
||||
else: result = AbsoluteDir splitPath(getAppDir()).head
|
||||
else:
|
||||
let binParent = AbsoluteDir splitPath(getAppDir()).head
|
||||
when defined(posix):
|
||||
if binParent == AbsoluteDir"/usr":
|
||||
result = AbsoluteDir"/usr/lib/nim"
|
||||
elif binParent == AbsoluteDir"/usr/local":
|
||||
result = AbsoluteDir"/usr/local/lib/nim"
|
||||
else:
|
||||
result = binParent
|
||||
else:
|
||||
result = binParent
|
||||
|
||||
proc setDefaultLibpath*(conf: ConfigRef) =
|
||||
# set default value (can be overwritten):
|
||||
if conf.libpath.isEmpty:
|
||||
# choose default libpath:
|
||||
var prefix = getPrefixDir(conf)
|
||||
when defined(posix):
|
||||
if prefix == AbsoluteDir"/usr":
|
||||
conf.libpath = AbsoluteDir"/usr/lib/nim"
|
||||
elif prefix == AbsoluteDir"/usr/local":
|
||||
conf.libpath = AbsoluteDir"/usr/local/lib/nim"
|
||||
else:
|
||||
conf.libpath = prefix / RelativeDir"lib"
|
||||
else:
|
||||
conf.libpath = prefix / RelativeDir"lib"
|
||||
conf.libpath = prefix / RelativeDir"lib"
|
||||
|
||||
# Special rule to support other tools (nimble) which import the compiler
|
||||
# modules and make use of them.
|
||||
@@ -851,27 +871,21 @@ template patchModule(conf: ConfigRef) {.dirty.} =
|
||||
let ov = conf.moduleOverrides[key]
|
||||
if ov.len > 0: result = AbsoluteFile(ov)
|
||||
|
||||
when (NimMajor, NimMinor) < (1, 1) or not declared(isRelativeTo):
|
||||
proc isRelativeTo(path, base: string): bool =
|
||||
# pending #13212 use os.isRelativeTo
|
||||
let path = path.normalizedPath
|
||||
let base = base.normalizedPath
|
||||
let ret = relativePath(path, base)
|
||||
result = path.len > 0 and not ret.startsWith ".."
|
||||
|
||||
const stdlibDirs* = [
|
||||
"pure", "core", "arch",
|
||||
"pure/collections",
|
||||
"pure/concurrency",
|
||||
"pure/unidecode", "impure",
|
||||
"wrappers", "wrappers/linenoise",
|
||||
"windows", "posix", "js"]
|
||||
"windows", "posix", "js",
|
||||
"deprecated/pure"]
|
||||
|
||||
const
|
||||
pkgPrefix = "pkg/"
|
||||
stdPrefix = "std/"
|
||||
|
||||
proc getRelativePathFromConfigPath*(conf: ConfigRef; f: AbsoluteFile, isTitle = false): RelativeFile =
|
||||
result = RelativeFile("")
|
||||
let f = $f
|
||||
if isTitle:
|
||||
for dir in stdlibDirs:
|
||||
@@ -902,10 +916,12 @@ proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): AbsoluteFile
|
||||
proc findModule*(conf: ConfigRef; modulename, currentModule: string): AbsoluteFile =
|
||||
# returns path to module
|
||||
var m = addFileExt(modulename, NimExt)
|
||||
var hasRelativeDot = false
|
||||
if m.startsWith(pkgPrefix):
|
||||
result = findFile(conf, m.substr(pkgPrefix.len), suppressStdlib = true)
|
||||
else:
|
||||
if m.startsWith(stdPrefix):
|
||||
result = AbsoluteFile("")
|
||||
let stripped = m.substr(stdPrefix.len)
|
||||
for candidate in stdlibDirs:
|
||||
let path = (conf.libpath.string / candidate / stripped)
|
||||
@@ -915,7 +931,11 @@ proc findModule*(conf: ConfigRef; modulename, currentModule: string): AbsoluteFi
|
||||
else: # If prefixed with std/ why would we add the current module path!
|
||||
let currentPath = currentModule.splitFile.dir
|
||||
result = AbsoluteFile currentPath / m
|
||||
if not fileExists(result):
|
||||
if m.startsWith('.') and not fileExists(result):
|
||||
result = AbsoluteFile ""
|
||||
hasRelativeDot = true
|
||||
|
||||
if not fileExists(result) and not hasRelativeDot:
|
||||
result = findFile(conf, m)
|
||||
patchModule(conf)
|
||||
|
||||
@@ -993,6 +1013,12 @@ proc isDynlibOverride*(conf: ConfigRef; lib: string): bool =
|
||||
result = optDynlibOverrideAll in conf.globalOptions or
|
||||
conf.dllOverrides.hasKey(lib.canonDynlibName)
|
||||
|
||||
proc showNonExportedFields*(conf: ConfigRef) =
|
||||
incl(conf.globalOptions, optShowNonExportedFields)
|
||||
|
||||
proc expandDone*(conf: ConfigRef): bool =
|
||||
result = conf.ideCmd == ideExpand and conf.expandLevels == 0 and conf.expandProgress
|
||||
|
||||
proc parseIdeCmd*(s: string): IdeCmd =
|
||||
case s:
|
||||
of "sug": ideSug
|
||||
@@ -1032,6 +1058,7 @@ proc `$`*(c: IdeCmd): string =
|
||||
of ideProject: "project"
|
||||
of ideGlobalSymbols: "globalSymbols"
|
||||
of ideDeclaration: "declaration"
|
||||
of ideExpand: "expand"
|
||||
of ideRecompile: "recompile"
|
||||
of ideChanged: "changed"
|
||||
of ideType: "type"
|
||||
|
||||
@@ -17,6 +17,7 @@ iterator myParentDirs(p: string): string =
|
||||
|
||||
proc getNimbleFile*(conf: ConfigRef; path: string): string =
|
||||
## returns absolute path to nimble file, e.g.: /pathto/cligen.nimble
|
||||
result = ""
|
||||
var parents = 0
|
||||
block packageSearch:
|
||||
for d in myParentDirs(path):
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
|
||||
## Package related procs.
|
||||
##
|
||||
##
|
||||
## See Also:
|
||||
## * `packagehandling` for package path handling
|
||||
## * `modulegraphs.getPackage`
|
||||
@@ -22,7 +22,7 @@ when defined(nimPreviewSlimSystem):
|
||||
|
||||
proc getPackage*(conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym =
|
||||
## Return a new package symbol.
|
||||
##
|
||||
##
|
||||
## See Also:
|
||||
## * `modulegraphs.getPackage`
|
||||
let
|
||||
@@ -31,7 +31,7 @@ proc getPackage*(conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym =
|
||||
info = newLineInfo(fileIdx, 1, 1)
|
||||
pkgName = getPackageName(conf, filename.string)
|
||||
pkgIdent = getIdent(cache, pkgName)
|
||||
newSym(skPackage, pkgIdent, ItemId(module: PackageModuleId, item: int32(fileIdx)), nil, info)
|
||||
newSym(skPackage, pkgIdent, idGeneratorForPackage(int32(fileIdx)), nil, info)
|
||||
|
||||
func getPackageSymbol*(sym: PSym): PSym =
|
||||
## Return the owning package symbol.
|
||||
@@ -47,7 +47,7 @@ func getPackageId*(sym: PSym): int =
|
||||
|
||||
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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user