mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-01 03:13:41 +00:00
Compare commits
571 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7a8fc46c0 | ||
|
|
5b43c98897 | ||
|
|
f388817a79 | ||
|
|
b865c2a54b | ||
|
|
6e681b546f | ||
|
|
2565d3d102 | ||
|
|
39185b46ca | ||
|
|
e0f2b3ba8f | ||
|
|
b04ef2973d | ||
|
|
be82d11576 | ||
|
|
c2fced129f | ||
|
|
5abe880469 | ||
|
|
9776f926a2 | ||
|
|
908b553215 | ||
|
|
96b3bae99b | ||
|
|
a404ec540a | ||
|
|
dea9e38d26 | ||
|
|
c623ab62cc | ||
|
|
f576df2bcc | ||
|
|
05e80e1cda | ||
|
|
7839658323 | ||
|
|
1b20f768c7 | ||
|
|
38ab51c445 | ||
|
|
7bc5bf8334 | ||
|
|
04c803d6df | ||
|
|
162d74db91 | ||
|
|
363d0ada50 | ||
|
|
a948deebb3 | ||
|
|
188ce5f3ee | ||
|
|
f8000d4ba1 | ||
|
|
48537fec81 | ||
|
|
638a4d9d9f | ||
|
|
93f74e4f93 | ||
|
|
910ed5888e | ||
|
|
618316beb9 | ||
|
|
ea8a049af3 | ||
|
|
c9f3a8b269 | ||
|
|
f1b7c0494e | ||
|
|
62aa1a3cfe | ||
|
|
77c6425e65 | ||
|
|
754531fff3 | ||
|
|
059a16b34d | ||
|
|
2a59f499e9 | ||
|
|
6c487a6309 | ||
|
|
8b4c17a140 | ||
|
|
3f87453981 | ||
|
|
1c03604ec6 | ||
|
|
fd63443419 | ||
|
|
5018e7f304 | ||
|
|
ee6df5bd24 | ||
|
|
d79fb77974 | ||
|
|
eb241f4241 | ||
|
|
ca7bf3be8b | ||
|
|
5b923cd149 | ||
|
|
5783cd67a8 | ||
|
|
e134a722de | ||
|
|
8c81cddf7e | ||
|
|
560eef5bbe | ||
|
|
944bab4c3c | ||
|
|
5a520a8454 | ||
|
|
33b8a00aa8 | ||
|
|
c55ceafd9a | ||
|
|
99425ff21d | ||
|
|
ee36931f26 | ||
|
|
cf99c9bfb5 | ||
|
|
d363eced3a | ||
|
|
1fa1024ddf | ||
|
|
58077450cc | ||
|
|
5d9c1544bf | ||
|
|
60911304b4 | ||
|
|
81c23bba7b | ||
|
|
92f2d68802 | ||
|
|
ed1d41c51e | ||
|
|
aa95ae6af9 | ||
|
|
f915064e07 | ||
|
|
e5139b0662 | ||
|
|
18135cc194 | ||
|
|
790f5bac01 | ||
|
|
3255b55266 | ||
|
|
8362d92e47 | ||
|
|
4bbafb47dc | ||
|
|
3eb89481cb | ||
|
|
4129993689 | ||
|
|
5a8fddf29b | ||
|
|
e0f3e8432a | ||
|
|
0e01a5f76c | ||
|
|
24f52d855c | ||
|
|
32769c478b | ||
|
|
8397554315 | ||
|
|
40c5175145 | ||
|
|
488f3ed085 | ||
|
|
0882a09986 | ||
|
|
49f63d3aae | ||
|
|
a5e2db2ac5 | ||
|
|
58bcf6cd46 | ||
|
|
c2ba0ee144 | ||
|
|
92c012d86d | ||
|
|
a9c7fb2fcc | ||
|
|
fa5707e7e2 | ||
|
|
cb0450398a | ||
|
|
07a986afa1 | ||
|
|
ea1a26294f | ||
|
|
459fbb9525 | ||
|
|
4972d797e4 | ||
|
|
35f1519ad6 | ||
|
|
79f1b8592a | ||
|
|
ac6fcab7a4 | ||
|
|
d70e292571 | ||
|
|
5a03eea518 | ||
|
|
545ddf4a4f | ||
|
|
f8f96d816c | ||
|
|
7ef85db9a9 | ||
|
|
18ca1788f0 | ||
|
|
fc7fe636e2 | ||
|
|
23c44f009a | ||
|
|
3d4ad9739c | ||
|
|
ba18c12005 | ||
|
|
755c4428fe | ||
|
|
2396f0ee71 | ||
|
|
e765687646 | ||
|
|
e6ec88d4c3 | ||
|
|
ad82e65387 | ||
|
|
ab48d7901e | ||
|
|
35268c500f | ||
|
|
6e01be34ef | ||
|
|
326a333c8b | ||
|
|
15213028b7 | ||
|
|
2b565aad89 | ||
|
|
a6428657e9 | ||
|
|
efe1bed82e | ||
|
|
a388c35741 | ||
|
|
a055f628f4 | ||
|
|
9ae0dd611f | ||
|
|
f9600b7207 | ||
|
|
82d5e773e3 | ||
|
|
25581c796f | ||
|
|
029dcc6259 | ||
|
|
2a3b056314 | ||
|
|
d0e5bd2305 | ||
|
|
9203d3a982 | ||
|
|
cd106cf680 | ||
|
|
5f7a6aff06 | ||
|
|
21fc8b4d4d | ||
|
|
42d2e68bca | ||
|
|
c9f49cbc0a | ||
|
|
84351da9d8 | ||
|
|
d4af0554c4 | ||
|
|
20dec10722 | ||
|
|
eaebbfa785 | ||
|
|
d564130a3b | ||
|
|
eff0837ff4 | ||
|
|
00d46ca1c0 | ||
|
|
114da04cbb | ||
|
|
d8177a3980 | ||
|
|
8df745a42e | ||
|
|
3f5599b344 | ||
|
|
329e169e96 | ||
|
|
def6234903 | ||
|
|
66a8856152 | ||
|
|
ab8241ad42 | ||
|
|
1ccff0324c | ||
|
|
ddc155af64 | ||
|
|
b044523c5a | ||
|
|
5a9edb222b | ||
|
|
97d77bf37e | ||
|
|
0c41fd0f50 | ||
|
|
d8d2a9e985 | ||
|
|
8117a949c5 | ||
|
|
ae9bb4474b | ||
|
|
88814bbe98 | ||
|
|
931ee0ca82 | ||
|
|
5df7d72afe | ||
|
|
73dd73f961 | ||
|
|
ce7f29e8e6 | ||
|
|
f2e8c39e85 | ||
|
|
547fcd69c3 | ||
|
|
c3c5839329 | ||
|
|
fbb2763204 | ||
|
|
b07694cd90 | ||
|
|
2212a90458 | ||
|
|
e1539c7344 | ||
|
|
806f3b592f | ||
|
|
f28a47ea7b | ||
|
|
9aad99bdfd | ||
|
|
085fbcea6f | ||
|
|
9eee15f668 | ||
|
|
170cb4f4cb | ||
|
|
a562de2d91 | ||
|
|
2b2efe3dbe | ||
|
|
5304b16a55 | ||
|
|
4264e9576d | ||
|
|
d00c8febee | ||
|
|
b1b0960c36 | ||
|
|
75baaa5e25 | ||
|
|
ceb742351a | ||
|
|
cf4390a24a | ||
|
|
742862b847 | ||
|
|
ac7a365137 | ||
|
|
d5840e1e3d | ||
|
|
7cb31455ee | ||
|
|
b68380f09b | ||
|
|
db9e27dffd | ||
|
|
cf09ef47b8 | ||
|
|
15e681ce66 | ||
|
|
721ca3e830 | ||
|
|
39f4a3e418 | ||
|
|
b9dd972c32 | ||
|
|
7023241aaf | ||
|
|
bebda3851f | ||
|
|
c7e77edecc | ||
|
|
ba577c7e1b | ||
|
|
cf22dec584 | ||
|
|
1fb9a6d946 | ||
|
|
d31404ac27 | ||
|
|
922e2a5098 | ||
|
|
511298242d | ||
|
|
296dfae8af | ||
|
|
b095203f28 | ||
|
|
630e18a6eb | ||
|
|
a25d43ca6b | ||
|
|
65ed2d7fe8 | ||
|
|
e6cb7e34ef | ||
|
|
5ef62fcb25 | ||
|
|
1874b3e786 | ||
|
|
83397a69fc | ||
|
|
433613e267 | ||
|
|
322ce1872f | ||
|
|
289b5e9ef9 | ||
|
|
c9c28bf85e | ||
|
|
da64c8762f | ||
|
|
212ae2f125 | ||
|
|
0e4a8bfb28 | ||
|
|
da37177ac2 | ||
|
|
3b8f721460 | ||
|
|
082c440f13 | ||
|
|
81ddc67785 | ||
|
|
04708742e7 | ||
|
|
e3c0bf48c5 | ||
|
|
0d5bd7e8b5 | ||
|
|
44e7a7b6c2 | ||
|
|
fda51b6ca2 | ||
|
|
756fabb979 | ||
|
|
48968f3c84 | ||
|
|
addd7b5e20 | ||
|
|
c8cffaf420 | ||
|
|
c0d240b8cd | ||
|
|
f34ae81971 | ||
|
|
9321b33cd2 | ||
|
|
afbcd1b330 | ||
|
|
8407a57499 | ||
|
|
3d7d5cf121 | ||
|
|
ce148e71ef | ||
|
|
42e83ac24c | ||
|
|
d208d7a995 | ||
|
|
61c66abbfe | ||
|
|
7024bb800c | ||
|
|
65d1140d11 | ||
|
|
b73d097d36 | ||
|
|
343ace8194 | ||
|
|
51d998390c | ||
|
|
df32c45757 | ||
|
|
bcfb540e57 | ||
|
|
50e921bb94 | ||
|
|
a906b3952b | ||
|
|
829f719670 | ||
|
|
803406d07c | ||
|
|
bb949a75db | ||
|
|
ceb1a1b688 | ||
|
|
f58d87cb43 | ||
|
|
c9c8fa99cc | ||
|
|
b9c15371a3 | ||
|
|
f7c99838e2 | ||
|
|
25e6c53bb5 | ||
|
|
1a77040278 | ||
|
|
2fdba334da | ||
|
|
4c73139316 | ||
|
|
95856ab8d3 | ||
|
|
d7bc4e43a2 | ||
|
|
3bb6d1916e | ||
|
|
3ccda773d6 | ||
|
|
13190435a6 | ||
|
|
44aadd50cf | ||
|
|
5484352d26 | ||
|
|
8c93c692b9 | ||
|
|
30f2cec671 | ||
|
|
46f2271968 | ||
|
|
d563efb719 | ||
|
|
67a6effb7b | ||
|
|
affe1be47c | ||
|
|
dc38b88f7e | ||
|
|
1868cbc449 | ||
|
|
5a020d641d | ||
|
|
313cc337f2 | ||
|
|
de69e1856f | ||
|
|
70e8551e37 | ||
|
|
903d06bab8 | ||
|
|
a5d6080a81 | ||
|
|
fbb0642e27 | ||
|
|
9852cf804b | ||
|
|
6d8913ee14 | ||
|
|
7deb49e992 | ||
|
|
5b7273b4f8 | ||
|
|
4becd5a2a8 | ||
|
|
07d465ca42 | ||
|
|
4137a4dbf3 | ||
|
|
f50e4500c2 | ||
|
|
745669ac25 | ||
|
|
d40872bf9b | ||
|
|
404b224945 | ||
|
|
210988c532 | ||
|
|
1acb9bae94 | ||
|
|
e11494f1cf | ||
|
|
326860e84c | ||
|
|
15d2a92be0 | ||
|
|
bae08d0961 | ||
|
|
43940294c5 | ||
|
|
44d80dd863 | ||
|
|
3f7142fcfd | ||
|
|
0b511b15ea | ||
|
|
dcbb2d66da | ||
|
|
1f32498a47 | ||
|
|
102b71f42e | ||
|
|
8550a8127c | ||
|
|
76f9ddb6ab | ||
|
|
ec9d0ee86d | ||
|
|
8513f50a8d | ||
|
|
dd7dd1b6dc | ||
|
|
ad67a46e5d | ||
|
|
52cbd0c558 | ||
|
|
edbe02b4e1 | ||
|
|
df53c68a36 | ||
|
|
58e0dad371 | ||
|
|
e06046ab51 | ||
|
|
fab70e4fe3 | ||
|
|
44c12d9d20 | ||
|
|
9db369063c | ||
|
|
a59fb5b352 | ||
|
|
cf36e4a44a | ||
|
|
de1ede77fe | ||
|
|
d55cc0888d | ||
|
|
423e8cca91 | ||
|
|
416ba133ad | ||
|
|
bb5ca0772e | ||
|
|
f45a1b927a | ||
|
|
03ded27021 | ||
|
|
2895ad70c8 | ||
|
|
38b836b49e | ||
|
|
7606efc0bf | ||
|
|
6d125da93f | ||
|
|
13253f4154 | ||
|
|
5bf3734984 | ||
|
|
974362c98f | ||
|
|
fd24a8923e | ||
|
|
eaf4b42ff9 | ||
|
|
511b6ae27c | ||
|
|
2f0a50fa51 | ||
|
|
3d88d06b32 | ||
|
|
b8be1ccb85 | ||
|
|
ac458448d8 | ||
|
|
cb3c3c306c | ||
|
|
38bdf1cd7f | ||
|
|
b2f9447896 | ||
|
|
87a2ced1ba | ||
|
|
73cc029fec | ||
|
|
dc0bbba3fa | ||
|
|
78174857f8 | ||
|
|
b03421d087 | ||
|
|
bc7733827d | ||
|
|
6663dbbe57 | ||
|
|
e5425b5f2f | ||
|
|
c94647aeca | ||
|
|
96523cdd3e | ||
|
|
18182e4bfd | ||
|
|
ff4a9a226f | ||
|
|
bd689849f2 | ||
|
|
c6c9e30379 | ||
|
|
7a39eb13a5 | ||
|
|
2255d8795b | ||
|
|
55e8aefbea | ||
|
|
73c570d1d9 | ||
|
|
ad58ed344a | ||
|
|
eb059fa848 | ||
|
|
a85e20c125 | ||
|
|
fa982b43f0 | ||
|
|
96d49608c0 | ||
|
|
eefcea8892 | ||
|
|
fc34193483 | ||
|
|
0193c8ad2e | ||
|
|
7993d61d00 | ||
|
|
2c2f2de614 | ||
|
|
f64179e7fe | ||
|
|
7c62de0cb7 | ||
|
|
11dad688fe | ||
|
|
063ae96a66 | ||
|
|
5ddea6a98f | ||
|
|
5fce81edfd | ||
|
|
6375df4c53 | ||
|
|
b80d70b0f3 | ||
|
|
a6526695f0 | ||
|
|
b50ae6817a | ||
|
|
124a584eb2 | ||
|
|
655cb08461 | ||
|
|
9e7d885f35 | ||
|
|
d0616ed115 | ||
|
|
085a21ebf4 | ||
|
|
bab1f67971 | ||
|
|
6a7f8e8ab5 | ||
|
|
3258c1e2a3 | ||
|
|
465815e894 | ||
|
|
6ce6bce12e | ||
|
|
d2684cdfd2 | ||
|
|
cab0c3e544 | ||
|
|
64e1408920 | ||
|
|
2678fa679a | ||
|
|
02b9af2f75 | ||
|
|
25cd8a5490 | ||
|
|
34c09a98c7 | ||
|
|
7d5d9f7703 | ||
|
|
176eaf5c90 | ||
|
|
d1f6c820dd | ||
|
|
2c0c0e772c | ||
|
|
96a19ea1b4 | ||
|
|
95f2f2396f | ||
|
|
28c9c062a4 | ||
|
|
b64dd795b1 | ||
|
|
5f515410af | ||
|
|
d914dca513 | ||
|
|
0a501932c2 | ||
|
|
dad3c40f55 | ||
|
|
4450fca6fd | ||
|
|
a59f0adc50 | ||
|
|
7d29f8b1a4 | ||
|
|
64168d4aea | ||
|
|
0718d6c2cd | ||
|
|
045eeab6b4 | ||
|
|
0ca71dd92c | ||
|
|
1e9316e23c | ||
|
|
c0db1705dc | ||
|
|
476b4ff372 | ||
|
|
a157c2baef | ||
|
|
20d0ef8afb | ||
|
|
0a1cb631a2 | ||
|
|
ab6dec6e90 | ||
|
|
71b7383f12 | ||
|
|
c522a455df | ||
|
|
cce8a739da | ||
|
|
766960dc15 | ||
|
|
9b949855c7 | ||
|
|
2c10b246ec | ||
|
|
bd55c862a6 | ||
|
|
c352892232 | ||
|
|
413dff03a0 | ||
|
|
a5686961bd | ||
|
|
d7a7662a7f | ||
|
|
dd39b11b13 | ||
|
|
d37c4e44d3 | ||
|
|
e259f80fc7 | ||
|
|
7113c1e931 | ||
|
|
3606e035f5 | ||
|
|
7ddb31262e | ||
|
|
5be5bf0222 | ||
|
|
284a8cb58a | ||
|
|
d72edfb14b | ||
|
|
765ff4b67b | ||
|
|
17bbce7c8a | ||
|
|
d9604d7d0b | ||
|
|
bab83c4d8b | ||
|
|
f36a61e6d4 | ||
|
|
fb878330a9 | ||
|
|
135fdde6a9 | ||
|
|
19b142401c | ||
|
|
48cbf1c496 | ||
|
|
ce2777af5a | ||
|
|
f65eaa51f1 | ||
|
|
e083a1533b | ||
|
|
326e3ad09d | ||
|
|
b6fb47df77 | ||
|
|
f288e1b11a | ||
|
|
0a81b038fd | ||
|
|
993b3909a8 | ||
|
|
b7f8031e98 | ||
|
|
206f2478b8 | ||
|
|
0f868b587b | ||
|
|
2f1a1b7106 | ||
|
|
0d50b0c8a7 | ||
|
|
91f0626dcb | ||
|
|
181350f6c9 | ||
|
|
2a7cf71db3 | ||
|
|
403fd3ac43 | ||
|
|
e9a23cee0a | ||
|
|
436f570651 | ||
|
|
e90d91f0e4 | ||
|
|
800bc661b6 | ||
|
|
bb9b60604b | ||
|
|
b81fd958d1 | ||
|
|
3d50f7e2a1 | ||
|
|
79c721d418 | ||
|
|
0db3c670ac | ||
|
|
35df59b3ce | ||
|
|
12eebf48b6 | ||
|
|
a4c613c110 | ||
|
|
23e95dc629 | ||
|
|
d6b0e46ee4 | ||
|
|
45bbf1ef5b | ||
|
|
55da84e141 | ||
|
|
f310cf5250 | ||
|
|
280193cc07 | ||
|
|
7e4748beee | ||
|
|
bc9fb4885b | ||
|
|
678beb8ef9 | ||
|
|
6adcc09877 | ||
|
|
c83914b435 | ||
|
|
50afafdb38 | ||
|
|
af10788dcc | ||
|
|
16d81fa205 | ||
|
|
96bed814d2 | ||
|
|
0adb1c6223 | ||
|
|
c65a5d754b | ||
|
|
1a074fffa4 | ||
|
|
ab36ffbeb1 | ||
|
|
ff89f7e33a | ||
|
|
de88fdb86e | ||
|
|
ae5a4cea98 | ||
|
|
cf47c2c60c | ||
|
|
24ac13f653 | ||
|
|
f67be92512 | ||
|
|
296c48de5e | ||
|
|
79a23fe805 | ||
|
|
7c637c2faf | ||
|
|
8ee0f14ab6 | ||
|
|
c99ce5051e | ||
|
|
38f05bb9a3 | ||
|
|
a009cbdc2f | ||
|
|
c8268330be | ||
|
|
ac3449b93b | ||
|
|
6cad5c7861 | ||
|
|
b70fd0400e | ||
|
|
eb087b3546 | ||
|
|
aa7f23e1ee | ||
|
|
9f6187b46c | ||
|
|
7182922622 | ||
|
|
eadea343ef | ||
|
|
6dc6487311 | ||
|
|
68cce40510 | ||
|
|
d1ce86fdc6 | ||
|
|
e96afd6324 | ||
|
|
c656714623 | ||
|
|
57a83df745 | ||
|
|
80320c72d3 | ||
|
|
bda9fd149c | ||
|
|
e11d582fa1 | ||
|
|
e7188cdfa8 | ||
|
|
06ef56ba72 | ||
|
|
e2f99a2026 | ||
|
|
165ea46284 | ||
|
|
af39f26a3a | ||
|
|
b70295c768 | ||
|
|
08fdffc717 | ||
|
|
73c44c6e9b | ||
|
|
bde899d4f8 | ||
|
|
da035e9c83 | ||
|
|
b056d32a79 | ||
|
|
e4d0f4fee0 | ||
|
|
c07973e313 | ||
|
|
549d8cc0c6 | ||
|
|
572b7c37a5 | ||
|
|
c7e1c665a1 | ||
|
|
3d13103443 | ||
|
|
a9aef65b2d | ||
|
|
b3d2cd738a | ||
|
|
7cfc7cfb26 |
@@ -56,6 +56,7 @@ addons:
|
||||
- boehmgc
|
||||
- make
|
||||
- sfml
|
||||
update: true
|
||||
|
||||
install:
|
||||
- if [[ $CPU = i386 ]]; then echo -e "#!/bin/bash\n$(which gcc) -m32 \"\$@\"" > bin/gcc; fi
|
||||
|
||||
29
appveyor.yml
29
appveyor.yml
@@ -1,14 +1,11 @@
|
||||
version: '{build}'
|
||||
|
||||
environment:
|
||||
DLLS_URL: https://nim-lang.org/download/dlls.zip
|
||||
DLLS_ARCHIVE: dlls.zip
|
||||
MINGW_DIR: mingw64
|
||||
MINGW_URL: https://nim-lang.org/download/mingw64-6.3.0.7z
|
||||
MINGW_ARCHIVE: mingw64-6.3.0.7z
|
||||
OPENBLAS_URL: https://sourceforge.net/projects/openblas/files/v0.3.5/OpenBLAS%200.3.5%20version.zip/download
|
||||
OPENBLAS_ARCHIVE: OpenBLAS-0.3.5.zip
|
||||
SQLITE_URL: http://www.sqlite.org/2017/sqlite-dll-win64-x64-3160200.zip
|
||||
SQLITE_ARCHIVE: sqlite-dll-win64-x64-3160200.zip
|
||||
platform: x64
|
||||
|
||||
matrix:
|
||||
- NIM_TEST_PACKAGES: false
|
||||
@@ -16,33 +13,19 @@ environment:
|
||||
|
||||
cache:
|
||||
- '%MINGW_ARCHIVE%'
|
||||
- '%SQLITE_ARCHIVE%'
|
||||
- '%OPENBLAS_ARCHIVE%'
|
||||
- '%DLLS_ARCHIVE%'
|
||||
|
||||
matrix:
|
||||
#allow_failures:
|
||||
# - NIM_TEST_PACKAGES: true
|
||||
fast_finish: true
|
||||
|
||||
install:
|
||||
- ps: Install-Product node 8 # node 8 or later is required to test js async stuff
|
||||
- MKDIR %CD%\DIST
|
||||
- MKDIR %CD%\DIST\PCRE
|
||||
- nuget install pcre -Verbosity quiet -Version 8.33.0.1 -OutputDirectory %CD%\DIST\PCRE
|
||||
- IF not exist "%SQLITE_ARCHIVE%" appveyor DownloadFile "%SQLITE_URL%" -FileName "%SQLITE_ARCHIVE%"
|
||||
- 7z x -y "%SQLITE_ARCHIVE%" -o"%CD%\DIST"> nul
|
||||
- IF not exist "%DLLS_ARCHIVE%" appveyor DownloadFile "%DLLS_URL%" -FileName "%DLLS_ARCHIVE%"
|
||||
- 7z x -y "%DLLS_ARCHIVE%" -o"%CD%\BIN"> nul
|
||||
- IF not exist "%MINGW_ARCHIVE%" appveyor DownloadFile "%MINGW_URL%" -FileName "%MINGW_ARCHIVE%"
|
||||
- 7z x -y "%MINGW_ARCHIVE%" -o"%CD%\DIST"> nul
|
||||
- IF not exist "%OPENBLAS_ARCHIVE%" appveyor DownloadFile "%OPENBLAS_URL%" -FileName "%OPENBLAS_ARCHIVE%"
|
||||
- 7z x -y "%OPENBLAS_ARCHIVE%" -o"%CD%\DIST"> nul
|
||||
- SET PATH=%CD%\DIST\%MINGW_DIR%\BIN;%CD%\BIN;%PATH%
|
||||
- IF "%PLATFORM%" == "x64" ( copy C:\OpenSSL-Win64\libeay32.dll %CD%\BIN\libeay64.dll & copy C:\OpenSSL-Win64\libeay32.dll %CD%\BIN\libeay32.dll & copy C:\OpenSSL-Win64\libssl32.dll %CD%\BIN\libssl64.dll & copy C:\OpenSSL-Win64\libssl32.dll %CD%\BIN\libssl32.dll )
|
||||
ELSE ( copy C:\OpenSSL-Win32\libeay32.dll %CD%\BIN\libeay32.dll & copy C:\OpenSSL-Win32\libssl32.dll %CD%\BIN\libssl32.dll )
|
||||
- IF "%PLATFORM%" == "x64" ( copy %CD%\DIST\sqlite3.dll %CD%\BIN\sqlite3_64.dll ) ELSE ( copy %CD%\DIST\sqlite3.dll %CD%\BIN\sqlite3_32.dll )
|
||||
- IF "%PLATFORM%" == "x64" ( copy %CD%\DIST\PCRE\pcre.redist.8.33.0.1\build\native\bin\v100\x64\Release\dynamic\utf8\pcre8.dll %CD%\bin\pcre64.dll ) ELSE ( copy %CD%\DIST\PCRE\pcre.redist.8.33.0.1\build\native\bin\v100\Win32\Release\dynamic\utf8\pcre8.dll %CD%\bin\pcre32.dll )
|
||||
- git clone --depth 1 https://github.com/nim-lang/csources
|
||||
- cd csources
|
||||
- IF "%PLATFORM%" == "x64" ( build64.bat ) else ( build.bat )
|
||||
- build64.bat
|
||||
- cd ..
|
||||
|
||||
build_script:
|
||||
|
||||
42
changelog.md
42
changelog.md
@@ -1,25 +1,32 @@
|
||||
## v0.20.2 - XXXX-XX-XX
|
||||
# v1.1 - xxxx-xx-xx
|
||||
|
||||
|
||||
### Changes affecting backwards compatibility
|
||||
|
||||
|
||||
#### Breaking changes in the standard library
|
||||
|
||||
|
||||
#### Breaking changes in the compiler
|
||||
|
||||
|
||||
### Library additions
|
||||
|
||||
|
||||
### Library changes
|
||||
## Changes affecting backwards compatibility
|
||||
|
||||
|
||||
|
||||
### Language additions
|
||||
### Breaking changes in the standard library
|
||||
|
||||
|
||||
|
||||
### Breaking changes in the compiler
|
||||
|
||||
|
||||
|
||||
## Library additions
|
||||
|
||||
|
||||
|
||||
## Library changes
|
||||
|
||||
|
||||
|
||||
## Language additions
|
||||
|
||||
|
||||
|
||||
## Language changes
|
||||
|
||||
### Language changes
|
||||
|
||||
|
||||
### Tool changes
|
||||
@@ -30,4 +37,5 @@
|
||||
|
||||
|
||||
|
||||
### Bugfixes
|
||||
|
||||
## Bugfixes
|
||||
|
||||
55
changelogs/changelog_0_20_2.md
Normal file
55
changelogs/changelog_0_20_2.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# v0.20.2 - 2019-07-17
|
||||
|
||||
|
||||
## Changes affecting backwards compatibility
|
||||
|
||||
- All `strutils.rfind` procs now take `start` and `last` like `strutils.find`
|
||||
with the same data slice/index meaning. This is backwards compatible for
|
||||
calls *not* changing the `rfind` `start` parameter from its default. (#11487)
|
||||
|
||||
In the unlikely case that you were using `rfind X, start=N`, or `rfind X, N`,
|
||||
then you need to change that to `rfind X, last=N` or `rfind X, 0, N`. (This
|
||||
should minimize gotchas porting code from other languages like Python or C++.)
|
||||
|
||||
- On Windows stderr/stdout/stdin are not opened as binary files anymore. Use the switch
|
||||
`-d:nimBinaryStdFiles` for a transition period.
|
||||
|
||||
### Breaking changes in the standard library
|
||||
|
||||
- Mac OS X / BSD: TSa_Family is now the ``uint8`` type, so type
|
||||
conversions like ``x.sin_family = uint16 toInt(nativesockets.AF_INET)``
|
||||
need to be changed into ``x.sin_family = TSa_Family toInt(nativesockets.AF_INET)``.
|
||||
|
||||
|
||||
### Breaking changes in the compiler
|
||||
|
||||
|
||||
## Library additions
|
||||
|
||||
- `toOpenArray` is now available for the JS target.
|
||||
|
||||
## Library changes
|
||||
|
||||
- Fix async IO operations stalling even after socket is closed. (#11232)
|
||||
|
||||
- More informative error message for `streams.openFileStream`. (#11438)
|
||||
|
||||
|
||||
## Language additions
|
||||
|
||||
|
||||
## Language changes
|
||||
|
||||
|
||||
### Tool changes
|
||||
|
||||
|
||||
### Compiler changes
|
||||
|
||||
- Better error message for IndexError for empty containers. (#11476)
|
||||
|
||||
- Fix regression in semfold for old right shift. (#11477)
|
||||
|
||||
- Fix for passing tuples as static params to macros. (#11423)
|
||||
|
||||
## Bugfixes
|
||||
138
changelogs/changelog_1_0_0.md
Normal file
138
changelogs/changelog_1_0_0.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# v1.0 - 2019-09-23
|
||||
|
||||
|
||||
## Changes affecting backwards compatibility
|
||||
|
||||
- The switch ``-d:nimBinaryStdFiles`` does not exist anymore. Instead
|
||||
stdin/stdout/stderr are binary files again. This change only affects
|
||||
Windows.
|
||||
|
||||
- On Windows console applications the code-page is set at program startup
|
||||
to UTF-8. Use the new switch `-d:nimDontSetUtf8CodePage` to disable this
|
||||
feature.
|
||||
|
||||
- The language definition and compiler are now stricter about ``gensym``'ed
|
||||
symbols in hygienic templates. See the section in the
|
||||
[manual](https://nim-lang.org/docs/manual.html#templates-hygiene-in-templates)
|
||||
for further details. Use the compiler switch `--oldgensym:on` for a
|
||||
transition period.
|
||||
|
||||
|
||||
### Breaking changes in the standard library
|
||||
|
||||
- We removed `unicode.Rune16` without any deprecation period as the name
|
||||
was wrong (see the [RFC](https://github.com/nim-lang/RFCs/issues/151) for details)
|
||||
and we didn't find any usages of it in the wild. If you still need it, add this
|
||||
piece of code to your project:
|
||||
```nim
|
||||
type
|
||||
Rune16* = distinct int16
|
||||
```
|
||||
|
||||
- `exportc` now uses C instead of C++ mangling with `nim cpp`, matching behavior
|
||||
of `importc`, see #10578.
|
||||
Use the new `exportcpp` to mangle as C++ when using `nim cpp`.
|
||||
|
||||
|
||||
### Breaking changes in the compiler
|
||||
|
||||
- A bug allowing `int` to be implicitly converted to range types of smaller size
|
||||
(e.g `range[0'i8..10'i8]`) has been fixed.
|
||||
|
||||
|
||||
|
||||
## Library additions
|
||||
|
||||
- `encodings.getCurrentEncoding` now distinguishes between the console's
|
||||
encoding and the OS's encoding. This distinction is only meaningful on
|
||||
Windows.
|
||||
- Added `system.getOsFileHandle` which is usually more useful
|
||||
than `system.getFileHandle`. This distinction is only meaningful on
|
||||
Windows.
|
||||
- Added a `json.parseJsonFragments` iterator that can be used to speedup
|
||||
JSON processing substantially when there are JSON fragments separated
|
||||
by whitespace.
|
||||
|
||||
|
||||
|
||||
## Library changes
|
||||
|
||||
- Added `os.delEnv` and `nimscript.delEnv`. (#11466)
|
||||
|
||||
- Enabled Oid usage in hashtables. (#11472)
|
||||
|
||||
- Added `unsafeColumnAt` procs, that return unsafe cstring from InstantRow. (#11647)
|
||||
|
||||
- Make public `Sha1Digest` and `Sha1State` types and `newSha1State`,
|
||||
`update` and `finalize` procedures from `sha1` module. (#11694)
|
||||
|
||||
- Added the `std/monotimes` module which implements monotonic timestamps.
|
||||
|
||||
- Consistent error handling of two `exec` overloads. (#10967)
|
||||
|
||||
- Officially the following modules now have an unstable API:
|
||||
- std/varints
|
||||
- core/allocators
|
||||
- core/hotcodereloading
|
||||
- asyncstreams
|
||||
- base64
|
||||
- browsers
|
||||
- collections/rtarrays
|
||||
- collections/sharedlist
|
||||
- collections/sharedtable
|
||||
- concurrency/atomics
|
||||
- concurrency/cpuload
|
||||
- concurrency/threadpool
|
||||
- coro
|
||||
- endians
|
||||
- httpcore
|
||||
- parsesql
|
||||
- pathnorm
|
||||
- reservedmem
|
||||
- typetraits
|
||||
|
||||
Every other stdlib module is API stable with respect to version 1.
|
||||
|
||||
|
||||
|
||||
## Language additions
|
||||
|
||||
- Inline iterators returning `lent T` types are now supported, similarly to
|
||||
iterators returning `var T`:
|
||||
```nim
|
||||
iterator myitems[T](x: openarray[T]): lent T
|
||||
iterator mypairs[T](x: openarray[T]): tuple[idx: int, val: lent T]
|
||||
```
|
||||
|
||||
- Added an `importjs` pragma that can now be used instead of `importcpp`
|
||||
and `importc` to import symbols from JavaScript. `importjs` for routines always
|
||||
takes a "pattern" for maximum flexibility.
|
||||
|
||||
|
||||
|
||||
## Language changes
|
||||
|
||||
- `uint64` is now finally a regular ordinal type. This means `high(uint64)` compiles
|
||||
and yields the correct value.
|
||||
|
||||
|
||||
### Tool changes
|
||||
|
||||
- The Nim compiler now does not recompile the Nim project via ``nim c -r`` if
|
||||
no dependent Nim file changed. This feature can be overridden by
|
||||
the ``--forceBuild`` command line option.
|
||||
- The Nim compiler now warns about unused module imports. You can use a
|
||||
top level ``{.used.}`` pragma in the module that you want to be importable
|
||||
without producing this warning.
|
||||
- The "testament" testing tool's name was changed
|
||||
from `tester` to `testament` and is generally available as a tool to run Nim
|
||||
tests automatically.
|
||||
|
||||
|
||||
### Compiler changes
|
||||
|
||||
- VM can now cast integer type arbitrarily. (#11459)
|
||||
|
||||
|
||||
|
||||
## Bugfixes
|
||||
@@ -1,27 +1,33 @@
|
||||
## v0.XX.0 - XX/XX/2018
|
||||
|
||||
### Changes affecting backwards compatibility
|
||||
|
||||
- Example item: ``Foo`` changed to ``Bar``.
|
||||
|
||||
#### Breaking changes in the standard library
|
||||
# vx.xx.x - yyyy-mm-dd
|
||||
|
||||
|
||||
#### Breaking changes in the compiler
|
||||
## Changes affecting backwards compatibility
|
||||
|
||||
### Library additions
|
||||
|
||||
### Library changes
|
||||
- Example item: `Foo` changed to `Bar`.
|
||||
|
||||
|
||||
### Language additions
|
||||
### Breaking changes in the standard library
|
||||
|
||||
|
||||
### Language changes
|
||||
### Breaking changes in the compiler
|
||||
|
||||
|
||||
## Library additions
|
||||
- `set[T].len` is now an alias for `set[T].card` (cardinality)
|
||||
|
||||
## Library changes
|
||||
|
||||
|
||||
## Language additions
|
||||
|
||||
|
||||
## Language changes
|
||||
|
||||
|
||||
### Tool changes
|
||||
|
||||
|
||||
### Compiler changes
|
||||
|
||||
### Bugfixes
|
||||
|
||||
## Bugfixes
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Simple alias analysis for the HLO and the code generators.
|
||||
|
||||
import
|
||||
ast, astalgo, types, trees, intsets, msgs
|
||||
ast, astalgo, types, trees, intsets
|
||||
|
||||
type
|
||||
TAnalysisResult* = enum
|
||||
@@ -22,14 +22,14 @@ proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult =
|
||||
result = arNo
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
result = isPartOfAux(n.sons[i], b, marker)
|
||||
if result == arYes: return
|
||||
of nkRecCase:
|
||||
assert(n.sons[0].kind == nkSym)
|
||||
result = isPartOfAux(n.sons[0], b, marker)
|
||||
if result == arYes: return
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
case n.sons[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
result = isPartOfAux(lastSon(n.sons[i]), b, marker)
|
||||
@@ -52,7 +52,7 @@ proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
|
||||
of tyGenericInst, tyDistinct, tyAlias, tySink:
|
||||
result = isPartOfAux(lastSon(a), b, marker)
|
||||
of tyArray, tySet, tyTuple:
|
||||
for i in 0 ..< sonsLen(a):
|
||||
for i in 0 ..< len(a):
|
||||
result = isPartOfAux(a.sons[i], b, marker)
|
||||
if result == arYes: return
|
||||
else: discard
|
||||
@@ -186,7 +186,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
if res != arNo:
|
||||
result = res
|
||||
if res == arYes: break
|
||||
of nkCall:
|
||||
of nkCallKinds:
|
||||
result = arNo
|
||||
for i in 1 ..< b.len:
|
||||
let res = isPartOf(a, b[i])
|
||||
|
||||
158
compiler/ast.nim
158
compiler/ast.nim
@@ -10,8 +10,9 @@
|
||||
# abstract syntax tree + symbol table
|
||||
|
||||
import
|
||||
lineinfos, hashes, nversion, options, strutils, std / sha1, ropes, idents,
|
||||
intsets, idgen
|
||||
lineinfos, hashes, options, ropes, idents, idgen, int128
|
||||
|
||||
export int128
|
||||
|
||||
type
|
||||
TCallingConvention* = enum
|
||||
@@ -227,7 +228,7 @@ type
|
||||
TNodeKinds* = set[TNodeKind]
|
||||
|
||||
type
|
||||
TSymFlag* = enum # already 36 flags!
|
||||
TSymFlag* = enum # already 38 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
|
||||
@@ -238,6 +239,7 @@ type
|
||||
sfForward, # symbol is forward declared
|
||||
sfImportc, # symbol is external; imported
|
||||
sfExportc, # symbol is exported (under a specified name)
|
||||
sfMangleCpp, # mangle as cpp (combines with `sfExportc`)
|
||||
sfVolatile, # variable is volatile
|
||||
sfRegister, # variable should be placed in a register
|
||||
sfPure, # object is "pure" that means it has no type-information
|
||||
@@ -279,6 +281,9 @@ type
|
||||
sfNonReloadable # symbol will be left as-is when hot code reloading is on -
|
||||
# meaning that it won't be renamed and/or changed in any way
|
||||
sfGeneratedOp # proc is a generated '='; do not inject destructors in it
|
||||
# variable is generated closure environment; requires early
|
||||
# destruction for --newruntime.
|
||||
sfTemplateParam # symbol is a template parameter
|
||||
|
||||
|
||||
TSymFlags* = set[TSymFlag]
|
||||
@@ -605,7 +610,6 @@ type
|
||||
mAddF64, mSubF64, mMulF64, mDivF64,
|
||||
mShrI, mShlI, mAshrI, mBitandI, mBitorI, mBitxorI,
|
||||
mMinI, mMaxI,
|
||||
mMinF64, mMaxF64,
|
||||
mAddU, mSubU, mMulU, mDivU, mModU,
|
||||
mEqI, mLeI, mLtI,
|
||||
mEqF64, mLeF64, mLtF64,
|
||||
@@ -618,13 +622,7 @@ type
|
||||
mXor, mEqCString, mEqProc,
|
||||
mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot,
|
||||
mUnaryPlusI, mBitnotI,
|
||||
mUnaryPlusF64, mUnaryMinusF64, mAbsF64,
|
||||
mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64,
|
||||
mZe32ToI64, mZeIToI64,
|
||||
mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat,
|
||||
mToInt, mToBiggestInt,
|
||||
mUnaryPlusF64, mUnaryMinusF64,
|
||||
mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr,
|
||||
mStrToStr, mEnumToStr,
|
||||
mAnd, mOr,
|
||||
@@ -668,7 +666,8 @@ type
|
||||
mInstantiationInfo, mGetTypeInfo,
|
||||
mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples,
|
||||
mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
|
||||
mSymIsInstantiationOf
|
||||
mSymIsInstantiationOf, mNodeId
|
||||
|
||||
|
||||
# things that we can evaluate safely at compile time, even if not asked for it:
|
||||
const
|
||||
@@ -681,7 +680,6 @@ const
|
||||
mAddF64, mSubF64, mMulF64, mDivF64,
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI,
|
||||
mMinI, mMaxI,
|
||||
mMinF64, mMaxF64,
|
||||
mAddU, mSubU, mMulU, mDivU, mModU,
|
||||
mEqI, mLeI, mLtI,
|
||||
mEqF64, mLeF64, mLtF64,
|
||||
@@ -692,13 +690,7 @@ const
|
||||
mEqB, mLeB, mLtB,
|
||||
mEqRef, mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor,
|
||||
mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI,
|
||||
mUnaryPlusF64, mUnaryMinusF64, mAbsF64,
|
||||
mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64,
|
||||
mZe32ToI64, mZeIToI64,
|
||||
mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat,
|
||||
mToInt, mToBiggestInt,
|
||||
mUnaryPlusF64, mUnaryMinusF64,
|
||||
mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr,
|
||||
mStrToStr, mEnumToStr,
|
||||
mAnd, mOr,
|
||||
@@ -764,7 +756,9 @@ type
|
||||
lfImportCompilerProc, # ``importc`` of a compilerproc
|
||||
lfSingleUse # no location yet and will only be used once
|
||||
lfEnforceDeref # a copyMem is required to dereference if this a
|
||||
# ptr array due to C array limitations. See #1181, #6422, #11171
|
||||
# ptr array due to C array limitations.
|
||||
# See #1181, #6422, #11171
|
||||
lfPrepareForMutation # string location is about to be mutated (V2)
|
||||
TStorageLoc* = enum
|
||||
OnUnknown, # location is unknown (stack, heap or static)
|
||||
OnStatic, # in a static section
|
||||
@@ -859,7 +853,6 @@ type
|
||||
# for modules, an unique index corresponding
|
||||
# to the module's fileIdx
|
||||
# for variables a slot index for the evaluator
|
||||
# for routines a superop-ID
|
||||
offset*: int # offset of record field
|
||||
loc*: TLoc
|
||||
annex*: PLib # additional fields (seldom used, so we use a
|
||||
@@ -906,6 +899,7 @@ type
|
||||
size*: BiggestInt # the size of the type in bytes
|
||||
# -1 means that the size is unkwown
|
||||
align*: int16 # the type's alignment requirements
|
||||
paddingAtEnd*: int16 #
|
||||
lockLevel*: TLockLevel # lock level as required for deadlock checking
|
||||
loc*: TLoc
|
||||
typeInst*: PType # for generic instantiations the tyGenericInst that led to this
|
||||
@@ -1029,7 +1023,9 @@ proc isCallExpr*(n: PNode): bool =
|
||||
|
||||
proc discardSons*(father: PNode)
|
||||
|
||||
proc len*(n: PNode): int {.inline.} =
|
||||
type Indexable = PNode | PType
|
||||
|
||||
proc len*(n: Indexable): int {.inline.} =
|
||||
when defined(nimNoNilSeqs):
|
||||
result = len(n.sons)
|
||||
else:
|
||||
@@ -1053,8 +1049,6 @@ proc add*(father, son: PNode) =
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
|
||||
type Indexable = PNode | PType
|
||||
|
||||
template `[]`*(n: Indexable, i: int): Indexable = n.sons[i]
|
||||
template `[]=`*(n: Indexable, i: int; x: Indexable) = n.sons[i] = x
|
||||
|
||||
@@ -1062,7 +1056,7 @@ template `[]`*(n: Indexable, i: BackwardsIndex): Indexable = n[n.len - i.int]
|
||||
template `[]=`*(n: Indexable, i: BackwardsIndex; x: Indexable) = n[n.len - i.int] = x
|
||||
|
||||
when defined(useNodeIds):
|
||||
const nodeIdToDebug* = -1 # 299750 # 300761 #300863 # 300879
|
||||
const nodeIdToDebug* = -1 # 2322968
|
||||
var gNodeId: int
|
||||
|
||||
proc newNode*(kind: TNodeKind): PNode =
|
||||
@@ -1240,10 +1234,48 @@ proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
|
||||
result = newNode(kind)
|
||||
result.intVal = intVal
|
||||
|
||||
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
|
||||
result = newIntNode(kind, intVal)
|
||||
proc newIntNode*(kind: TNodeKind, intVal: Int128): PNode =
|
||||
result = newNode(kind)
|
||||
result.intVal = castToInt64(intVal)
|
||||
|
||||
proc lastSon*(n: Indexable): Indexable = n.sons[^1]
|
||||
|
||||
proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
|
||||
## Used throughout the compiler code to test whether a type tree contains or
|
||||
## doesn't contain a specific type/types - it is often the case that only the
|
||||
## last child nodes of a type tree need to be searched. This is a really hot
|
||||
## path within the compiler!
|
||||
result = t
|
||||
while result.kind in kinds: result = lastSon(result)
|
||||
|
||||
proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
|
||||
|
||||
# this is dirty. abstractVarRange isn't defined yet and therefor it
|
||||
# is duplicated here.
|
||||
const abstractVarRange = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
|
||||
tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned}
|
||||
case skipTypes(typ, abstractVarRange).kind
|
||||
of tyInt: result = newNode(nkIntLit)
|
||||
of tyInt8: result = newNode(nkInt8Lit)
|
||||
of tyInt16: result = newNode(nkInt16Lit)
|
||||
of tyInt32: result = newNode(nkInt32Lit)
|
||||
of tyInt64: result = newNode(nkInt64Lit)
|
||||
of tyChar: result = newNode(nkCharLit)
|
||||
of tyUInt: result = newNode(nkUIntLit)
|
||||
of tyUInt8: result = newNode(nkUInt8Lit)
|
||||
of tyUInt16: result = newNode(nkUInt16Lit)
|
||||
of tyUInt32: result = newNode(nkUInt32Lit)
|
||||
of tyUInt64: result = newNode(nkUInt64Lit)
|
||||
else: # tyBool, tyEnum
|
||||
# XXX: does this really need to be the kind nkIntLit?
|
||||
result = newNode(nkIntLit)
|
||||
result.intVal = intVal
|
||||
result.typ = typ
|
||||
|
||||
proc newIntTypeNode*(intVal: Int128, typ: PType): PNode =
|
||||
# XXX: introduce range check
|
||||
newIntTypeNode(castToInt64(intVal), typ)
|
||||
|
||||
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
|
||||
result = newNode(kind)
|
||||
result.floatVal = floatVal
|
||||
@@ -1310,7 +1342,7 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
|
||||
if a.lode == nil: a.lode = b.lode
|
||||
if a.r == nil: a.r = b.r
|
||||
|
||||
proc newSons*(father: PNode, length: int) =
|
||||
proc newSons*(father: Indexable, length: int) =
|
||||
when defined(nimNoNilSeqs):
|
||||
setLen(father.sons, length)
|
||||
else:
|
||||
@@ -1319,21 +1351,6 @@ proc newSons*(father: PNode, length: int) =
|
||||
else:
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc newSons*(father: PType, length: int) =
|
||||
when defined(nimNoNilSeqs):
|
||||
setLen(father.sons, length)
|
||||
else:
|
||||
if isNil(father.sons):
|
||||
newSeq(father.sons, length)
|
||||
else:
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc sonsLen*(n: PType): int = n.sons.len
|
||||
proc len*(n: PType): int = n.sons.len
|
||||
proc sonsLen*(n: PNode): int = n.sons.len
|
||||
proc lastSon*(n: PNode): PNode = n.sons[^1]
|
||||
proc lastSon*(n: PType): PType = n.sons[^1]
|
||||
|
||||
proc assignType*(dest, src: PType) =
|
||||
dest.kind = src.kind
|
||||
dest.flags = src.flags
|
||||
@@ -1351,8 +1368,8 @@ proc assignType*(dest, src: PType) =
|
||||
mergeLoc(dest.sym.loc, src.sym.loc)
|
||||
else:
|
||||
dest.sym = src.sym
|
||||
newSons(dest, sonsLen(src))
|
||||
for i in 0 ..< sonsLen(src): dest.sons[i] = src.sons[i]
|
||||
newSons(dest, len(src))
|
||||
for i in 0 ..< len(src): dest.sons[i] = src.sons[i]
|
||||
|
||||
proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
|
||||
result = newType(t.kind, owner)
|
||||
@@ -1428,14 +1445,6 @@ proc initNodeTable*(x: var TNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
|
||||
## Used throughout the compiler code to test whether a type tree contains or
|
||||
## doesn't contain a specific type/types - it is often the case that only the
|
||||
## last child nodes of a type tree need to be searched. This is a really hot
|
||||
## path within the compiler!
|
||||
result = t
|
||||
while result.kind in kinds: result = lastSon(result)
|
||||
|
||||
proc skipTypes*(t: PType, kinds: TTypeKinds; maxIters: int): PType =
|
||||
result = t
|
||||
var i = maxIters
|
||||
@@ -1474,14 +1483,14 @@ proc propagateToOwner*(owner, elem: PType) =
|
||||
if tfHasAsgn in elem.flags:
|
||||
let o2 = owner.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
if o2.kind in {tyTuple, tyObject, tyArray,
|
||||
tySequence, tyOpt, tySet, tyDistinct}:
|
||||
tySequence, tyOpt, tySet, tyDistinct, tyOpenArray, tyVarargs}:
|
||||
o2.flags.incl tfHasAsgn
|
||||
owner.flags.incl tfHasAsgn
|
||||
|
||||
if tfHasOwned in elem.flags:
|
||||
let o2 = owner.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
if o2.kind in {tyTuple, tyObject, tyArray,
|
||||
tySequence, tyOpt, tySet, tyDistinct}:
|
||||
tySequence, tyOpt, tySet, tyDistinct, tyOpenArray, tyVarargs}:
|
||||
o2.flags.incl tfHasOwned
|
||||
owner.flags.incl tfHasOwned
|
||||
|
||||
@@ -1514,7 +1523,7 @@ proc delSon*(father: PNode, idx: int) =
|
||||
if father.len == 0: return
|
||||
else:
|
||||
if isNil(father.sons): return
|
||||
var length = sonsLen(father)
|
||||
var length = len(father)
|
||||
for i in idx .. length - 2: father.sons[i] = father.sons[i + 1]
|
||||
setLen(father.sons, length - 1)
|
||||
|
||||
@@ -1555,7 +1564,7 @@ proc shallowCopy*(src: PNode): PNode =
|
||||
of nkSym: result.sym = src.sym
|
||||
of nkIdent: result.ident = src.ident
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else: newSeq(result.sons, sonsLen(src))
|
||||
else: newSeq(result.sons, len(src))
|
||||
|
||||
proc copyTree*(src: PNode): PNode =
|
||||
# copy a whole syntax tree; performs deep copying
|
||||
@@ -1576,12 +1585,12 @@ proc copyTree*(src: PNode): PNode =
|
||||
of nkIdent: result.ident = src.ident
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else:
|
||||
newSeq(result.sons, sonsLen(src))
|
||||
for i in 0 ..< sonsLen(src):
|
||||
newSeq(result.sons, len(src))
|
||||
for i in 0 ..< len(src):
|
||||
result.sons[i] = copyTree(src.sons[i])
|
||||
|
||||
proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if n.sons[i].kind == kind:
|
||||
return true
|
||||
result = false
|
||||
@@ -1599,30 +1608,43 @@ proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit: result = n.kind in kinds
|
||||
else:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if n.kind in kinds or containsNode(n.sons[i], kinds): return true
|
||||
|
||||
proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit: result = n.kind == kind
|
||||
else:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc getInt*(a: PNode): BiggestInt =
|
||||
proc getInt*(a: PNode): Int128 =
|
||||
case a.kind
|
||||
of nkCharLit..nkUInt64Lit: result = a.intVal
|
||||
of nkCharLit, nkUIntLit..nkUInt64Lit:
|
||||
result = toInt128(cast[uint64](a.intVal))
|
||||
of nkInt8Lit..nkInt64Lit:
|
||||
result = toInt128(a.intVal)
|
||||
of nkIntLit:
|
||||
# XXX: enable this assert
|
||||
# assert a.typ.kind notin {tyChar, tyUint..tyUInt64}
|
||||
result = toInt128(a.intVal)
|
||||
else:
|
||||
raiseRecoverableError("cannot extract number from invalid AST node")
|
||||
|
||||
proc getInt64*(a: PNode): int64 {.deprecated: "use getInt".} =
|
||||
case a.kind
|
||||
of nkCharLit, nkUIntLit..nkUInt64Lit, nkIntLit..nkInt64Lit:
|
||||
result = a.intVal
|
||||
else:
|
||||
raiseRecoverableError("cannot extract number from invalid AST node")
|
||||
#internalError(a.info, "getInt")
|
||||
#doAssert false, "getInt"
|
||||
#result = 0
|
||||
|
||||
proc getFloat*(a: PNode): BiggestFloat =
|
||||
case a.kind
|
||||
of nkFloatLiterals: result = a.floatVal
|
||||
of nkCharLit, nkUIntLit..nkUInt64Lit, nkIntLit..nkInt64Lit:
|
||||
result = BiggestFloat a.intVal
|
||||
else:
|
||||
raiseRecoverableError("cannot extract number from invalid AST node")
|
||||
#doAssert false, "getFloat"
|
||||
|
||||
@@ -31,6 +31,15 @@ when declared(echo):
|
||||
proc debug*(n: PType; conf: ConfigRef = nil) {.exportc: "debugType", deprecated.}
|
||||
proc debug*(n: PNode; conf: ConfigRef = nil) {.exportc: "debugNode", deprecated.}
|
||||
|
||||
proc typekinds*(t: PType) {.deprecated.} =
|
||||
var t = t
|
||||
var s = ""
|
||||
while t != nil and t.len > 0:
|
||||
s.add $t.kind
|
||||
s.add " "
|
||||
t = t.lastSon
|
||||
echo s
|
||||
|
||||
template debug*(x: PSym|PType|PNode) {.deprecated.} =
|
||||
when compiles(c.config):
|
||||
debug(c.config, x)
|
||||
@@ -77,7 +86,6 @@ proc idNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym
|
||||
proc lookupInRecord*(n: PNode, field: PIdent): PSym
|
||||
proc mustRehash*(length, counter: int): bool
|
||||
proc nextTry*(h, maxHash: Hash): Hash {.inline.}
|
||||
@@ -117,7 +125,7 @@ proc sameValue*(a, b: PNode): bool =
|
||||
result = false
|
||||
case a.kind
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal
|
||||
if b.kind in {nkCharLit..nkUInt64Lit}: result = getInt(a) == getInt(b)
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
@@ -131,8 +139,8 @@ proc leValue*(a, b: PNode): bool =
|
||||
# a <= b?
|
||||
result = false
|
||||
case a.kind
|
||||
of nkCharLit..nkUInt32Lit:
|
||||
if b.kind in {nkCharLit..nkUInt32Lit}: result = a.intVal <= b.intVal
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
if b.kind in {nkCharLit..nkUInt64Lit}: result = getInt(a) <= getInt(b)
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
@@ -152,14 +160,14 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
|
||||
result = nil
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
result = lookupInRecord(n.sons[i], field)
|
||||
if result != nil: return
|
||||
of nkRecCase:
|
||||
if (n.sons[0].kind != nkSym): return nil
|
||||
result = lookupInRecord(n.sons[0], field)
|
||||
if result != nil: return
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
case n.sons[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
result = lookupInRecord(lastSon(n.sons[i]), field)
|
||||
@@ -174,14 +182,54 @@ proc getModule*(s: PSym): PSym =
|
||||
assert((result.kind == skModule) or (result.owner != result))
|
||||
while result != nil and result.kind != skModule: result = result.owner
|
||||
|
||||
proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
|
||||
for i in start ..< sonsLen(list):
|
||||
proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym =
|
||||
for i in start ..< len(list):
|
||||
if list.sons[i].kind == nkSym:
|
||||
result = list.sons[i].sym
|
||||
if result.name.id == ident.id: return
|
||||
else: return nil
|
||||
result = nil
|
||||
|
||||
proc sameIgnoreBacktickGensymInfo(a, b: string): bool =
|
||||
if a[0] != b[0]: return false
|
||||
var alen = a.len - 1
|
||||
while alen > 0 and a[alen] != '`': dec(alen)
|
||||
if alen <= 0: alen = a.len
|
||||
|
||||
var i = 1
|
||||
var j = 1
|
||||
while true:
|
||||
while i < alen and a[i] == '_': inc i
|
||||
while j < b.len and b[j] == '_': inc j
|
||||
var aa = if i < alen: toLowerAscii(a[i]) else: '\0'
|
||||
var bb = if j < b.len: toLowerAscii(b[j]) else: '\0'
|
||||
if aa != bb: return false
|
||||
|
||||
# the characters are identical:
|
||||
if i >= alen:
|
||||
# both cursors at the end:
|
||||
if j >= b.len: return true
|
||||
# not yet at the end of 'b':
|
||||
return false
|
||||
elif j >= b.len:
|
||||
return false
|
||||
inc i
|
||||
inc j
|
||||
|
||||
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:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
## result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $x.id),
|
||||
## if c.instLines: actual.info else: templ.info)
|
||||
for i in 1 ..< len(list):
|
||||
let it = list[i].sym
|
||||
if it.name.id == ident.id or
|
||||
sameIgnoreBacktickGensymInfo(it.name.s, ident.s): return it
|
||||
|
||||
proc hashNode(p: RootRef): Hash =
|
||||
result = hash(cast[pointer](p))
|
||||
|
||||
@@ -279,9 +327,9 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
|
||||
sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
|
||||
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
|
||||
else:
|
||||
if sonsLen(n) > 0:
|
||||
if len(n) > 0:
|
||||
sonsRope = rope("[")
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if i > 0: add(sonsRope, ",")
|
||||
addf(sonsRope, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, n.sons[i],
|
||||
marker, indent + 4, maxRecDepth - 1)])
|
||||
@@ -328,9 +376,9 @@ proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int,
|
||||
else:
|
||||
addf(result, ",$N$1\"ident\": null", [istr])
|
||||
else:
|
||||
if sonsLen(n) > 0:
|
||||
if len(n) > 0:
|
||||
addf(result, ",$N$1\"sons\": [", [istr])
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if i > 0: add(result, ",")
|
||||
addf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(conf, n.sons[i],
|
||||
marker, indent + 4, maxRecDepth - 1)])
|
||||
@@ -515,12 +563,12 @@ proc value(this: var DebugPrinter; value: PType) =
|
||||
this.key "n"
|
||||
this.value value.n
|
||||
|
||||
if sonsLen(value) > 0:
|
||||
if len(value) > 0:
|
||||
this.key "sons"
|
||||
this.openBracket
|
||||
for i in 0 ..< sonsLen(value):
|
||||
for i in 0 ..< len(value):
|
||||
this.value value.sons[i]
|
||||
if i != sonsLen(value) - 1:
|
||||
if i != len(value) - 1:
|
||||
this.comma
|
||||
this.closeBracket
|
||||
|
||||
@@ -568,12 +616,12 @@ proc value(this: var DebugPrinter; value: PNode) =
|
||||
if this.renderSymType and value.typ != nil:
|
||||
this.key "typ"
|
||||
this.value value.typ
|
||||
if sonsLen(value) > 0:
|
||||
if len(value) > 0:
|
||||
this.key "sons"
|
||||
this.openBracket
|
||||
for i in 0 ..< sonsLen(value):
|
||||
for i in 0 ..< len(value):
|
||||
this.value value.sons[i]
|
||||
if i != sonsLen(value) - 1:
|
||||
if i != len(value) - 1:
|
||||
this.comma
|
||||
this.closeBracket
|
||||
|
||||
|
||||
@@ -11,12 +11,17 @@
|
||||
# the code here should be reused in the Nim standard library
|
||||
|
||||
type
|
||||
TBitSet* = seq[int8] # we use byte here to avoid issues with
|
||||
ElemType = byte
|
||||
TBitSet* = seq[ElemType] # we use byte here to avoid issues with
|
||||
# cross-compiling; uint would be more efficient
|
||||
# however
|
||||
|
||||
const
|
||||
ElemSize* = sizeof(int8) * 8
|
||||
ElemSize* = 8
|
||||
One = ElemType(1)
|
||||
Zero = ElemType(0)
|
||||
|
||||
template modElemSize(arg: untyped): untyped = arg and 7
|
||||
template divElemSize(arg: untyped): untyped = arg shr 3
|
||||
|
||||
proc bitSetInit*(b: var TBitSet, length: int)
|
||||
proc bitSetUnion*(x: var TBitSet, y: TBitSet)
|
||||
@@ -32,17 +37,16 @@ proc bitSetCard*(x: TBitSet): BiggestInt
|
||||
# implementation
|
||||
|
||||
proc bitSetIn(x: TBitSet, e: BiggestInt): bool =
|
||||
result = (x[int(e div ElemSize)] and toU8(int(1 shl (e mod ElemSize)))) !=
|
||||
toU8(0)
|
||||
result = (x[int(e.divElemSize)] and (One shl e.modElemSize)) != Zero
|
||||
|
||||
proc bitSetIncl(x: var TBitSet, elem: BiggestInt) =
|
||||
assert(elem >= 0)
|
||||
x[int(elem div ElemSize)] = x[int(elem div ElemSize)] or
|
||||
toU8(int(1 shl (elem mod ElemSize)))
|
||||
x[int(elem.divElemSize)] = x[int(elem.divElemSize)] or
|
||||
(One shl elem.modElemSize)
|
||||
|
||||
proc bitSetExcl(x: var TBitSet, elem: BiggestInt) =
|
||||
x[int(elem div ElemSize)] = x[int(elem div ElemSize)] and
|
||||
not toU8(int(1 shl (elem mod ElemSize)))
|
||||
x[int(elem.divElemSize)] = x[int(elem.divElemSize)] and
|
||||
not(One shl elem.modElemSize)
|
||||
|
||||
proc bitSetInit(b: var TBitSet, length: int) =
|
||||
newSeq(b, length)
|
||||
@@ -67,13 +71,13 @@ proc bitSetEquals(x, y: TBitSet): bool =
|
||||
|
||||
proc bitSetContains(x, y: TBitSet): bool =
|
||||
for i in 0 .. high(x):
|
||||
if (x[i] and not y[i]) != int8(0):
|
||||
if (x[i] and not y[i]) != Zero:
|
||||
return false
|
||||
result = true
|
||||
|
||||
# Number of set bits for all values of int8
|
||||
const populationCount: array[low(int8)..high(int8), int8] = block:
|
||||
var arr: array[low(int8)..high(int8), int8]
|
||||
const populationCount: array[uint8, uint8] = block:
|
||||
var arr: array[uint8, uint8]
|
||||
|
||||
proc countSetBits(x: uint8): uint8 =
|
||||
return
|
||||
@@ -87,11 +91,11 @@ const populationCount: array[low(int8)..high(int8), int8] = block:
|
||||
((x and 0b10000000'u8) shr 7)
|
||||
|
||||
|
||||
for it in low(int8)..high(int8):
|
||||
arr[it] = cast[int8](countSetBits(cast[uint8](it)))
|
||||
for it in low(uint8)..high(uint8):
|
||||
arr[it] = countSetBits(cast[uint8](it))
|
||||
|
||||
arr
|
||||
|
||||
proc bitSetCard(x: TBitSet): BiggestInt =
|
||||
for it in x:
|
||||
result.inc populationCount[it]
|
||||
result.inc int(populationCount[it])
|
||||
|
||||
@@ -120,7 +120,7 @@ proc hashType(c: var MD5Context, t: PType) =
|
||||
|
||||
case t.kind
|
||||
of tyGenericBody, tyGenericInst, tyGenericInvocation:
|
||||
for i in 0 ..< sonsLen(t)-ord(t.kind != tyGenericInvocation):
|
||||
for i in 0 ..< len(t)-ord(t.kind != tyGenericInvocation):
|
||||
c.hashType t.sons[i]
|
||||
of tyUserTypeClass:
|
||||
internalAssert t.sym != nil and t.sym.owner != nil
|
||||
@@ -128,7 +128,7 @@ proc hashType(c: var MD5Context, t: PType) =
|
||||
of tyUserTypeClassInst:
|
||||
let body = t.base
|
||||
c.hashSym body.sym
|
||||
for i in 1 .. sonsLen(t) - 2:
|
||||
for i in 1 .. len(t) - 2:
|
||||
c.hashType t.sons[i]
|
||||
of tyFromExpr:
|
||||
c.hashTree(t.n)
|
||||
@@ -137,15 +137,15 @@ proc hashType(c: var MD5Context, t: PType) =
|
||||
c.hashType(t.sons[1])
|
||||
of tyTuple:
|
||||
if t.n != nil:
|
||||
assert(sonsLen(t.n) == sonsLen(t))
|
||||
for i in 0 ..< sonsLen(t.n):
|
||||
assert(len(t.n) == len(t))
|
||||
for i in 0 ..< len(t.n):
|
||||
assert(t.n.sons[i].kind == nkSym)
|
||||
c &= t.n.sons[i].sym.name.s
|
||||
c &= ":"
|
||||
c.hashType(t.sons[i])
|
||||
c &= ","
|
||||
else:
|
||||
for i in 0 ..< sonsLen(t): c.hashType t.sons[i]
|
||||
for i in 0 ..< len(t): c.hashType t.sons[i]
|
||||
of tyRange:
|
||||
c.hashTree(t.n)
|
||||
c.hashType(t.sons[0])
|
||||
@@ -238,7 +238,7 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
||||
encodeVInt(n.sym.id, result)
|
||||
pushSym(w, n.sym)
|
||||
else:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
encodeNode(w, n.info, n.sons[i], result)
|
||||
add(result, ')')
|
||||
|
||||
@@ -304,7 +304,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
||||
add(result, '=')
|
||||
encodeVInt(t.align, result)
|
||||
encodeLoc(w, t.loc, result)
|
||||
for i in 0 ..< sonsLen(t):
|
||||
for i in 0 ..< len(t):
|
||||
if t.sons[i] == nil:
|
||||
add(result, "^()")
|
||||
else:
|
||||
|
||||
@@ -79,9 +79,19 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
|
||||
proc openArrayLoc(p: BProc, n: PNode): Rope =
|
||||
var a: TLoc
|
||||
|
||||
let q = skipConv(n)
|
||||
var q = skipConv(n)
|
||||
var skipped = false
|
||||
while q.kind == nkStmtListExpr and q.len > 0:
|
||||
skipped = true
|
||||
q = q.lastSon
|
||||
if getMagic(q) == mSlice:
|
||||
# magic: pass slice to openArray:
|
||||
if skipped:
|
||||
q = skipConv(n)
|
||||
while q.kind == nkStmtListExpr and q.len > 0:
|
||||
for i in 0..q.len-2:
|
||||
genStmts(p, q[i])
|
||||
q = q.lastSon
|
||||
var b, c: TLoc
|
||||
initLocExpr(p, q[1], a)
|
||||
initLocExpr(p, q[2], b)
|
||||
@@ -90,21 +100,23 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
|
||||
if optBoundsCheck in p.options:
|
||||
genBoundsCheck(p, a, b, c)
|
||||
let ty = skipTypes(a.t, abstractVar+{tyPtr})
|
||||
let dest = getTypeDesc(p.module, n.typ.sons[0])
|
||||
case ty.kind
|
||||
of tyArray:
|
||||
let first = firstOrd(p.config, ty)
|
||||
let first = toInt64(firstOrd(p.config, ty))
|
||||
if first == 0:
|
||||
result = "($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
|
||||
result = "($4*)(($1)+($2)), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
|
||||
else:
|
||||
result = "($1)+(($2)-($4)), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), intLiteral(first)]
|
||||
of tyOpenArray, tyVarargs, tyUncheckedArray:
|
||||
result = "($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
|
||||
result = "($5*)($1)+(($2)-($4)), ($3)-($2)+1" %
|
||||
[rdLoc(a), rdLoc(b), rdLoc(c), intLiteral(first), dest]
|
||||
of tyOpenArray, tyVarargs, tyUncheckedArray, tyCString:
|
||||
result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
|
||||
of tyString, tySequence:
|
||||
if skipTypes(n.typ, abstractInst).kind == tyVar and
|
||||
not compileToCpp(p.module):
|
||||
result = "(*$1)$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p)]
|
||||
result = "($5*)(*$1)$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest]
|
||||
else:
|
||||
result = "$1$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p)]
|
||||
result = "($5*)$1$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest]
|
||||
else:
|
||||
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
|
||||
else:
|
||||
@@ -156,7 +168,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
|
||||
# means '*T'. See posix.nim for lots of examples that do that in the wild.
|
||||
let callee = call.sons[0]
|
||||
if callee.kind == nkSym and
|
||||
{sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and
|
||||
{sfImportc, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportc} and
|
||||
{lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
|
||||
result = addrLoc(p.config, a)
|
||||
else:
|
||||
@@ -174,7 +186,7 @@ proc genArgNoParam(p: BProc, n: PNode): Rope =
|
||||
result = rdLoc(a)
|
||||
|
||||
template genParamLoop(params) {.dirty.} =
|
||||
if i < sonsLen(typ):
|
||||
if i < len(typ):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
let paramType = typ.n.sons[i]
|
||||
if not paramType.typ.isCompileTimeOnly:
|
||||
@@ -184,8 +196,8 @@ template genParamLoop(params) {.dirty.} =
|
||||
if params != nil: add(params, ~", ")
|
||||
add(params, genArgNoParam(p, ri.sons[i]))
|
||||
|
||||
proc addActualPrefixForHCR(res: var Rope, module: PSym, sym: PSym) =
|
||||
if sym.flags * {sfImportc, sfNonReloadable} == {} and
|
||||
proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
|
||||
if sym.flags * {sfImportc, sfNonReloadable} == {} and sym.loc.k == locProc and
|
||||
(sym.typ.callConv == ccInline or sym.owner.id == module.id):
|
||||
res = res & "_actual".rope
|
||||
|
||||
@@ -197,13 +209,13 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri.sons[0].typ, abstractInstOwned)
|
||||
assert(typ.kind == tyProc)
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
var length = sonsLen(ri)
|
||||
assert(len(typ) == len(typ.n))
|
||||
var length = len(ri)
|
||||
for i in 1 ..< length:
|
||||
genParamLoop(params)
|
||||
var callee = rdLoc(op)
|
||||
if p.hcrOn and ri.sons[0].kind == nkSym:
|
||||
callee.addActualPrefixForHCR(p.module.module, ri.sons[0].sym)
|
||||
callee.addActualSuffixForHCR(p.module.module, ri.sons[0].sym)
|
||||
fixupCall(p, le, ri, d, callee, params)
|
||||
|
||||
proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
@@ -222,9 +234,9 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
|
||||
var typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
var length = sonsLen(ri)
|
||||
var length = len(ri)
|
||||
for i in 1 ..< length:
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
assert(len(typ) == len(typ.n))
|
||||
genParamLoop(pl)
|
||||
|
||||
template genCallPattern {.dirty.} =
|
||||
@@ -236,7 +248,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
let rawProc = getRawProcType(p, typ)
|
||||
if typ.sons[0] != nil:
|
||||
if isInvalidReturnType(p.config, typ.sons[0]):
|
||||
if sonsLen(ri) > 1: add(pl, ~", ")
|
||||
if len(ri) > 1: add(pl, ~", ")
|
||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
|
||||
# Great, we can use 'd':
|
||||
@@ -268,7 +280,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
genCallPattern()
|
||||
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
|
||||
if i < sonsLen(typ):
|
||||
if i < len(typ):
|
||||
# 'var T' is 'T&' in C++. This means we ignore the request of
|
||||
# any nkHiddenAddr when it's a 'var T'.
|
||||
let paramType = typ.n.sons[i]
|
||||
@@ -345,7 +357,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
|
||||
# for better or worse c2nim translates the 'this' argument to a 'var T'.
|
||||
# However manual wrappers may also use 'ptr T'. In any case we support both
|
||||
# for convenience.
|
||||
internalAssert p.config, i < sonsLen(typ)
|
||||
internalAssert p.config, i < len(typ)
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
# if the parameter is lying (tyVar) and thus we required an additional deref,
|
||||
# skip the deref:
|
||||
@@ -382,11 +394,14 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
|
||||
while i < pat.len:
|
||||
case pat[i]
|
||||
of '@':
|
||||
if j < ri.len:
|
||||
result.add genOtherArg(p, ri, j, typ)
|
||||
for k in j+1 ..< ri.len:
|
||||
result.add(~", ")
|
||||
result.add genOtherArg(p, ri, k, typ)
|
||||
var first = true
|
||||
for k in j ..< ri.len:
|
||||
let arg = genOtherArg(p, ri, k, typ)
|
||||
if arg.len > 0:
|
||||
if not first:
|
||||
result.add(~", ")
|
||||
first = false
|
||||
result.add arg
|
||||
inc i
|
||||
of '#':
|
||||
if i+1 < pat.len and pat[i+1] in {'+', '@'}:
|
||||
@@ -436,8 +451,8 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
var length = sonsLen(ri)
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
var length = len(ri)
|
||||
assert(len(typ) == len(typ.n))
|
||||
# don't call '$' here for efficiency:
|
||||
let pat = ri.sons[0].sym.loc.r.data
|
||||
internalAssert p.config, pat.len > 0
|
||||
@@ -472,7 +487,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var params: Rope
|
||||
for i in 2 ..< length:
|
||||
if params != nil: params.add(~", ")
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
assert(len(typ) == len(typ.n))
|
||||
add(params, genOtherArg(p, ri, i, typ))
|
||||
fixupCall(p, le, ri, d, pl, params)
|
||||
|
||||
@@ -484,8 +499,8 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
var length = sonsLen(ri)
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
var length = len(ri)
|
||||
assert(len(typ) == len(typ.n))
|
||||
|
||||
# don't call '$' here for efficiency:
|
||||
let pat = ri.sons[0].sym.loc.r.data
|
||||
@@ -507,8 +522,8 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
add(pl, ~": ")
|
||||
add(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
|
||||
for i in start ..< length:
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
if i >= sonsLen(typ):
|
||||
assert(len(typ) == len(typ.n))
|
||||
if i >= len(typ):
|
||||
internalError(p.config, ri.info, "varargs for objective C method?")
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
var param = typ.n.sons[i].sym
|
||||
@@ -518,7 +533,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
add(pl, genArg(p, ri.sons[i], param, ri))
|
||||
if typ.sons[0] != nil:
|
||||
if isInvalidReturnType(p.config, typ.sons[0]):
|
||||
if sonsLen(ri) > 1: add(pl, ~" ")
|
||||
if len(ri) > 1: add(pl, ~" ")
|
||||
# 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:
|
||||
|
||||
@@ -30,6 +30,9 @@ proc intLiteral(i: BiggestInt): Rope =
|
||||
else:
|
||||
result = ~"(IL64(-9223372036854775807) - IL64(1))"
|
||||
|
||||
proc intLiteral(i: Int128): Rope =
|
||||
intLiteral(toInt64(i))
|
||||
|
||||
proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
||||
case n.kind
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
@@ -76,7 +79,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
||||
# with the new semantics for 'nil' strings, we can map "" to nil and
|
||||
# save tons of allocations:
|
||||
if n.strVal.len == 0 and optNilSeqs notin p.options and
|
||||
p.config.selectedGc != gcDestructors:
|
||||
p.config.selectedGC != gcDestructors:
|
||||
result = genNilStringLiteral(p.module, n.info)
|
||||
else:
|
||||
result = genStringLiteral(p.module, n)
|
||||
@@ -93,26 +96,30 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
||||
proc genLiteral(p: BProc, n: PNode): Rope =
|
||||
result = genLiteral(p, n, n.typ)
|
||||
|
||||
proc bitSetToWord(s: TBitSet, size: int): BiggestInt =
|
||||
proc bitSetToWord(s: TBitSet, size: int): BiggestUInt =
|
||||
result = 0
|
||||
for j in 0 ..< size:
|
||||
if j < len(s): result = result or (ze64(s[j]) shl (j * 8))
|
||||
if j < len(s): result = result or (BiggestUInt(s[j]) shl (j * 8))
|
||||
|
||||
proc genRawSetData(cs: TBitSet, size: int): Rope =
|
||||
if size > 8:
|
||||
result = "{$n" % []
|
||||
var res = "{\n"
|
||||
for i in 0 ..< size:
|
||||
res.add "0x"
|
||||
res.add "0123456789abcdef"[cs[i] div 16]
|
||||
res.add "0123456789abcdef"[cs[i] mod 16]
|
||||
if i < size - 1:
|
||||
# not last iteration?
|
||||
if (i + 1) mod 8 == 0:
|
||||
addf(result, "0x$1,$n", [rope(toHex(ze64(cs[i]), 2))])
|
||||
# not last iteration
|
||||
if i mod 8 == 7:
|
||||
res.add ",\n"
|
||||
else:
|
||||
addf(result, "0x$1, ", [rope(toHex(ze64(cs[i]), 2))])
|
||||
res.add ", "
|
||||
else:
|
||||
addf(result, "0x$1}$n", [rope(toHex(ze64(cs[i]), 2))])
|
||||
res.add "}\n"
|
||||
|
||||
result = rope(res)
|
||||
else:
|
||||
result = intLiteral(bitSetToWord(cs, size))
|
||||
# result := rope('0x' + ToHex(bitSetToWord(cs, size), size * 2))
|
||||
result = intLiteral(cast[BiggestInt](bitSetToWord(cs, size)))
|
||||
|
||||
proc genSetNode(p: BProc, n: PNode): Rope =
|
||||
var cs: TBitSet
|
||||
@@ -356,7 +363,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
|
||||
of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString,
|
||||
tyInt..tyUInt64, tyRange, tyVar, tyLent:
|
||||
tyInt..tyUInt64, tyRange, tyVar, tyLent, tyNil:
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
|
||||
else: internalError(p.config, "genAssignment: " & $ty.kind)
|
||||
|
||||
@@ -581,8 +588,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mBitxorI: applyFormat("($4)($1 ^ $2)")
|
||||
of mMinI: applyFormat("(($1 <= $2) ? $1 : $2)")
|
||||
of mMaxI: applyFormat("(($1 >= $2) ? $1 : $2)")
|
||||
of mMinF64: applyFormat("(($1 <= $2) ? $1 : $2)")
|
||||
of mMaxF64: applyFormat("(($1 >= $2) ? $1 : $2)")
|
||||
of mAddU: applyFormat("($4)((NU$3)($1) + (NU$3)($2))")
|
||||
of mSubU: applyFormat("($4)((NU$3)($1) - (NU$3)($2))")
|
||||
of mMulU: applyFormat("($4)((NU$3)($1) * (NU$3)($2))")
|
||||
@@ -635,28 +640,6 @@ proc genIsNil(p: BProc, e: PNode, d: var TLoc) =
|
||||
unaryExpr(p, e, d, "($1 == 0)")
|
||||
|
||||
proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
const
|
||||
unArithTab: array[mNot..mToBiggestInt, string] = [
|
||||
"!($1)", # Not
|
||||
"$1", # UnaryPlusI
|
||||
"($3)((NU$2) ~($1))", # BitnotI
|
||||
"$1", # UnaryPlusF64
|
||||
"-($1)", # UnaryMinusF64
|
||||
"($1 < 0? -($1) : ($1))", # AbsF64; BUGFIX: fabs() makes problems
|
||||
# for Tiny C, so we don't use it
|
||||
"(($3)(NU)(NU8)($1))", # mZe8ToI
|
||||
"(($3)(NU64)(NU8)($1))", # mZe8ToI64
|
||||
"(($3)(NU)(NU16)($1))", # mZe16ToI
|
||||
"(($3)(NU64)(NU16)($1))", # mZe16ToI64
|
||||
"(($3)(NU64)(NU32)($1))", # mZe32ToI64
|
||||
"(($3)(NU64)(NU)($1))", # mZeIToI64
|
||||
"(($3)(NU8)(NU)($1))", # ToU8
|
||||
"(($3)(NU16)(NU)($1))", # ToU16
|
||||
"(($3)(NU32)(NU64)($1))", # ToU32
|
||||
"((double) ($1))", # ToFloat
|
||||
"((double) ($1))", # ToBiggestFloat
|
||||
"float64ToInt32($1)", # ToInt
|
||||
"float64ToInt64($1)"] # ToBiggestInt
|
||||
var
|
||||
a: TLoc
|
||||
t: PType
|
||||
@@ -667,7 +650,6 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
template applyFormat(frmt: untyped) =
|
||||
putIntoDest(p, d, e, frmt % [rdLoc(a), rope(getSize(p.config, t) * 8),
|
||||
getSimpleTypeDesc(p.module, e.typ)])
|
||||
|
||||
case op
|
||||
of mNot:
|
||||
applyFormat("!($1)")
|
||||
@@ -679,35 +661,6 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
applyFormat("$1")
|
||||
of mUnaryMinusF64:
|
||||
applyFormat("-($1)")
|
||||
of mAbsF64:
|
||||
applyFormat("($1 < 0? -($1) : ($1))")
|
||||
# BUGFIX: fabs() makes problems for Tiny C
|
||||
of mZe8ToI:
|
||||
applyFormat("(($3)(NU)(NU8)($1))")
|
||||
of mZe8ToI64:
|
||||
applyFormat("(($3)(NU64)(NU8)($1))")
|
||||
of mZe16ToI:
|
||||
applyFormat("(($3)(NU)(NU16)($1))")
|
||||
of mZe16ToI64:
|
||||
applyFormat("(($3)(NU64)(NU16)($1))")
|
||||
of mZe32ToI64:
|
||||
applyFormat("(($3)(NU64)(NU32)($1))")
|
||||
of mZeIToI64:
|
||||
applyFormat("(($3)(NU64)(NU)($1))")
|
||||
of mToU8:
|
||||
applyFormat("(($3)(NU8)(NU)($1))")
|
||||
of mToU16:
|
||||
applyFormat("(($3)(NU16)(NU)($1))")
|
||||
of mToU32:
|
||||
applyFormat("(($3)(NU32)(NU64)($1))")
|
||||
of mToFloat:
|
||||
applyFormat("((double) ($1))")
|
||||
of mToBiggestFloat:
|
||||
applyFormat("((double) ($1))")
|
||||
of mToInt:
|
||||
applyFormat("float64ToInt32($1)")
|
||||
of mToBiggestInt:
|
||||
applyFormat("float64ToInt64($1)")
|
||||
else:
|
||||
assert false, $op
|
||||
|
||||
@@ -844,7 +797,7 @@ proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc)
|
||||
|
||||
proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
|
||||
var test, u, v: TLoc
|
||||
for i in 1 ..< sonsLen(e):
|
||||
for i in 1 ..< len(e):
|
||||
var it = e.sons[i]
|
||||
assert(it.kind in nkCallKinds)
|
||||
assert(it.sons[0].kind == nkSym)
|
||||
@@ -859,7 +812,8 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
|
||||
v.r.add(".")
|
||||
v.r.add(disc.sym.loc.r)
|
||||
genInExprAux(p, it, u, v, test)
|
||||
let strLit = genStringLiteral(p.module, newStrNode(nkStrLit, field.name.s))
|
||||
let msg = genFieldError(field, disc.sym)
|
||||
let strLit = genStringLiteral(p.module, newStrNode(nkStrLit, msg))
|
||||
if op.magic == mNot:
|
||||
linefmt(p, cpsStmts,
|
||||
"if ($1) #raiseFieldError($2);$n",
|
||||
@@ -978,6 +932,10 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
if d.k == locNone: d.storage = OnHeap
|
||||
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
|
||||
a.r = ropecg(p.module, "(*$1)", [a.r])
|
||||
|
||||
if lfPrepareForMutation in d.flags and ty.kind == tyString and
|
||||
p.config.selectedGC == gcDestructors:
|
||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||
putIntoDest(p, d, n,
|
||||
ropecg(p.module, "$1$3[$2]", [rdLoc(a), rdCharLoc(b), dataField(p)]), a.storage)
|
||||
|
||||
@@ -1102,7 +1060,7 @@ proc gcUsage(conf: ConfigRef; n: PNode) =
|
||||
if conf.selectedGC == gcNone: message(conf, n.info, warnGcMem, n.renderTree)
|
||||
|
||||
proc strLoc(p: BProc; d: TLoc): Rope =
|
||||
if p.config.selectedGc == gcDestructors:
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
result = byRefLoc(p, d)
|
||||
else:
|
||||
result = rdLoc(d)
|
||||
@@ -1129,7 +1087,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
|
||||
var L = 0
|
||||
var appends: Rope = nil
|
||||
var lens: Rope = nil
|
||||
for i in 0 .. sonsLen(e) - 2:
|
||||
for i in 0 .. len(e) - 2:
|
||||
# compute the length expression:
|
||||
initLocExpr(p, e.sons[i + 1], a)
|
||||
if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar:
|
||||
@@ -1168,7 +1126,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||
assert(d.k == locNone)
|
||||
var L = 0
|
||||
initLocExpr(p, e.sons[1], dest)
|
||||
for i in 0 .. sonsLen(e) - 3:
|
||||
for i in 0 .. len(e) - 3:
|
||||
# compute the length expression:
|
||||
initLocExpr(p, e.sons[i + 2], a)
|
||||
if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar:
|
||||
@@ -1235,6 +1193,8 @@ proc genDefault(p: BProc; n: PNode; d: var TLoc) =
|
||||
if d.k == locNone: getTemp(p, n.typ, d, needsInit=true)
|
||||
else: resetLoc(p, d)
|
||||
|
||||
proc trivialDestructor(s: PSym): bool {.inline.} = s.ast[bodyPos].len == 0
|
||||
|
||||
proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
|
||||
var sizeExpr = sizeExpr
|
||||
let typ = a.t
|
||||
@@ -1252,7 +1212,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
|
||||
genAssignment(p, a, b, {})
|
||||
else:
|
||||
let ti = genTypeInfo(p.module, typ, a.lode.info)
|
||||
if bt.destructor != nil:
|
||||
if bt.destructor != nil and not trivialDestructor(bt.destructor):
|
||||
# the prototype of a destructor is ``=destroy(x: var T)`` and that of a
|
||||
# finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling
|
||||
# convention at least:
|
||||
@@ -1343,11 +1303,17 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
|
||||
let seqtype = skipTypes(e.typ, abstractVarRange)
|
||||
var a: TLoc
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
putIntoDest(p, d, e, ropecg(p.module,
|
||||
"($1)#nimNewSeqOfCap($2, $3)", [
|
||||
getTypeDesc(p.module, seqtype),
|
||||
genTypeInfo(p.module, seqtype, e.info), a.rdLoc]))
|
||||
gcUsage(p.config, e)
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
if d.k == locNone: getTemp(p, e.typ, d, needsInit=false)
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
|
||||
[d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
|
||||
getSeqPayloadType(p.module, seqtype)])
|
||||
else:
|
||||
putIntoDest(p, d, e, ropecg(p.module,
|
||||
"($1)#nimNewSeqOfCap($2, $3)", [
|
||||
getTypeDesc(p.module, seqtype),
|
||||
genTypeInfo(p.module, seqtype, e.info), a.rdLoc]))
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genConstExpr(p: BProc, n: PNode): Rope
|
||||
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
|
||||
@@ -1436,7 +1402,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||
elif d.k == locNone:
|
||||
getTemp(p, n.typ, d)
|
||||
|
||||
let l = intLiteral(sonsLen(n))
|
||||
let l = intLiteral(len(n))
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
let seqtype = n.typ
|
||||
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
|
||||
@@ -1446,7 +1412,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||
# generate call to newSeq before adding the elements per hand:
|
||||
genNewSeqAux(p, dest[], l,
|
||||
optNilSeqs notin p.options and n.len == 0)
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
initLoc(arr, locExpr, n[i], OnHeap)
|
||||
arr.r = ropecg(p.module, "$1$3[$2]", [rdLoc(dest[]), intLiteral(i), dataField(p)])
|
||||
arr.storage = OnHeap # we know that sequences are on the heap
|
||||
@@ -1467,7 +1433,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
|
||||
if d.k == locNone:
|
||||
getTemp(p, n.typ, d)
|
||||
# generate call to newSeq before adding the elements per hand:
|
||||
let L = int(lengthOrd(p.config, n.sons[1].typ))
|
||||
let L = toInt(lengthOrd(p.config, n.sons[1].typ))
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
let seqtype = n.typ
|
||||
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
|
||||
@@ -1681,11 +1647,14 @@ proc makePtrType(baseType: PType): PType =
|
||||
addSonSkipIntLit(result, baseType)
|
||||
|
||||
proc makeAddr(n: PNode): PNode =
|
||||
result = newTree(nkHiddenAddr, n)
|
||||
result.typ = makePtrType(n.typ)
|
||||
if n.kind == nkHiddenAddr:
|
||||
result = n
|
||||
else:
|
||||
result = newTree(nkHiddenAddr, n)
|
||||
result.typ = makePtrType(n.typ)
|
||||
|
||||
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||
if p.config.selectedGc == gcDestructors:
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
e.sons[1] = makeAddr(e[1])
|
||||
genCall(p, e, d)
|
||||
return
|
||||
@@ -1714,7 +1683,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
|
||||
if p.config.selectedGc == gcDestructors:
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
binaryStmtAddr(p, e, d, "setLengthStrV2")
|
||||
else:
|
||||
var a, b, call: TLoc
|
||||
@@ -1759,7 +1728,7 @@ proc fewCmps(conf: ConfigRef; s: PNode): bool =
|
||||
elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}:
|
||||
result = true # better not emit the set if int is basetype!
|
||||
else:
|
||||
result = sonsLen(s) <= 8 # 8 seems to be a good value
|
||||
result = len(s) <= 8 # 8 seems to be a good value
|
||||
|
||||
template binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
|
||||
putIntoDest(p, d, e, frmt % [rdLoc(a), rdSetElemLoc(p.config, b, a.t)])
|
||||
@@ -1792,7 +1761,7 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
|
||||
e.sons[2]
|
||||
initLocExpr(p, ea, a)
|
||||
initLoc(b, locExpr, e, OnUnknown)
|
||||
var length = sonsLen(e.sons[1])
|
||||
var length = len(e.sons[1])
|
||||
if length > 0:
|
||||
b.r = rope("(")
|
||||
for i in 0 ..< length:
|
||||
@@ -1928,7 +1897,7 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
|
||||
if srcTyp.kind in {tyPtr, tyPointer} and etyp.kind in IntegralTypes:
|
||||
putIntoDest(p, d, e, "(($1) (ptrdiff_t) ($2))" %
|
||||
[getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage)
|
||||
elif p.config.selectedGc == gcDestructors and etyp.kind in {tySequence, tyString}:
|
||||
elif p.config.selectedGC == gcDestructors and etyp.kind in {tySequence, tyString}:
|
||||
putIntoDest(p, d, e, "(*($1*) (&$2))" %
|
||||
[getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage)
|
||||
else:
|
||||
@@ -2056,25 +2025,26 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) =
|
||||
resetLoc(p, a)
|
||||
|
||||
proc genDestroy(p: BProc; n: PNode) =
|
||||
if optNimV2 in p.config.globalOptions:
|
||||
let t = n[1].typ.skipTypes(abstractInst)
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
let arg = n[1].skipAddr
|
||||
let t = arg.typ.skipTypes(abstractInst)
|
||||
case t.kind
|
||||
of tyString:
|
||||
var a: TLoc
|
||||
initLocExpr(p, n[1].skipAddr, a)
|
||||
linefmt(p, cpsStmts, "if ($1.len && $1.p->allocator) {$n" &
|
||||
initLocExpr(p, arg, a)
|
||||
linefmt(p, cpsStmts, "if ($1.p && $1.p->allocator) {$n" &
|
||||
" $1.p->allocator->dealloc($1.p->allocator, $1.p, $1.p->cap + 1 + sizeof(NI) + sizeof(void*)); }$n",
|
||||
[rdLoc(a)])
|
||||
of tySequence:
|
||||
var a: TLoc
|
||||
initLocExpr(p, n[1].skipAddr, a)
|
||||
linefmt(p, cpsStmts, "if ($1.len && $1.p->allocator) {$n" &
|
||||
initLocExpr(p, arg, a)
|
||||
linefmt(p, cpsStmts, "if ($1.p && $1.p->allocator) {$n" &
|
||||
" $1.p->allocator->dealloc($1.p->allocator, $1.p, ($1.p->cap * sizeof($2)) + sizeof(NI) + sizeof(void*)); }$n",
|
||||
[rdLoc(a), getTypeDesc(p.module, t.lastSon)])
|
||||
else: discard "nothing to do"
|
||||
else:
|
||||
let t = n[1].typ.skipTypes(abstractVar)
|
||||
if t.destructor != nil and t.destructor.magic != mDestroy:
|
||||
if t.destructor != nil and t.destructor.ast[bodyPos].len != 0:
|
||||
internalError(p.config, n.info, "destructor turned out to be not trivial")
|
||||
discard "ignore calls to the default destructor"
|
||||
|
||||
@@ -2113,7 +2083,7 @@ proc genEnumToStr(p: BProc, e: PNode, d: var TLoc) =
|
||||
proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
case op
|
||||
of mOr, mAnd: genAndOr(p, e, d, op)
|
||||
of mNot..mToBiggestInt: unaryArith(p, e, d, op)
|
||||
of mNot..mUnaryMinusF64: unaryArith(p, e, d, op)
|
||||
of mUnaryMinusI..mAbsI: unaryArithOverflow(p, e, d, op)
|
||||
of mAddF64..mDivF64: binaryFloatArith(p, e, d, op)
|
||||
of mShrI..mXor: binaryArith(p, e, d, op)
|
||||
@@ -2161,7 +2131,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
genAssignment(p, dest, call, {})
|
||||
of mAppendStrStr: genStrAppend(p, e, d)
|
||||
of mAppendSeqElem:
|
||||
if p.config.selectedGc == gcDestructors:
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
e.sons[1] = makeAddr(e[1])
|
||||
genCall(p, e, d)
|
||||
else:
|
||||
@@ -2195,6 +2165,22 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
if not p.module.compileToCpp:
|
||||
p.module.includeHeader("<stdalign.h>")
|
||||
putIntoDest(p, d, e, "((NI)alignof($1))" % [getTypeDesc(p.module, t)])
|
||||
of mOffsetOf:
|
||||
var dotExpr: PNode
|
||||
block findDotExpr:
|
||||
if e[1].kind == nkDotExpr:
|
||||
dotExpr = e[1]
|
||||
elif e[1].kind == nkCheckedFieldExpr:
|
||||
dotExpr = e[1][0]
|
||||
else:
|
||||
internalError(p.config, e.info, "unknown ast")
|
||||
let t = dotExpr[0].typ.skipTypes({tyTypeDesc})
|
||||
let member =
|
||||
if t.kind == tyTuple:
|
||||
"Field" & rope(dotExpr[1].sym.position)
|
||||
else:
|
||||
rope(dotExpr[1].sym.name.s)
|
||||
putIntoDest(p,d,e, "((NI)offsetof($1, $2))" % [getTypeDesc(p.module, t), member])
|
||||
of mChr: genSomeCast(p, e, d)
|
||||
of mOrd: genOrd(p, e, d)
|
||||
of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
|
||||
@@ -2255,8 +2241,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mNLen..mNError, mSlurp..mQuoteAst:
|
||||
localError(p.config, e.info, strutils.`%`(errXMustBeCompileTime, e.sons[0].sym.name.s))
|
||||
of mSpawn:
|
||||
let n = lowerings.wrapProcForSpawn(p.module.g.graph, p.module.module, e, e.typ, nil, nil)
|
||||
expr(p, n, d)
|
||||
when defined(leanCompiler):
|
||||
quit "compiler built without support for the 'spawn' statement"
|
||||
else:
|
||||
let n = spawn.wrapProcForSpawn(p.module.g.graph, p.module.module, e, e.typ, nil, nil)
|
||||
expr(p, n, d)
|
||||
of mParallel:
|
||||
when defined(leanCompiler):
|
||||
quit "compiler built without support for the 'parallel' statement"
|
||||
@@ -2276,7 +2265,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mAccessEnv: unaryExpr(p, e, d, "$1.ClE_0")
|
||||
of mSlice:
|
||||
localError(p.config, e.info, "invalid context for 'toOpenArray'; " &
|
||||
" 'toOpenArray' is only valid within a call expression")
|
||||
"'toOpenArray' is only valid within a call expression")
|
||||
else:
|
||||
when defined(debugMagics):
|
||||
echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind
|
||||
@@ -2334,7 +2323,7 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||
let t = n.typ
|
||||
discard getTypeDesc(p.module, t) # so that any fields are initialized
|
||||
if d.k == locNone: getTemp(p, t, d)
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
var it = n.sons[i]
|
||||
if it.kind == nkExprColonExpr: it = it.sons[1]
|
||||
initLoc(rec, locExpr, it, d.storage)
|
||||
@@ -2376,7 +2365,7 @@ proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||
var arr: TLoc
|
||||
if not handleConstExpr(p, n, d):
|
||||
if d.k == locNone: getTemp(p, n.typ, d)
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), d.storage)
|
||||
arr.r = "$1[$2]" % [rdLoc(d), intLiteral(i)]
|
||||
expr(p, n.sons[i], arr)
|
||||
@@ -2546,6 +2535,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
of skVar, skForVar, skResult, skLet:
|
||||
if {sfGlobal, sfThread} * sym.flags != {}:
|
||||
genVarPrototype(p.module, n)
|
||||
if sfCompileTime in sym.flags:
|
||||
genSingleVar(p, sym, n, astdef(sym))
|
||||
|
||||
if sym.loc.r == nil or sym.loc.t == nil:
|
||||
#echo "FAILED FOR PRCO ", p.prc.name.s
|
||||
#echo renderTree(p.prc.ast, {renderIds})
|
||||
@@ -2696,9 +2688,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
if ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
||||
(sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
|
||||
(prc.kind == skMethod):
|
||||
# we have not only the header:
|
||||
if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags:
|
||||
genProc(p.module, prc)
|
||||
# Generate proc even if empty body, bugfix #11651.
|
||||
genProc(p.module, prc)
|
||||
of nkParForStmt: genParForStmt(p, n)
|
||||
of nkState: genState(p, n)
|
||||
of nkGotoState:
|
||||
@@ -2718,9 +2709,14 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
|
||||
of tyBool: result = rope"NIM_FALSE"
|
||||
of tyEnum, tyChar, tyInt..tyInt64, tyUInt..tyUInt64: result = rope"0"
|
||||
of tyFloat..tyFloat128: result = rope"0.0"
|
||||
of tyCString, tyString, tyVar, tyLent, tyPointer, tyPtr, tySequence, tyUntyped,
|
||||
of tyCString, tyVar, tyLent, tyPointer, tyPtr, tyUntyped,
|
||||
tyTyped, tyTypeDesc, tyStatic, tyRef, tyNil:
|
||||
result = rope"NIM_NIL"
|
||||
of tyString, tySequence:
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
result = rope"{0, NIM_NIL}"
|
||||
else:
|
||||
result = rope"NIM_NIL"
|
||||
of tyProc:
|
||||
if t.callConv != ccClosure:
|
||||
result = rope"NIM_NIL"
|
||||
@@ -2744,14 +2740,15 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
|
||||
else:
|
||||
globalError(p.config, info, "cannot create null element for: " & $t.kind)
|
||||
|
||||
proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode, result: var Rope; count: var int) =
|
||||
proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode,
|
||||
result: var Rope; count: var int) =
|
||||
case obj.kind
|
||||
of nkRecList:
|
||||
for it in obj.sons:
|
||||
getNullValueAux(p, t, it, cons, result, count)
|
||||
of nkRecCase:
|
||||
getNullValueAux(p, t, obj.sons[0], cons, result, count)
|
||||
for i in 1 ..< sonsLen(obj):
|
||||
for i in 1 ..< len(obj):
|
||||
getNullValueAux(p, t, lastSon(obj.sons[i]), cons, result, count)
|
||||
of nkSym:
|
||||
if count > 0: result.add ", "
|
||||
@@ -2770,7 +2767,8 @@ proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode, result: var Rope; cou
|
||||
else:
|
||||
localError(p.config, cons.info, "cannot create null element for: " & $obj)
|
||||
|
||||
proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode, result: var Rope; count: var int) =
|
||||
proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode,
|
||||
result: var Rope; count: var int) =
|
||||
var base = t.sons[0]
|
||||
let oldRes = result
|
||||
if not p.module.compileToCpp: result.add "{"
|
||||
@@ -2783,7 +2781,7 @@ proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode, result: var Ro
|
||||
inc count
|
||||
getNullValueAux(p, t, obj, cons, result, count)
|
||||
# do not emit '{}' as that is not valid C:
|
||||
if oldcount == count: result = oldres
|
||||
if oldcount == count: result = oldRes
|
||||
elif not p.module.compileToCpp: result.add "}"
|
||||
|
||||
proc genConstObjConstr(p: BProc; n: PNode): Rope =
|
||||
@@ -2798,7 +2796,7 @@ proc genConstObjConstr(p: BProc; n: PNode): Rope =
|
||||
result = "{$1}$n" % [result]
|
||||
|
||||
proc genConstSimpleList(p: BProc, n: PNode): Rope =
|
||||
var length = sonsLen(n)
|
||||
var length = len(n)
|
||||
result = rope("{")
|
||||
for i in 0 .. length - 2:
|
||||
addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
|
||||
@@ -2857,7 +2855,7 @@ proc genConstExpr(p: BProc, n: PNode): Rope =
|
||||
of nkBracket, nkPar, nkTupleConstr, nkClosure:
|
||||
var t = skipTypes(n.typ, abstractInstOwned)
|
||||
if t.kind == tySequence:
|
||||
if p.config.selectedGc == gcDestructors:
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
result = genConstSeqV2(p, n, n.typ)
|
||||
else:
|
||||
result = genConstSeq(p, n, n.typ)
|
||||
@@ -2881,7 +2879,7 @@ proc genConstExpr(p: BProc, n: PNode): Rope =
|
||||
of nkObjConstr:
|
||||
result = genConstObjConstr(p, n)
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if p.config.selectedGc == gcDestructors:
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
result = genStringLiteralV2Const(p.module, n)
|
||||
else:
|
||||
var d: TLoc
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# included from cgen.nim
|
||||
|
||||
## This include file contains the logic to produce constant string
|
||||
## and seq literals. The code here is responsible that
|
||||
## ``const x = ["a", "b"]`` works without hidden runtime creation code.
|
||||
@@ -19,7 +21,7 @@ template detectVersion(field, corename) =
|
||||
if core == nil or core.kind != skConst:
|
||||
m.g.field = 1
|
||||
else:
|
||||
m.g.field = int ast.getInt(core.ast)
|
||||
m.g.field = toInt(ast.getInt(core.ast))
|
||||
result = m.g.field
|
||||
|
||||
proc detectStrVersion(m: BModule): int =
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
## is needed for incremental compilation.
|
||||
|
||||
import
|
||||
ast, astalgo, ropes, options, strutils, nimlexbase, msgs, cgendata, rodutils,
|
||||
intsets, platform, llstream, tables, sighashes, modulegraphs, pathutils
|
||||
ast, ropes, options, strutils, nimlexbase, cgendata, rodutils,
|
||||
intsets, llstream, tables, modulegraphs, pathutils
|
||||
|
||||
# Careful! Section marks need to contain a tabulator so that they cannot
|
||||
# be part of C string literals.
|
||||
|
||||
@@ -15,7 +15,7 @@ const
|
||||
stringCaseThreshold = 8
|
||||
# above X strings a hash-switch for strings is generated
|
||||
|
||||
proc getTraverseProc(p: BProc, v: Psym): Rope =
|
||||
proc getTraverseProc(p: BProc, v: PSym): Rope =
|
||||
if p.config.selectedGC in {gcMarkAndSweep, gcDestructors, gcV2, gcRefc} and
|
||||
optNimV2 notin p.config.globalOptions and
|
||||
containsGarbageCollectedRef(v.loc.t):
|
||||
@@ -62,7 +62,7 @@ proc endBlock(p: BProc)
|
||||
proc genVarTuple(p: BProc, n: PNode) =
|
||||
var tup, field: TLoc
|
||||
if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
|
||||
var L = sonsLen(n)
|
||||
var L = len(n)
|
||||
|
||||
# if we have a something that's been captured, use the lowering instead:
|
||||
for i in 0 .. L-3:
|
||||
@@ -199,7 +199,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||
# Called by return and break stmts.
|
||||
# Deals with issues faced when jumping out of try/except/finally stmts,
|
||||
|
||||
var stack = newSeq[tuple[n: PNode, inExcept: bool]](0)
|
||||
var stack = newSeq[tuple[fin: PNode, inExcept: bool]](0)
|
||||
|
||||
for i in 1 .. howManyTrys:
|
||||
let tryStmt = p.nestedTryStmts.pop
|
||||
@@ -214,9 +214,9 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||
|
||||
# Find finally-stmt for this try-stmt
|
||||
# and generate a copy of its sons
|
||||
var finallyStmt = lastSon(tryStmt.n)
|
||||
if finallyStmt.kind == nkFinally:
|
||||
genStmts(p, finallyStmt.sons[0])
|
||||
var finallyStmt = tryStmt.fin
|
||||
if finallyStmt != nil:
|
||||
genStmts(p, finallyStmt[0])
|
||||
|
||||
# push old elements again:
|
||||
for i in countdown(howManyTrys-1, 0):
|
||||
@@ -246,10 +246,10 @@ proc genGotoState(p: BProc, n: PNode) =
|
||||
lineF(p, cpsStmts, " goto BeforeRet_;$n", [])
|
||||
var statesCounter = lastOrd(p.config, n.sons[0].typ)
|
||||
if n.len >= 2 and n[1].kind == nkIntLit:
|
||||
statesCounter = n[1].intVal
|
||||
statesCounter = getInt(n[1])
|
||||
let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope
|
||||
else: rope"STATE"
|
||||
for i in 0i64 .. statesCounter:
|
||||
for i in 0i64 .. toInt64(statesCounter):
|
||||
lineF(p, cpsStmts, "case $2: goto $1$2;$n", [prefix, rope(i)])
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
|
||||
@@ -271,19 +271,16 @@ proc genGotoVar(p: BProc; value: PNode) =
|
||||
else:
|
||||
lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
|
||||
|
||||
proc genSingleVar(p: BProc, a: PNode) =
|
||||
let vn = a.sons[0]
|
||||
let v = vn.sym
|
||||
if sfCompileTime in v.flags: return
|
||||
proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
if sfGoto in v.flags:
|
||||
# translate 'var state {.goto.} = X' into 'goto LX':
|
||||
genGotoVar(p, a.sons[2])
|
||||
genGotoVar(p, value)
|
||||
return
|
||||
var targetProc = p
|
||||
var traverseProc: Rope
|
||||
if sfGlobal in v.flags:
|
||||
if v.flags * {sfImportc, sfExportc} == {sfImportc} and
|
||||
a.sons[2].kind == nkEmpty and
|
||||
value.kind == nkEmpty and
|
||||
v.loc.flags * {lfHeader, lfNoDecl} != {}:
|
||||
return
|
||||
if sfPure in v.flags:
|
||||
@@ -313,14 +310,13 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||
if traverseProc != nil and not p.hcrOn:
|
||||
registerTraverseProc(p, v, traverseProc)
|
||||
else:
|
||||
let value = a.sons[2]
|
||||
let imm = isAssignedImmediately(p.config, value)
|
||||
if imm and p.module.compileToCpp and p.splitDecls == 0 and
|
||||
not containsHiddenPointer(v.typ):
|
||||
# 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, a)
|
||||
genLineDir(p, vn)
|
||||
let decl = localVarDecl(p, vn)
|
||||
var tmp: TLoc
|
||||
if value.kind in nkCallKinds and value[0].kind == nkSym and
|
||||
@@ -330,7 +326,7 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||
assert(typ.kind == tyProc)
|
||||
for i in 1..<value.len:
|
||||
if params != nil: params.add(~", ")
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
assert(len(typ) == len(typ.n))
|
||||
add(params, genOtherArg(p, value, i, typ))
|
||||
if params == nil:
|
||||
lineF(p, cpsStmts, "$#;$n", [decl])
|
||||
@@ -363,12 +359,17 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||
lineCg(targetProc, cpsStmts, "if (hcrRegisterGlobal($3, \"$1\", sizeof($2), $4, (void**)&$1))$N",
|
||||
[v.loc.r, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc])
|
||||
startBlock(targetProc)
|
||||
if a.sons[2].kind != nkEmpty:
|
||||
genLineDir(targetProc, a)
|
||||
loadInto(targetProc, a.sons[0], a.sons[2], v.loc)
|
||||
if value.kind != nkEmpty:
|
||||
genLineDir(targetProc, vn)
|
||||
loadInto(targetProc, vn, value, v.loc)
|
||||
if forHcr:
|
||||
endBlock(targetProc)
|
||||
|
||||
proc genSingleVar(p: BProc, a: PNode) =
|
||||
let v = a[0].sym
|
||||
if sfCompileTime in v.flags: return
|
||||
genSingleVar(p, v, a[0], a.sons[2])
|
||||
|
||||
proc genClosureVar(p: BProc, a: PNode) =
|
||||
var immediateAsgn = a.sons[2].kind != nkEmpty
|
||||
var v: TLoc
|
||||
@@ -428,7 +429,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
else:
|
||||
expr(p, it.sons[1], d)
|
||||
endBlock(p)
|
||||
if sonsLen(n) > 1:
|
||||
if len(n) > 1:
|
||||
lineF(p, cpsStmts, "goto $1;$n", [lend])
|
||||
fixLabel(p, lelse)
|
||||
elif it.len == 1:
|
||||
@@ -436,7 +437,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
expr(p, it.sons[0], d)
|
||||
endBlock(p)
|
||||
else: internalError(p.config, n.info, "genIf()")
|
||||
if sonsLen(n) > 1: fixLabel(p, lend)
|
||||
if len(n) > 1: fixLabel(p, lend)
|
||||
|
||||
proc genReturnStmt(p: BProc, t: PNode) =
|
||||
if nfPreventCg in t.flags: return
|
||||
@@ -494,7 +495,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
if aSize > 10_000:
|
||||
localError(p.config, it.info,
|
||||
"case statement has too many cases for computed goto"); return
|
||||
arraySize = aSize.int
|
||||
arraySize = toInt(aSize)
|
||||
if firstOrd(p.config, it.sons[0].typ) != 0:
|
||||
localError(p.config, it.info,
|
||||
"case statement has to start at 0 for computed goto"); return
|
||||
@@ -527,7 +528,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
return
|
||||
|
||||
let val = getOrdValue(it.sons[j])
|
||||
lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(val+id+1)])
|
||||
lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(toInt64(val)+id+1)])
|
||||
|
||||
genStmts(p, it.lastSon)
|
||||
|
||||
@@ -564,7 +565,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
|
||||
# significantly worse code
|
||||
var
|
||||
a: TLoc
|
||||
assert(sonsLen(t) == 2)
|
||||
assert(len(t) == 2)
|
||||
inc(p.withinLoop)
|
||||
genLineDir(p, t)
|
||||
|
||||
@@ -611,7 +612,7 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
|
||||
endBlock(p)
|
||||
|
||||
proc genParForStmt(p: BProc, t: PNode) =
|
||||
assert(sonsLen(t) == 3)
|
||||
assert(len(t) == 3)
|
||||
inc(p.withinLoop)
|
||||
genLineDir(p, t)
|
||||
|
||||
@@ -622,12 +623,12 @@ proc genParForStmt(p: BProc, t: PNode) =
|
||||
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
|
||||
#discard mangleName(forLoopVar)
|
||||
let call = t.sons[1]
|
||||
assert(sonsLen(call) in {4, 5})
|
||||
assert(len(call) in {4, 5})
|
||||
initLocExpr(p, call.sons[1], rangeA)
|
||||
initLocExpr(p, call.sons[2], rangeB)
|
||||
|
||||
# $n at the beginning because of #9710
|
||||
if call.sonsLen == 4: # `||`(a, b, annotation)
|
||||
if call.len == 4: # `||`(a, b, annotation)
|
||||
lineF(p, cpsStmts, "$n#pragma omp $4$n" &
|
||||
"for ($1 = $2; $1 <= $3; ++$1)",
|
||||
[forLoopVar.loc.rdLoc,
|
||||
@@ -675,8 +676,8 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
if p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept:
|
||||
# if the current try stmt have a finally block,
|
||||
# we must execute it before reraising
|
||||
var finallyBlock = p.nestedTryStmts[^1].n[^1]
|
||||
if finallyBlock.kind == nkFinally:
|
||||
let finallyBlock = p.nestedTryStmts[^1].fin
|
||||
if finallyBlock != nil:
|
||||
genSimpleBlock(p, finallyBlock[0])
|
||||
if t[0].kind != nkEmpty:
|
||||
var a: TLoc
|
||||
@@ -690,7 +691,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
lineCg(p, cpsStmts, "#raiseExceptionEx((#Exception*)$1, $2, $3, $4, $5);$n",
|
||||
[e, makeCString(typ.sym.name.s),
|
||||
makeCString(if p.prc != nil: p.prc.name.s else: p.module.module.name.s),
|
||||
makeCString(toFileName(p.config, t.info)), toLinenumber(t.info)])
|
||||
quotedFilename(p.config, t.info), toLinenumber(t.info)])
|
||||
if optNimV2 in p.config.globalOptions:
|
||||
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [e])
|
||||
else:
|
||||
@@ -705,7 +706,7 @@ template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
|
||||
rangeFormat, eqFormat: FormatStr, labl: TLabel) =
|
||||
var
|
||||
x, y: TLoc
|
||||
var length = sonsLen(b)
|
||||
var length = len(b)
|
||||
for i in 0 .. length - 2:
|
||||
if b.sons[i].kind == nkRange:
|
||||
initLocExpr(p, b.sons[i].sons[0], x)
|
||||
@@ -724,7 +725,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
||||
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
|
||||
lineF(p, cpsStmts, "LA$1_: ;$n", [rope(labId + i)])
|
||||
if t.sons[i].kind == nkOfBranch:
|
||||
var length = sonsLen(t.sons[i])
|
||||
var length = len(t.sons[i])
|
||||
exprBlock(p, t.sons[i].sons[length - 1], d)
|
||||
lineF(p, cpsStmts, "goto $1;$n", [lend])
|
||||
else:
|
||||
@@ -758,13 +759,13 @@ template genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
|
||||
rangeFormat, eqFormat: FormatStr) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, t.sons[0], a)
|
||||
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a)
|
||||
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, len(t)-1, a)
|
||||
fixLabel(p, lend)
|
||||
|
||||
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
branches: var openArray[Rope]) =
|
||||
var x: TLoc
|
||||
var length = sonsLen(b)
|
||||
var length = len(b)
|
||||
for i in 0 .. length - 2:
|
||||
assert(b.sons[i].kind != nkRange)
|
||||
initLocExpr(p, b.sons[i], x)
|
||||
@@ -776,8 +777,8 @@ proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
# count how many constant strings there are in the case:
|
||||
var strings = 0
|
||||
for i in 1 ..< sonsLen(t):
|
||||
if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1)
|
||||
for i in 1 ..< len(t):
|
||||
if t.sons[i].kind == nkOfBranch: inc(strings, len(t.sons[i]) - 1)
|
||||
if strings > stringCaseThreshold:
|
||||
var bitMask = math.nextPowerOfTwo(strings) - 1
|
||||
var branches: seq[Rope]
|
||||
@@ -785,7 +786,7 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
|
||||
var labId = p.labels
|
||||
for i in 1 ..< sonsLen(t):
|
||||
for i in 1 ..< len(t):
|
||||
inc(p.labels)
|
||||
if t.sons[i].kind == nkOfBranch:
|
||||
genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels) & "_",
|
||||
@@ -801,16 +802,16 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
lineF(p, cpsStmts, "case $1: $n$2break;$n",
|
||||
[intLiteral(j), branches[j]])
|
||||
lineF(p, cpsStmts, "}$n", []) # else statement:
|
||||
if t.sons[sonsLen(t)-1].kind != nkOfBranch:
|
||||
if t.sons[len(t)-1].kind != nkOfBranch:
|
||||
lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)])
|
||||
# third pass: generate statements
|
||||
var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
|
||||
var lend = genCaseSecondPass(p, t, d, labId, len(t)-1)
|
||||
fixLabel(p, lend)
|
||||
else:
|
||||
genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
|
||||
|
||||
proc branchHasTooBigRange(b: PNode): bool =
|
||||
for i in 0 .. sonsLen(b)-2:
|
||||
for i in 0 .. len(b)-2:
|
||||
# last son is block
|
||||
if (b.sons[i].kind == nkRange) and
|
||||
b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
|
||||
@@ -924,7 +925,8 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
getTemp(p, t.typ, d)
|
||||
genLineDir(p, t)
|
||||
discard cgsym(p.module, "popCurrentExceptionEx")
|
||||
add(p.nestedTryStmts, (t, false))
|
||||
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
|
||||
add(p.nestedTryStmts, (fin, false))
|
||||
startBlock(p, "try {$n")
|
||||
expr(p, t[0], d)
|
||||
endBlock(p)
|
||||
@@ -1021,8 +1023,9 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
|
||||
var length = sonsLen(t)
|
||||
add(p.nestedTryStmts, (t, quirkyExceptions))
|
||||
let length = len(t)
|
||||
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
|
||||
add(p.nestedTryStmts, (fin, quirkyExceptions))
|
||||
expr(p, t.sons[0], d)
|
||||
if not quirkyExceptions:
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n", [])
|
||||
@@ -1039,7 +1042,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
||||
# bug #4230: avoid false sharing between branches:
|
||||
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
|
||||
var blen = sonsLen(t.sons[i])
|
||||
var blen = len(t.sons[i])
|
||||
if blen == 1:
|
||||
# general except section:
|
||||
if i > 1: lineF(p, cpsStmts, "else", [])
|
||||
@@ -1159,36 +1162,10 @@ proc genEmit(p: BProc, t: PNode) =
|
||||
genLineDir(p, t)
|
||||
line(p, cpsStmts, s)
|
||||
|
||||
proc genBreakPoint(p: BProc, t: PNode) =
|
||||
var name: string
|
||||
if optEndb in p.options:
|
||||
if t.kind == nkExprColonExpr:
|
||||
assert(t.sons[1].kind in {nkStrLit..nkTripleStrLit})
|
||||
name = normalize(t.sons[1].strVal)
|
||||
else:
|
||||
inc(p.module.g.breakPointId)
|
||||
name = "bp" & $p.module.g.breakPointId
|
||||
genLineDir(p, t) # BUGFIX
|
||||
appcg(p.module, p.module.g.breakpoints,
|
||||
"#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [
|
||||
toLinenumber(t.info), makeCString(toFilename(p.config, t.info)),
|
||||
makeCString(name)])
|
||||
|
||||
proc genWatchpoint(p: BProc, n: PNode) =
|
||||
if optEndb notin p.options: return
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[1], a)
|
||||
let typ = skipTypes(n.sons[1].typ, abstractVarRange)
|
||||
lineCg(p, cpsStmts, "#dbgRegisterWatchpoint($1, (NCSTRING)$2, $3);$n",
|
||||
[addrLoc(p.config, a), makeCString(renderTree(n.sons[1])),
|
||||
genTypeInfo(p.module, typ, n.info)])
|
||||
|
||||
proc genPragma(p: BProc, n: PNode) =
|
||||
for it in n.sons:
|
||||
case whichPragma(it)
|
||||
of wEmit: genEmit(p, it)
|
||||
of wBreakpoint: genBreakPoint(p, it)
|
||||
of wWatchPoint: genWatchpoint(p, it)
|
||||
of wInjectStmt:
|
||||
var p = newProc(nil, p.module)
|
||||
p.options = p.options - {optLineTrace, optStackTrace}
|
||||
@@ -1211,7 +1188,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
|
||||
var t = skipTypes(objtype, abstractVar)
|
||||
assert t.kind == tyObject
|
||||
discard genTypeInfo(p.module, t, a.lode.info)
|
||||
var L = lengthOrd(p.config, field.typ)
|
||||
var L = toInt64(lengthOrd(p.config, field.typ))
|
||||
if not containsOrIncl(p.module.declaredThings, field.id):
|
||||
appcg(p.module, cfsVars, "extern $1",
|
||||
[discriminatorTableDecl(p.module, t, field)])
|
||||
@@ -1266,11 +1243,13 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs))
|
||||
initLoc(a, locNone, le, OnUnknown)
|
||||
a.flags.incl(lfEnforceDeref)
|
||||
a.flags.incl(lfPrepareForMutation)
|
||||
expr(p, le, a)
|
||||
a.flags.excl(lfPrepareForMutation)
|
||||
if fastAsgn: incl(a.flags, lfNoDeepCopy)
|
||||
assert(a.t != nil)
|
||||
genLineDir(p, ri)
|
||||
loadInto(p, e.sons[0], ri, a)
|
||||
loadInto(p, le, ri, a)
|
||||
else:
|
||||
genLineDir(p, e)
|
||||
asgnFieldDiscriminant(p, e)
|
||||
|
||||
@@ -28,7 +28,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
|
||||
if n == nil: return
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
genTraverseProc(c, accessor, n.sons[i], typ)
|
||||
of nkRecCase:
|
||||
if (n.sons[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
|
||||
@@ -38,7 +38,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
|
||||
if disc.loc.t == nil:
|
||||
internalError(c.p.config, n.info, "genTraverseProc()")
|
||||
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
let branch = n.sons[i]
|
||||
assert branch.kind in {nkOfBranch, nkElse}
|
||||
if branch.kind == nkOfBranch:
|
||||
@@ -87,14 +87,14 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
else:
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
of tyObject:
|
||||
for i in 0 ..< sonsLen(typ):
|
||||
for i in 0 ..< len(typ):
|
||||
var x = typ.sons[i]
|
||||
if x != nil: x = x.skipTypes(skipPtrs)
|
||||
genTraverseProc(c, accessor.parentObj(c.p.module), x)
|
||||
if typ.n != nil: genTraverseProc(c, accessor, typ.n, typ)
|
||||
of tyTuple:
|
||||
let typ = getUniqueType(typ)
|
||||
for i in 0 ..< sonsLen(typ):
|
||||
for i in 0 ..< len(typ):
|
||||
genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", [accessor, i]), typ.sons[i])
|
||||
of tyRef:
|
||||
lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
|
||||
|
||||
@@ -155,6 +155,7 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind =
|
||||
of tyNone, tyTyped: result = ctVoid
|
||||
of tyBool: result = ctBool
|
||||
of tyChar: result = ctChar
|
||||
of tyNil: result = ctPtr
|
||||
of tySet: result = mapSetType(conf, typ)
|
||||
of tyOpenArray, tyArray, tyVarargs, tyUncheckedArray: result = ctArray
|
||||
of tyObject, tyTuple: result = ctStruct
|
||||
@@ -329,6 +330,9 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
|
||||
addAbiCheck(m, typ, result)
|
||||
|
||||
proc pushType(m: BModule, typ: PType) =
|
||||
for i in 0 .. high(m.typeStack):
|
||||
# pointer equality is good enough here:
|
||||
if m.typeStack[i] == typ: return
|
||||
add(m.typeStack, typ)
|
||||
|
||||
proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope =
|
||||
@@ -384,14 +388,53 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
|
||||
result = getTypeForward(m, t, hashType(t))
|
||||
pushType(m, t)
|
||||
of tySequence:
|
||||
let sig = hashType(t)
|
||||
if m.config.selectedGC == gcDestructors:
|
||||
result = getTypeDescAux(m, t, check)
|
||||
if skipTypes(etB.sons[0], typedescInst).kind == tyEmpty:
|
||||
internalError(m.config, "cannot map the empty seq type to a C type")
|
||||
|
||||
result = cacheGetType(m.forwTypeCache, sig)
|
||||
if result == nil:
|
||||
result = getTypeName(m, t, sig)
|
||||
if not isImportedType(t):
|
||||
m.forwTypeCache[sig] = result
|
||||
addForwardStructFormat(m, rope"struct", result)
|
||||
let payload = result & "_Content"
|
||||
addForwardStructFormat(m, rope"struct", payload)
|
||||
|
||||
if cacheGetType(m.typeCache, sig) == nil:
|
||||
m.typeCache[sig] = result
|
||||
#echo "adding ", sig, " ", typeToString(t), " ", m.module.name.s
|
||||
appcg(m, m.s[cfsTypes],
|
||||
"struct $1 {$N" &
|
||||
" NI len; $1_Content* p;$N" &
|
||||
"};$N", [result])
|
||||
else:
|
||||
result = getTypeForward(m, t, hashType(t)) & seqStar(m)
|
||||
pushType(m, t)
|
||||
result = getTypeForward(m, t, sig) & seqStar(m)
|
||||
pushType(m, t)
|
||||
else:
|
||||
result = getTypeDescAux(m, t, check)
|
||||
|
||||
proc getSeqPayloadType(m: BModule; t: PType): Rope =
|
||||
var check = initIntSet()
|
||||
result = getTypeDescWeak(m, t, check) & "_Content"
|
||||
#result = getTypeForward(m, t, hashType(t)) & "_Content"
|
||||
|
||||
proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) =
|
||||
let sig = hashType(t)
|
||||
let result = cacheGetType(m.typeCache, sig)
|
||||
if result == nil:
|
||||
discard getTypeDescAux(m, t, check)
|
||||
else:
|
||||
# little hack for now to prevent multiple definitions of the same
|
||||
# Seq_Content:
|
||||
appcg(m, m.s[cfsTypes], """$N
|
||||
$3ifndef $2_Content_PP
|
||||
$3define $2_Content_PP
|
||||
struct $2_Content { NI cap;#AllocatorObj* allocator;$1 data[SEQ_DECL_SIZE];};
|
||||
$3endif$N
|
||||
""", [getTypeDescAux(m, t.skipTypes(abstractInst).sons[0], check), result, rope"#"])
|
||||
|
||||
proc paramStorageLoc(param: PSym): TStorageLoc =
|
||||
if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin {
|
||||
tyArray, tyOpenArray, tyVarargs}:
|
||||
@@ -407,7 +450,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||
rettype = ~"void"
|
||||
else:
|
||||
rettype = getTypeDescAux(m, t.sons[0], check)
|
||||
for i in 1 ..< sonsLen(t.n):
|
||||
for i in 1 ..< len(t.n):
|
||||
if t.n.sons[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams")
|
||||
var param = t.n.sons[i].sym
|
||||
if isCompileTimeOnly(param.typ): continue
|
||||
@@ -427,7 +470,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||
add(params, param.loc.r)
|
||||
# declare the len field for open arrays:
|
||||
var arr = param.typ
|
||||
if arr.kind in {tyVar, tyLent}: arr = arr.lastSon
|
||||
if arr.kind in {tyVar, tyLent, tySink}: arr = arr.lastSon
|
||||
var j = 0
|
||||
while arr.kind in {tyOpenArray, tyVarargs}:
|
||||
# this fixes the 'sort' bug:
|
||||
@@ -435,7 +478,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||
# need to pass hidden parameter:
|
||||
addf(params, ", NI $1Len_$2", [param.loc.r, j.rope])
|
||||
inc(j)
|
||||
arr = arr.sons[0]
|
||||
arr = arr.sons[0].skipTypes({tySink})
|
||||
if t.sons[0] != nil and isInvalidReturnType(m.config, t.sons[0]):
|
||||
var arr = t.sons[0]
|
||||
if params != nil: add(params, ", ")
|
||||
@@ -468,7 +511,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||
result = nil
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
add(result, genRecordFieldsAux(m, n.sons[i], rectype, check))
|
||||
of nkRecCase:
|
||||
if n.sons[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux")
|
||||
@@ -476,7 +519,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||
# prefix mangled name with "_U" to avoid clashes with other field names,
|
||||
# since identifiers are not allowed to start with '_'
|
||||
var unionBody: Rope = nil
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
case n.sons[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
let k = lastSon(n.sons[i])
|
||||
@@ -513,7 +556,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||
if fieldType.kind == tyUncheckedArray:
|
||||
addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
|
||||
[getTypeDescAux(m, fieldType.elemType, check), sname])
|
||||
elif fieldType.kind == tySequence and m.config.selectedGC != gcDestructors:
|
||||
elif fieldType.kind == tySequence:
|
||||
# we need to use a weak dependency here for trecursive_table.
|
||||
addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
|
||||
elif field.bitsize != 0:
|
||||
@@ -591,7 +634,7 @@ proc getTupleDesc(m: BModule, typ: PType, name: Rope,
|
||||
check: var IntSet): Rope =
|
||||
result = "$1 $2 {$n" % [structOrUnion(typ), name]
|
||||
var desc: Rope = nil
|
||||
for i in 0 ..< sonsLen(typ):
|
||||
for i in 0 ..< len(typ):
|
||||
addf(desc, "$1 Field$2;$n",
|
||||
[getTypeDescAux(m, typ.sons[i], check), rope(i)])
|
||||
if desc == nil: add(result, "char dummy;\L")
|
||||
@@ -627,15 +670,6 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
|
||||
result = if result.kind == tyGenericInst: result.sons[1]
|
||||
else: result.elemType
|
||||
|
||||
proc getSeqPayloadType(m: BModule; t: PType): Rope =
|
||||
result = getTypeForward(m, t, hashType(t)) & "_Content"
|
||||
when false:
|
||||
var check = initIntSet()
|
||||
# XXX remove this duplication:
|
||||
appcg(m, m.s[cfsSeqTypes],
|
||||
"struct $2_Content { NI cap; void* allocator; $1 data[SEQ_DECL_SIZE]; };$n",
|
||||
[getTypeDescAux(m, t.sons[0], check), result])
|
||||
|
||||
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||
# returns only the type's name
|
||||
var t = origTyp.skipTypes(irrelevantForBackend-{tyOwned})
|
||||
@@ -675,11 +709,15 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||
result = name & star
|
||||
m.typeCache[sig] = result
|
||||
of tySequence:
|
||||
# no restriction! We have a forward declaration for structs
|
||||
let name = getTypeForward(m, et, hashType et)
|
||||
result = name & seqStar(m) & star
|
||||
m.typeCache[sig] = result
|
||||
pushType(m, et)
|
||||
if m.config.selectedGC == gcDestructors:
|
||||
result = getTypeDescWeak(m, et, check) & star
|
||||
m.typeCache[sig] = result
|
||||
else:
|
||||
# no restriction! We have a forward declaration for structs
|
||||
let name = getTypeForward(m, et, hashType et)
|
||||
result = name & seqStar(m) & star
|
||||
m.typeCache[sig] = result
|
||||
pushType(m, et)
|
||||
else:
|
||||
# else we have a strong dependency :-(
|
||||
result = getTypeDescAux(m, et, check) & star
|
||||
@@ -731,29 +769,25 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||
"void* ClE_0;$n} $1;$n",
|
||||
[result, rettype, desc])
|
||||
of tySequence:
|
||||
# we cannot use getTypeForward here because then t would be associated
|
||||
# with the name of the struct, not with the pointer to the struct:
|
||||
result = cacheGetType(m.forwTypeCache, sig)
|
||||
if result == nil:
|
||||
result = getTypeName(m, origTyp, sig)
|
||||
if m.config.selectedGC == gcDestructors:
|
||||
result = getTypeDescWeak(m, t, check)
|
||||
else:
|
||||
# we cannot use getTypeForward here because then t would be associated
|
||||
# with the name of the struct, not with the pointer to the struct:
|
||||
result = cacheGetType(m.forwTypeCache, sig)
|
||||
if result == nil:
|
||||
result = getTypeName(m, origTyp, sig)
|
||||
if not isImportedType(t):
|
||||
addForwardStructFormat(m, structOrUnion(t), result)
|
||||
m.forwTypeCache[sig] = result
|
||||
assert(cacheGetType(m.typeCache, sig) == nil)
|
||||
m.typeCache[sig] = result & seqStar(m)
|
||||
if not isImportedType(t):
|
||||
addForwardStructFormat(m, structOrUnion(t), result)
|
||||
m.forwTypeCache[sig] = result
|
||||
assert(cacheGetType(m.typeCache, sig) == nil)
|
||||
m.typeCache[sig] = result & seqStar(m)
|
||||
if not isImportedType(t):
|
||||
if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
|
||||
const
|
||||
cppSeq = "struct $2 : #TGenericSeq {$n"
|
||||
cSeq = "struct $2 {$n" &
|
||||
" #TGenericSeq Sup;$n"
|
||||
if m.config.selectedGC == gcDestructors:
|
||||
appcg(m, m.s[cfsTypes],
|
||||
"typedef struct{ NI cap;#AllocatorObj* allocator;$1 data[SEQ_DECL_SIZE];}$2_Content;$n" &
|
||||
"struct $2 {$n" &
|
||||
" NI len; $2_Content* p;$n" &
|
||||
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
|
||||
else:
|
||||
if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
|
||||
const
|
||||
cppSeq = "struct $2 : #TGenericSeq {$n"
|
||||
cSeq = "struct $2 {$n" &
|
||||
" #TGenericSeq Sup;$n"
|
||||
if m.compileToCpp:
|
||||
appcg(m, m.s[cfsSeqTypes],
|
||||
cppSeq & " $1 data[SEQ_DECL_SIZE];$n" &
|
||||
@@ -762,11 +796,9 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||
appcg(m, m.s[cfsSeqTypes],
|
||||
cSeq & " $1 data[SEQ_DECL_SIZE];$n" &
|
||||
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
|
||||
elif m.config.selectedGC == gcDestructors:
|
||||
internalError(m.config, "cannot map the empty seq type to a C type")
|
||||
else:
|
||||
result = rope("TGenericSeq")
|
||||
add(result, seqStar(m))
|
||||
else:
|
||||
result = rope("TGenericSeq")
|
||||
add(result, seqStar(m))
|
||||
of tyUncheckedArray:
|
||||
result = getTypeName(m, origTyp, sig)
|
||||
m.typeCache[sig] = result
|
||||
@@ -774,7 +806,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||
let foo = getTypeDescAux(m, t.sons[0], check)
|
||||
addf(m.s[cfsTypes], "typedef $1 $2[1];$n", [foo, result])
|
||||
of tyArray:
|
||||
var n: BiggestInt = lengthOrd(m.config, t)
|
||||
var n: BiggestInt = toInt64(lengthOrd(m.config, t))
|
||||
if n <= 0: n = 1 # make an array of at least one element
|
||||
result = getTypeName(m, origTyp, sig)
|
||||
m.typeCache[sig] = result
|
||||
@@ -830,21 +862,8 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||
m.typeCache[sig] = typedefName
|
||||
result = typedefName
|
||||
else:
|
||||
when false:
|
||||
if t.sym != nil and t.sym.name.s == "KeyValuePair":
|
||||
if t == origTyp:
|
||||
echo "wtf: came here"
|
||||
writeStackTrace()
|
||||
quit 1
|
||||
result = cacheGetType(m.forwTypeCache, sig)
|
||||
if result == nil:
|
||||
when false:
|
||||
if t.sym != nil and t.sym.name.s == "KeyValuePair":
|
||||
# or {sfImportc, sfExportc} * t.sym.flags == {}:
|
||||
if t.loc.r != nil:
|
||||
echo t.kind, " ", hashType t
|
||||
echo origTyp.kind, " ", sig
|
||||
assert t.loc.r == nil
|
||||
result = getTypeName(m, origTyp, sig)
|
||||
m.forwTypeCache[sig] = result
|
||||
if not isImportedType(t):
|
||||
@@ -903,8 +922,13 @@ proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
|
||||
|
||||
proc finishTypeDescriptions(m: BModule) =
|
||||
var i = 0
|
||||
var check = initIntSet()
|
||||
while i < len(m.typeStack):
|
||||
discard getTypeDesc(m, m.typeStack[i])
|
||||
let t = m.typeStack[i]
|
||||
if m.config.selectedGC == gcDestructors and t.skipTypes(abstractInst).kind == tySequence:
|
||||
seqV2ContentType(m, t, check)
|
||||
else:
|
||||
discard getTypeDescAux(m, t, check)
|
||||
inc(i)
|
||||
|
||||
template cgDeclFrmt*(s: PSym): string =
|
||||
@@ -933,7 +957,7 @@ proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope =
|
||||
fillLoc(prc.loc, locProc, prc.ast[namePos], mangleName(m, prc), OnUnknown)
|
||||
genProcParams(m, prc.typ, rettype, params, check)
|
||||
# handle the 2 options for hotcodereloading codegen - function pointer
|
||||
# (instead of forward declaration) or header for function budy with "_actual" postfix
|
||||
# (instead of forward declaration) or header for function body with "_actual" postfix
|
||||
let asPtrStr = rope(if asPtr: "_PTR" else: "")
|
||||
var name = prc.loc.r
|
||||
if isReloadable(m, prc) and not asPtr:
|
||||
@@ -955,7 +979,7 @@ proc getNimNode(m: BModule): Rope =
|
||||
result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)]
|
||||
inc(m.typeNodes)
|
||||
|
||||
proc TINameForHcr(m: BModule, name: Rope): Rope =
|
||||
proc tiNameForHcr(m: BModule, name: Rope): Rope =
|
||||
return if m.hcrOn: "(*".rope & name & ")" else: name
|
||||
|
||||
proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
|
||||
@@ -967,7 +991,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
|
||||
else:
|
||||
nimtypeKind = ord(typ.kind)
|
||||
|
||||
let nameHcr = TINameForHcr(m, name)
|
||||
let nameHcr = tiNameForHcr(m, name)
|
||||
|
||||
var size: Rope
|
||||
if tfIncompleteStruct in typ.flags: size = rope"void*"
|
||||
@@ -989,7 +1013,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
|
||||
if typename == "ref object" and origType.skipTypes(skipPtrs).sym != nil:
|
||||
typename = "anon ref object from " & m.config$origType.skipTypes(skipPtrs).sym.info
|
||||
addf(m.s[cfsTypeInit3], "$1.name = $2;$n",
|
||||
[nameHcr, makeCstring typename])
|
||||
[nameHcr, makeCString typename])
|
||||
discard cgsym(m, "nimTypeRoot")
|
||||
addf(m.s[cfsTypeInit3], "$1.nextType = nimTypeRoot; nimTypeRoot=&$1;$n",
|
||||
[nameHcr])
|
||||
@@ -1004,7 +1028,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
|
||||
proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope;
|
||||
info: TLineInfo) =
|
||||
var base: Rope
|
||||
if sonsLen(typ) > 0 and typ.lastSon != nil:
|
||||
if len(typ) > 0 and typ.lastSon != nil:
|
||||
var x = typ.lastSon
|
||||
if typ.kind == tyObject: x = x.skipTypes(skipPtrs)
|
||||
if typ.kind == tyPtr and x.kind == tyObject and incompleteType(x):
|
||||
@@ -1024,6 +1048,8 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
|
||||
internalError(m.config, d.info, "anonymous obj with discriminator")
|
||||
result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)]
|
||||
|
||||
proc rope(arg: Int128): Rope = rope($arg)
|
||||
|
||||
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
|
||||
discard cgsym(m, "TNimNode")
|
||||
var tmp = discriminatorTableName(m, objtype, d)
|
||||
@@ -1041,7 +1067,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
|
||||
info: TLineInfo) =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
var L = sonsLen(n)
|
||||
var L = len(n)
|
||||
if L == 1:
|
||||
genObjectFields(m, typ, origType, n.sons[0], expr, info)
|
||||
elif L > 0:
|
||||
@@ -1072,18 +1098,18 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
|
||||
makeCString(field.name.s),
|
||||
tmp, rope(L)])
|
||||
addf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, rope(L+1)])
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
var b = n.sons[i] # branch
|
||||
var tmp2 = getNimNode(m)
|
||||
genObjectFields(m, typ, origType, lastSon(b), tmp2, info)
|
||||
case b.kind
|
||||
of nkOfBranch:
|
||||
if sonsLen(b) < 2:
|
||||
if len(b) < 2:
|
||||
internalError(m.config, b.info, "genObjectFields; nkOfBranch broken")
|
||||
for j in 0 .. sonsLen(b) - 2:
|
||||
for j in 0 .. len(b) - 2:
|
||||
if b.sons[j].kind == nkRange:
|
||||
var x = int(getOrdValue(b.sons[j].sons[0]))
|
||||
var y = int(getOrdValue(b.sons[j].sons[1]))
|
||||
var x = toInt(getOrdValue(b.sons[j].sons[0]))
|
||||
var y = toInt(getOrdValue(b.sons[j].sons[1]))
|
||||
while x <= y:
|
||||
addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(x), tmp2])
|
||||
inc(x)
|
||||
@@ -1119,7 +1145,7 @@ proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo
|
||||
var tmp = getNimNode(m)
|
||||
if not isImportedType(typ):
|
||||
genObjectFields(m, typ, origType, typ.n, tmp, info)
|
||||
addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [TINameForHcr(m, name), tmp])
|
||||
addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [tiNameForHcr(m, name), tmp])
|
||||
var t = typ.sons[0]
|
||||
while t != nil:
|
||||
t = t.skipTypes(skipPtrs)
|
||||
@@ -1129,7 +1155,7 @@ proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo
|
||||
proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) =
|
||||
genTypeInfoAuxBase(m, typ, typ, name, rope("0"), info)
|
||||
var expr = getNimNode(m)
|
||||
var length = sonsLen(typ)
|
||||
var length = len(typ)
|
||||
if length > 0:
|
||||
var tmp = getTempName(m) & "_" & $length
|
||||
genTNimNodeArray(m, tmp, rope(length))
|
||||
@@ -1147,7 +1173,7 @@ proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo)
|
||||
else:
|
||||
addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n",
|
||||
[expr, rope(length)])
|
||||
addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [TINameForHcr(m, name), expr])
|
||||
addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [tiNameForHcr(m, name), expr])
|
||||
|
||||
proc genEnumInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
|
||||
# Type information for enumerations is quite heavy, so we do some
|
||||
@@ -1155,7 +1181,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
|
||||
# anyway. We generate a cstring array and a loop over it. Exceptional
|
||||
# positions will be reset after the loop.
|
||||
genTypeInfoAux(m, typ, typ, name, info)
|
||||
var length = sonsLen(typ.n)
|
||||
var length = len(typ.n)
|
||||
var nodePtrs = getTempName(m) & "_" & $length
|
||||
genTNimNodeArray(m, nodePtrs, rope(length))
|
||||
var enumNames, specialCases: Rope
|
||||
@@ -1186,17 +1212,17 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
|
||||
add(m.s[cfsTypeInit3], specialCases)
|
||||
addf(m.s[cfsTypeInit3],
|
||||
"$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n$4.node = &$1;$n",
|
||||
[getNimNode(m), rope(length), nodePtrs, TINameForHcr(m, name)])
|
||||
[getNimNode(m), rope(length), nodePtrs, tiNameForHcr(m, name)])
|
||||
if hasHoles:
|
||||
# 1 << 2 is {ntfEnumHole}
|
||||
addf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [TINameForHcr(m, name)])
|
||||
addf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [tiNameForHcr(m, name)])
|
||||
|
||||
proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
|
||||
assert(typ.sons[0] != nil)
|
||||
genTypeInfoAux(m, typ, typ, name, info)
|
||||
var tmp = getNimNode(m)
|
||||
addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
|
||||
[tmp, rope(firstOrd(m.config, typ)), TINameForHcr(m, name)])
|
||||
[tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)])
|
||||
|
||||
proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
|
||||
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1], info), info)
|
||||
@@ -1327,12 +1353,12 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
|
||||
if m.config.selectedGC != gcDestructors:
|
||||
if m.config.selectedGC >= gcMarkAndSweep:
|
||||
let markerProc = genTraverseProc(m, origType, sig)
|
||||
addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [TINameForHcr(m, result), markerProc])
|
||||
addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
|
||||
of tyRef:
|
||||
genTypeInfoAux(m, t, t, result, info)
|
||||
if m.config.selectedGC >= gcMarkAndSweep:
|
||||
let markerProc = genTraverseProc(m, origType, sig)
|
||||
addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [TINameForHcr(m, result), markerProc])
|
||||
addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
|
||||
of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info)
|
||||
of tyArray: genArrayInfo(m, t, result, info)
|
||||
of tySet: genSetInfo(m, t, result, info)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# This module declares some helpers for the C code generator.
|
||||
|
||||
import
|
||||
ast, astalgo, ropes, hashes, strutils, types, msgs, wordrecg,
|
||||
ast, hashes, strutils, msgs, wordrecg,
|
||||
platform, trees, options
|
||||
|
||||
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
|
||||
import
|
||||
ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
|
||||
nversion, nimsets, msgs, std / sha1, bitsets, idents, types,
|
||||
nversion, nimsets, msgs, bitsets, idents, types,
|
||||
ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
|
||||
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
|
||||
rodutils, renderer, cgendata, ccgmerge, aliases,
|
||||
lowerings, tables, sets, ndi, lineinfos, pathutils, transf, enumtostr
|
||||
|
||||
when not defined(leanCompiler):
|
||||
import semparallel
|
||||
import spawn, semparallel
|
||||
|
||||
import strutils except `%` # collides with ropes.`%`
|
||||
|
||||
@@ -113,6 +113,9 @@ proc cgFormatValue(result: var string; value: string): void =
|
||||
proc cgFormatValue(result: var string; value: BiggestInt): void =
|
||||
result.addInt value
|
||||
|
||||
proc cgFormatValue(result: var string; value: Int128): void =
|
||||
result.addInt128 value
|
||||
|
||||
# TODO: please document
|
||||
macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
|
||||
args.expectKind nnkBracket
|
||||
@@ -261,14 +264,8 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||
if optEmbedOrigSrc in p.config.globalOptions:
|
||||
add(p.s(cpsStmts), ~"//" & sourceLine(p.config, t.info) & "\L")
|
||||
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config)
|
||||
if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
|
||||
(p.prc == nil or sfPure notin p.prc.flags):
|
||||
if freshLineInfo(p, t.info):
|
||||
linefmt(p, cpsStmts, "#endb($1, $2);$N",
|
||||
[line, makeCString(toFilename(p.config, t.info))])
|
||||
elif ({optLineTrace, optStackTrace} * p.options ==
|
||||
{optLineTrace, optStackTrace}) and
|
||||
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIDX:
|
||||
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",
|
||||
[line, quotedFilename(p.config, t.info)])
|
||||
@@ -296,13 +293,13 @@ proc lenField(p: BProc): Rope =
|
||||
result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
|
||||
|
||||
proc lenExpr(p: BProc; a: TLoc): Rope =
|
||||
if p.config.selectedGc == gcDestructors:
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
result = rdLoc(a) & ".len"
|
||||
else:
|
||||
result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)]
|
||||
|
||||
proc dataField(p: BProc): Rope =
|
||||
if p.config.selectedGc == gcDestructors:
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
result = rope".p->data"
|
||||
else:
|
||||
result = rope"->data"
|
||||
@@ -380,10 +377,10 @@ proc isComplexValueType(t: PType): bool {.inline.} =
|
||||
(t.kind == tyProc and t.callConv == ccClosure)
|
||||
|
||||
proc resetLoc(p: BProc, loc: var TLoc) =
|
||||
let containsGcRef = p.config.selectedGc != gcDestructors and containsGarbageCollectedRef(loc.t)
|
||||
let containsGcRef = p.config.selectedGC != gcDestructors and containsGarbageCollectedRef(loc.t)
|
||||
let typ = skipTypes(loc.t, abstractVarRange)
|
||||
if isImportedCppType(typ): return
|
||||
if p.config.selectedGc == gcDestructors and typ.kind in {tyString, tySequence}:
|
||||
if p.config.selectedGC == gcDestructors and typ.kind in {tyString, tySequence}:
|
||||
assert rdLoc(loc) != nil
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
|
||||
elif not isComplexValueType(typ):
|
||||
@@ -414,7 +411,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
|
||||
|
||||
proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
|
||||
let typ = loc.t
|
||||
if p.config.selectedGc == gcDestructors and skipTypes(typ, abstractInst).kind in {tyString, tySequence}:
|
||||
if p.config.selectedGC == gcDestructors and skipTypes(typ, abstractInst).kind in {tyString, tySequence}:
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
|
||||
elif not isComplexValueType(typ):
|
||||
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
|
||||
@@ -476,19 +473,6 @@ proc deinitGCFrame(p: BProc): Rope =
|
||||
result = ropecg(p.module,
|
||||
"if (((NU)&GCFRAME_) < 4096) #nimGCFrame(&GCFRAME_);$n", [])
|
||||
|
||||
proc localDebugInfo(p: BProc, s: PSym, retType: PType) =
|
||||
if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
|
||||
# XXX work around a bug: No type information for open arrays possible:
|
||||
if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
|
||||
var a = "&" & s.loc.r
|
||||
if s.kind == skParam and ccgIntroducedPtr(p.config, s, retType): a = s.loc.r
|
||||
lineF(p, cpsInit,
|
||||
"FR_.s[$1].address = (void*)$3; FR_.s[$1].typ = $4; FR_.s[$1].name = $2;$n",
|
||||
[p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
|
||||
genTypeInfo(p.module, s.loc.t, s.info)])
|
||||
inc(p.maxFrameLen)
|
||||
inc p.blocks[p.blocks.len-1].frameLen
|
||||
|
||||
proc localVarDecl(p: BProc; n: PNode): Rope =
|
||||
let s = n.sym
|
||||
if s.loc.k == locNone:
|
||||
@@ -512,7 +496,6 @@ proc assignLocalVar(p: BProc, n: PNode) =
|
||||
let nl = if optLineDir in p.config.options: "" else: "\L"
|
||||
let decl = localVarDecl(p, n) & ";" & nl
|
||||
line(p, cpsLocals, decl)
|
||||
localDebugInfo(p, n.sym, nil)
|
||||
|
||||
include ccgthreadvars
|
||||
|
||||
@@ -559,17 +542,10 @@ proc assignGlobalVar(p: BProc, n: PNode) =
|
||||
if p.withinLoop > 0:
|
||||
# fixes tests/run/tzeroarray:
|
||||
resetLoc(p, s.loc)
|
||||
if p.module.module.options * {optStackTrace, optEndb} ==
|
||||
{optStackTrace, optEndb}:
|
||||
appcg(p.module, p.module.s[cfsDebugInit],
|
||||
"#dbgRegisterGlobal($1, &$2, $3);$n",
|
||||
[makeCString(normalize(s.owner.name.s & '.' & s.name.s)),
|
||||
s.loc.r, genTypeInfo(p.module, s.typ, n.info)])
|
||||
|
||||
proc assignParam(p: BProc, s: PSym, retType: PType) =
|
||||
assert(s.loc.r != nil)
|
||||
scopeMangledParam(p, s)
|
||||
localDebugInfo(p, s, retType)
|
||||
|
||||
proc fillProcLoc(m: BModule; n: PNode) =
|
||||
let sym = n.sym
|
||||
@@ -686,7 +662,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
[loadlib, genStringLiteral(m, lib.path)])
|
||||
else:
|
||||
var p = newProc(nil, m)
|
||||
p.options = p.options - {optStackTrace, optEndb}
|
||||
p.options = p.options - {optStackTrace}
|
||||
var dest: TLoc
|
||||
initLoc(dest, locTemp, lib.path, OnStack)
|
||||
dest.r = getTempName(m)
|
||||
@@ -780,8 +756,8 @@ proc cgsym(m: BModule, name: string): Rope =
|
||||
# we're picky here for the system module too:
|
||||
rawMessage(m.config, errGenerated, "system module needs: " & name)
|
||||
result = sym.loc.r
|
||||
if m.hcrOn and sym != nil and sym.kind in skProc..skIterator:
|
||||
result.addActualPrefixForHCR(m.module, sym)
|
||||
if m.hcrOn and sym != nil and sym.kind in {skProc..skIterator}:
|
||||
result.addActualSuffixForHCR(m.module, sym)
|
||||
|
||||
proc generateHeaders(m: BModule) =
|
||||
add(m.s[cfsHeaders], "\L#include \"nimbase.h\"\L")
|
||||
@@ -1014,7 +990,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
#incl(res.loc.flags, lfIndirect)
|
||||
res.loc.storage = OnUnknown
|
||||
|
||||
for i in 1 ..< sonsLen(prc.typ.n):
|
||||
for i in 1 ..< len(prc.typ.n):
|
||||
let param = prc.typ.n.sons[i].sym
|
||||
if param.typ.isCompileTimeOnly: continue
|
||||
assignParam(p, param, prc.typ[0])
|
||||
@@ -1030,6 +1006,11 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
generatedProc = ropecg(p.module, "$N$1 {$n$2$3$4}$N$N",
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
|
||||
else:
|
||||
if m.hcrOn and isReloadable(m, prc):
|
||||
# Add forward declaration for "_actual"-suffixed functions defined in the same module (or inline).
|
||||
# This fixes the use of methods and also the case when 2 functions within the same module
|
||||
# call each other using directly the "_actual" versions (an optimization) - see issue #11608
|
||||
addf(m.s[cfsProcHeaders], "$1;\n", [header])
|
||||
generatedProc = ropecg(p.module, "$N$1 {$N", [header])
|
||||
add(generatedProc, initGCFrame(p))
|
||||
if optStackTrace in prc.options:
|
||||
@@ -1058,7 +1039,8 @@ proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
|
||||
result = (sfCompileToCpp in m.module.flags and
|
||||
sfCompileToCpp notin sym.getModule().flags and
|
||||
m.config.cmd != cmdCompileToCpp) or (
|
||||
sym.flags * {sfImportc, sfInfixCall, sfCompilerProc} == {sfImportc} and
|
||||
sym.flags * {sfInfixCall, sfCompilerProc, sfMangleCpp} == {} and
|
||||
sym.flags * {sfImportc, sfExportc} != {} and
|
||||
sym.magic == mNone and
|
||||
m.config.cmd == cmdCompileToCpp)
|
||||
|
||||
@@ -1105,7 +1087,8 @@ proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
# a check for ``m.declaredThings``.
|
||||
if not containsOrIncl(m.declaredThings, prc.id):
|
||||
#if prc.loc.k == locNone:
|
||||
# mangle the inline proc based on the module where it is defined - not on the first module that uses it
|
||||
# mangle the inline proc based on the module where it is defined -
|
||||
# not on the first module that uses it
|
||||
fillProcLoc(findPendingModule(m, prc), prc.ast[namePos])
|
||||
#elif {sfExportc, sfImportc} * prc.flags == {}:
|
||||
# # reset name to restore consistency in case of hashing collisions:
|
||||
@@ -1309,7 +1292,6 @@ proc genMainProc(m: BModule) =
|
||||
PreMainBody = "$N" &
|
||||
"void PreMainInner(void) {$N" &
|
||||
"$2" &
|
||||
"$3" &
|
||||
"}$N$N" &
|
||||
PosixCmdLine &
|
||||
"void PreMain(void) {$N" &
|
||||
@@ -1399,17 +1381,11 @@ proc genMainProc(m: BModule) =
|
||||
elif m.config.target.targetOS == osGenode:
|
||||
m.includeHeader("<libc/component.h>")
|
||||
|
||||
if optEndb in m.config.options:
|
||||
for i in 0..<m.config.m.fileInfos.len:
|
||||
m.g.breakpoints.addf("dbgRegisterFilename($1);$N",
|
||||
[m.config.m.fileInfos[i].projPath.string.makeCString])
|
||||
|
||||
let initStackBottomCall =
|
||||
if m.config.target.targetOS == osStandalone or m.config.selectedGC == gcNone: "".rope
|
||||
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])
|
||||
inc(m.labels)
|
||||
appcg(m, m.s[cfsProcs], PreMainBody, [
|
||||
m.g.mainDatInit, m.g.breakpoints, m.g.otherModsInit])
|
||||
appcg(m, m.s[cfsProcs], PreMainBody, [m.g.mainDatInit, m.g.otherModsInit])
|
||||
|
||||
if m.config.target.targetOS == osWindows and
|
||||
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
|
||||
@@ -1474,20 +1450,20 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
|
||||
datInit = m.getDatInitName
|
||||
|
||||
if m.hcrOn:
|
||||
var hcr_module_meta = "$nN_LIB_PRIVATE const char* hcr_module_list[] = {$n" % []
|
||||
var hcrModuleMeta = "$nN_LIB_PRIVATE const char* hcr_module_list[] = {$n" % []
|
||||
let systemModulePath = getModuleDllPath(m, g.modules[g.graph.config.m.systemFileIdx.int].module)
|
||||
let mainModulePath = getModuleDllPath(m, m.module)
|
||||
if sfMainModule in m.module.flags:
|
||||
addf(hcr_module_meta, "\t$1,$n", [systemModulePath])
|
||||
addf(hcrModuleMeta, "\t$1,$n", [systemModulePath])
|
||||
g.graph.importDeps.withValue(FileIndex(m.module.position), deps):
|
||||
for curr in deps[]:
|
||||
addf(hcr_module_meta, "\t$1,$n", [getModuleDllPath(m, g.modules[curr.int].module)])
|
||||
addf(hcr_module_meta, "\t\"\"};$n", [])
|
||||
addf(hcr_module_meta, "$nN_LIB_EXPORT N_NIMCALL(void**, HcrGetImportedModules)() { return (void**)hcr_module_list; }$n", [])
|
||||
addf(hcr_module_meta, "$nN_LIB_EXPORT N_NIMCALL(char*, HcrGetSigHash)() { return \"$1\"; }$n$n",
|
||||
addf(hcrModuleMeta, "\t$1,$n", [getModuleDllPath(m, g.modules[curr.int].module)])
|
||||
addf(hcrModuleMeta, "\t\"\"};$n", [])
|
||||
addf(hcrModuleMeta, "$nN_LIB_EXPORT N_NIMCALL(void**, HcrGetImportedModules)() { return (void**)hcr_module_list; }$n", [])
|
||||
addf(hcrModuleMeta, "$nN_LIB_EXPORT N_NIMCALL(char*, HcrGetSigHash)() { return \"$1\"; }$n$n",
|
||||
[($sigHash(m.module)).rope])
|
||||
if sfMainModule in m.module.flags:
|
||||
add(g.mainModProcs, hcr_module_meta)
|
||||
add(g.mainModProcs, hcrModuleMeta)
|
||||
addf(g.mainModProcs, "static void* hcr_handle;$N", [])
|
||||
addf(g.mainModProcs, "N_LIB_EXPORT N_NIMCALL(void, $1)(void);$N", [init])
|
||||
addf(g.mainModProcs, "N_LIB_EXPORT N_NIMCALL(void, $1)(void);$N", [datInit])
|
||||
@@ -1511,7 +1487,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
|
||||
add(g.mainDatInit, "\t*cmd_count = cmdCount;\n")
|
||||
add(g.mainDatInit, "\t*cmd_line = cmdLine;\n")
|
||||
else:
|
||||
add(m.s[cfsInitProc], hcr_module_meta)
|
||||
add(m.s[cfsInitProc], hcrModuleMeta)
|
||||
return
|
||||
|
||||
if m.s[cfsDatInitProc].len > 0:
|
||||
@@ -1774,14 +1750,10 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
|
||||
if sfSystemModule in module.flags:
|
||||
incl result.flags, preventStackTrace
|
||||
excl(result.preInitProc.options, optStackTrace)
|
||||
let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi")
|
||||
let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCfilePath(g.config, filename), "ndi")
|
||||
else: AbsoluteFile""
|
||||
open(result.ndi, ndiName, g.config)
|
||||
|
||||
proc nullify[T](arr: var T) =
|
||||
for i in low(arr)..high(arr):
|
||||
arr[i] = Rope(nil)
|
||||
|
||||
proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
|
||||
result = rawNewModule(g, module, AbsoluteFile toFullPath(conf, module.position.FileIndex))
|
||||
|
||||
@@ -1805,7 +1777,7 @@ proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
|
||||
let f = if graph.config.headerFile.len > 0: AbsoluteFile graph.config.headerFile
|
||||
else: graph.config.projectFull
|
||||
g.generatedHeader = rawNewModule(g, module,
|
||||
changeFileExt(completeCFilePath(graph.config, f), hExt))
|
||||
changeFileExt(completeCfilePath(graph.config, f), hExt))
|
||||
incl g.generatedHeader.flags, isHeaderFile
|
||||
|
||||
proc writeHeader(m: BModule) =
|
||||
@@ -1838,9 +1810,9 @@ proc writeHeader(m: BModule) =
|
||||
proc getCFile(m: BModule): AbsoluteFile =
|
||||
let ext =
|
||||
if m.compileToCpp: ".nim.cpp"
|
||||
elif m.config.cmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".nim.m"
|
||||
elif m.config.cmd == cmdCompileToOC or sfCompileToObjc in m.module.flags: ".nim.m"
|
||||
else: ".nim.c"
|
||||
result = changeFileExt(completeCFilePath(m.config, withPackageName(m.config, m.cfilename)), ext)
|
||||
result = changeFileExt(completeCfilePath(m.config, withPackageName(m.config, m.cfilename)), ext)
|
||||
|
||||
when false:
|
||||
proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
|
||||
@@ -1872,21 +1844,25 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
if b == nil: return
|
||||
var m = BModule(b)
|
||||
if passes.skipCodegen(m.config, n): return
|
||||
if passes.skipCodegen(m.config, n) or
|
||||
not moduleHasChanged(m.g.graph, m.module):
|
||||
return
|
||||
m.initProc.options = initProcOptions(m)
|
||||
#softRnl = if optLineDir in m.config.options: noRnl else: rnl
|
||||
# XXX replicate this logic!
|
||||
let transformed_n = transformStmt(m.g.graph, m.module, n)
|
||||
let transformedN = transformStmt(m.g.graph, m.module, n)
|
||||
if m.hcrOn:
|
||||
addHcrInitGuards(m.initProc, transformed_n, m.inHcrInitGuard)
|
||||
addHcrInitGuards(m.initProc, transformedN, m.inHcrInitGuard)
|
||||
else:
|
||||
genStmts(m.initProc, transformed_n)
|
||||
genStmts(m.initProc, transformedN)
|
||||
|
||||
proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
|
||||
result = true
|
||||
if optForceFullMake notin m.config.globalOptions:
|
||||
if not equalsFile(code, cfile.cname):
|
||||
if m.config.symbolFiles == readOnlySf: #isDefined(m.config, "nimdiff"):
|
||||
if not moduleHasChanged(m.g.graph, m.module):
|
||||
result = false
|
||||
elif not equalsFile(code, cfile.cname):
|
||||
if false:
|
||||
#m.config.symbolFiles == readOnlySf: #isDefined(m.config, "nimdiff"):
|
||||
if fileExists(cfile.cname):
|
||||
copyFile(cfile.cname.string, cfile.cname.string & ".backup")
|
||||
echo "diff ", cfile.cname.string, ".backup ", cfile.cname.string
|
||||
@@ -1894,12 +1870,15 @@ proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
|
||||
echo "new file ", cfile.cname.string
|
||||
if not writeRope(code, cfile.cname):
|
||||
rawMessage(m.config, errCannotOpenFile, cfile.cname.string)
|
||||
return
|
||||
if fileExists(cfile.obj) and os.fileNewer(cfile.obj.string, cfile.cname.string):
|
||||
result = true
|
||||
elif fileExists(cfile.obj) and os.fileNewer(cfile.obj.string, cfile.cname.string):
|
||||
result = false
|
||||
else:
|
||||
result = true
|
||||
else:
|
||||
if not writeRope(code, cfile.cname):
|
||||
rawMessage(m.config, errCannotOpenFile, cfile.cname.string)
|
||||
result = true
|
||||
|
||||
# We need 2 different logics here: pending modules (including
|
||||
# 'nim__dat') may require file merging for the combination of dead code
|
||||
@@ -1911,18 +1890,19 @@ proc writeModule(m: BModule, pending: bool) =
|
||||
let cfile = getCFile(m)
|
||||
|
||||
if true or optForceFullMake in m.config.globalOptions:
|
||||
genInitCode(m)
|
||||
finishTypeDescriptions(m)
|
||||
if sfMainModule in m.module.flags:
|
||||
# generate main file:
|
||||
genMainProc(m)
|
||||
add(m.s[cfsProcHeaders], m.g.mainModProcs)
|
||||
generateThreadVarsSize(m)
|
||||
if moduleHasChanged(m.g.graph, m.module):
|
||||
genInitCode(m)
|
||||
finishTypeDescriptions(m)
|
||||
if sfMainModule in m.module.flags:
|
||||
# generate main file:
|
||||
genMainProc(m)
|
||||
add(m.s[cfsProcHeaders], m.g.mainModProcs)
|
||||
generateThreadVarsSize(m)
|
||||
|
||||
var cf = Cfile(nimname: m.module.name.s, cname: cfile,
|
||||
obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
|
||||
obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {})
|
||||
var code = genModule(m, cf)
|
||||
if code != nil:
|
||||
if code != nil or m.config.symbolFiles != disabledSf:
|
||||
when hasTinyCBackend:
|
||||
if conf.cmd == cmdRun:
|
||||
tccgen.compileCCode($code)
|
||||
@@ -1932,7 +1912,7 @@ proc writeModule(m: BModule, pending: bool) =
|
||||
addFileToCompile(m.config, cf)
|
||||
elif pending and mergeRequired(m) and sfMainModule notin m.module.flags:
|
||||
let cf = Cfile(nimname: m.module.name.s, cname: cfile,
|
||||
obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
|
||||
obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {})
|
||||
mergeFiles(cfile, m)
|
||||
genInitCode(m)
|
||||
finishTypeDescriptions(m)
|
||||
@@ -1946,7 +1926,7 @@ proc writeModule(m: BModule, pending: bool) =
|
||||
# ``system.c`` but then compilation fails due to an error. This means
|
||||
# that ``system.o`` is missing, so we need to call the C compiler for it:
|
||||
var cf = Cfile(nimname: m.module.name.s, cname: cfile,
|
||||
obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
|
||||
obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {})
|
||||
if not fileExists(cf.obj): cf.flags = {CfileFlag.Cached}
|
||||
addFileToCompile(m.config, cf)
|
||||
close(m.ndi)
|
||||
@@ -1954,7 +1934,7 @@ proc writeModule(m: BModule, pending: bool) =
|
||||
proc updateCachedModule(m: BModule) =
|
||||
let cfile = getCFile(m)
|
||||
var cf = Cfile(nimname: m.module.name.s, cname: cfile,
|
||||
obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
|
||||
obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {})
|
||||
|
||||
if mergeRequired(m) and sfMainModule notin m.module.flags:
|
||||
mergeFiles(cfile, m)
|
||||
@@ -1979,48 +1959,44 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||
for destructorCall in graph.globalDestructors:
|
||||
n.add destructorCall
|
||||
if passes.skipCodegen(m.config, n): return
|
||||
# if the module is cached, we don't regenerate the main proc
|
||||
# nor the dispatchers? But if the dispatchers changed?
|
||||
# XXX emit the dispatchers into its own .c file?
|
||||
if n != nil:
|
||||
m.initProc.options = initProcOptions(m)
|
||||
genStmts(m.initProc, n)
|
||||
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?
|
||||
# XXX emit the dispatchers into its own .c file?
|
||||
if n != nil:
|
||||
m.initProc.options = initProcOptions(m)
|
||||
genStmts(m.initProc, n)
|
||||
|
||||
if m.hcrOn:
|
||||
# make sure this is pulled in (meaning hcrGetGlobal() is called for it during init)
|
||||
discard cgsym(m, "programResult")
|
||||
if m.inHcrInitGuard:
|
||||
endBlock(m.initProc)
|
||||
|
||||
if sfMainModule in m.module.flags:
|
||||
if m.hcrOn:
|
||||
# pull ("define" since they are inline when HCR is on) these functions in the main file
|
||||
# so it can load the HCR runtime and later pass the library handle to the HCR runtime which
|
||||
# will in turn pass it to the other modules it initializes so they can initialize the
|
||||
# register/get procs so they don't have to have the definitions of these functions as well
|
||||
discard cgsym(m, "nimLoadLibrary")
|
||||
discard cgsym(m, "nimLoadLibraryError")
|
||||
discard cgsym(m, "nimGetProcAddr")
|
||||
discard cgsym(m, "procAddrError")
|
||||
discard cgsym(m, "rawWrite")
|
||||
# make sure this is pulled in (meaning hcrGetGlobal() is called for it during init)
|
||||
discard cgsym(m, "programResult")
|
||||
if m.inHcrInitGuard:
|
||||
endBlock(m.initProc)
|
||||
|
||||
# raise dependencies on behalf of genMainProc
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC != gcNone:
|
||||
discard cgsym(m, "initStackBottomWith")
|
||||
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
|
||||
discard cgsym(m, "initThreadVarsEmulation")
|
||||
if sfMainModule in m.module.flags:
|
||||
if m.hcrOn:
|
||||
# pull ("define" since they are inline when HCR is on) these functions in the main file
|
||||
# so it can load the HCR runtime and later pass the library handle to the HCR runtime which
|
||||
# will in turn pass it to the other modules it initializes so they can initialize the
|
||||
# register/get procs so they don't have to have the definitions of these functions as well
|
||||
discard cgsym(m, "nimLoadLibrary")
|
||||
discard cgsym(m, "nimLoadLibraryError")
|
||||
discard cgsym(m, "nimGetProcAddr")
|
||||
discard cgsym(m, "procAddrError")
|
||||
discard cgsym(m, "rawWrite")
|
||||
|
||||
if m.g.breakpoints != nil:
|
||||
discard cgsym(m, "dbgRegisterBreakpoint")
|
||||
if optEndb in m.config.options:
|
||||
discard cgsym(m, "dbgRegisterFilename")
|
||||
# raise dependencies on behalf of genMainProc
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC != gcNone:
|
||||
discard cgsym(m, "initStackBottomWith")
|
||||
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
|
||||
discard 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)
|
||||
if m.g.forwardedProcs.len == 0:
|
||||
incl m.flags, objHasKidsValid
|
||||
let disp = generateMethodDispatchers(graph)
|
||||
for x in disp: genProcAux(m, x.sym)
|
||||
|
||||
m.g.modules_closed.add m
|
||||
m.g.modulesClosed.add m
|
||||
|
||||
proc genForwardedProcs(g: BModuleList) =
|
||||
# Forward declared proc:s lack bodies when first encountered, so they're given
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## This module contains the data structures for the C code generation phase.
|
||||
|
||||
import
|
||||
ast, astalgo, ropes, passes, options, intsets, platform, sighashes,
|
||||
ast, ropes, options, intsets,
|
||||
tables, ndi, lineinfos, pathutils, modulegraphs
|
||||
|
||||
type
|
||||
@@ -73,7 +73,7 @@ type
|
||||
noSafePoints*: bool # the proc doesn't use safe points in exception handling
|
||||
lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements
|
||||
currLineInfo*: TLineInfo # AST codegen will make this superfluous
|
||||
nestedTryStmts*: seq[tuple[n: PNode, inExcept: bool]]
|
||||
nestedTryStmts*: seq[tuple[fin: PNode, inExcept: bool]]
|
||||
# in how many nested try statements we are
|
||||
# (the vars must be volatile then)
|
||||
# bool is true when are in the except part of a try block
|
||||
@@ -100,7 +100,7 @@ type
|
||||
TypeCache* = Table[SigHash, Rope]
|
||||
TypeCacheWithOwner* = Table[SigHash, tuple[str: Rope, owner: PSym]]
|
||||
|
||||
Codegenflag* = enum
|
||||
CodegenFlag* = enum
|
||||
preventStackTrace, # true if stack traces need to be prevented
|
||||
usesThreadVars, # true if the module uses a thread var
|
||||
frameDeclared, # hack for ROD support so that we don't declare
|
||||
@@ -114,11 +114,9 @@ type
|
||||
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
|
||||
mapping*: Rope # the generated mapping file (if requested)
|
||||
modules*: seq[BModule] # list of all compiled modules
|
||||
modules_closed*: seq[BModule] # list of the same compiled modules, but in the order they were closed
|
||||
modulesClosed*: seq[BModule] # list of the same compiled modules, but in the order they were closed
|
||||
forwardedProcs*: seq[PSym] # proc:s that did not yet have a body
|
||||
generatedHeader*: BModule
|
||||
breakPointId*: int
|
||||
breakpoints*: Rope # later the breakpoints are inserted into the main proc
|
||||
typeInfoMarker*: TypeCacheWithOwner
|
||||
config*: ConfigRef
|
||||
graph*: ModuleGraph
|
||||
@@ -137,7 +135,7 @@ type
|
||||
|
||||
TCGen = object of PPassContext # represents a C source file
|
||||
s*: TCFileSections # sections of the C file
|
||||
flags*: set[Codegenflag]
|
||||
flags*: set[CodegenFlag]
|
||||
module*: PSym
|
||||
filename*: AbsoluteFile
|
||||
cfilename*: AbsoluteFile # filename of the module (including path,
|
||||
@@ -196,6 +194,6 @@ proc newModuleList*(g: ModuleGraph): BModuleList =
|
||||
config: g.config, graph: g, nimtvDeclared: initIntSet())
|
||||
|
||||
iterator cgenModules*(g: BModuleList): BModule =
|
||||
for m in g.modules_closed:
|
||||
for m in g.modulesClosed:
|
||||
# iterate modules in the order they were closed
|
||||
yield m
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## This module implements code generation for multi methods.
|
||||
|
||||
import
|
||||
intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys,
|
||||
intsets, options, ast, msgs, idents, renderer, types, magicsys,
|
||||
sempass2, strutils, modulegraphs, lineinfos
|
||||
|
||||
proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode =
|
||||
@@ -48,7 +48,7 @@ proc methodCall*(n: PNode; conf: ConfigRef): PNode =
|
||||
if disp != nil:
|
||||
result.sons[0].sym = disp
|
||||
# change the arguments to up/downcasts to fit the dispatcher's parameters:
|
||||
for i in 1 ..< sonsLen(result):
|
||||
for i in 1 ..< len(result):
|
||||
result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true, conf)
|
||||
else:
|
||||
localError(conf, n.info, "'" & $result.sons[0] & "' lacks a dispatcher")
|
||||
@@ -58,10 +58,10 @@ type
|
||||
|
||||
proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
|
||||
if a.name.id != b.name.id: return
|
||||
if sonsLen(a.typ) != sonsLen(b.typ):
|
||||
if len(a.typ) != len(b.typ):
|
||||
return
|
||||
|
||||
for i in 1 ..< sonsLen(a.typ):
|
||||
for i in 1 ..< len(a.typ):
|
||||
var aa = a.typ.sons[i]
|
||||
var bb = b.typ.sons[i]
|
||||
while true:
|
||||
@@ -118,7 +118,7 @@ proc createDispatcher(s: PSym): PSym =
|
||||
disp.ast.sons[bodyPos] = newNodeI(nkEmpty, s.info)
|
||||
disp.loc.r = nil
|
||||
if s.typ.sons[0] != nil:
|
||||
if disp.ast.sonsLen > resultPos:
|
||||
if disp.ast.len > resultPos:
|
||||
disp.ast.sons[resultPos].sym = copySym(s.ast.sons[resultPos].sym)
|
||||
else:
|
||||
# We've encountered a method prototype without a filled-in
|
||||
@@ -136,7 +136,7 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
|
||||
# from later definitions, particularly the resultPos slot. Also,
|
||||
# the lock level of the dispatcher needs to be updated/checked
|
||||
# against that of the method.
|
||||
if disp.ast.sonsLen > resultPos and meth.ast.sonsLen > resultPos and
|
||||
if disp.ast.len > resultPos and meth.ast.len > resultPos and
|
||||
disp.ast.sons[resultPos].kind == nkEmpty:
|
||||
disp.ast.sons[resultPos] = copyTree(meth.ast.sons[resultPos])
|
||||
|
||||
@@ -198,7 +198,7 @@ proc relevantCol(methods: seq[PSym], col: int): bool =
|
||||
return true
|
||||
|
||||
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
|
||||
for col in 1 ..< sonsLen(a.typ):
|
||||
for col in 1 ..< len(a.typ):
|
||||
if contains(relevantCols, col):
|
||||
var aa = skipTypes(a.typ.sons[col], skipPtrs)
|
||||
var bb = skipTypes(b.typ.sons[col], skipPtrs)
|
||||
@@ -228,7 +228,7 @@ proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
|
||||
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PSym =
|
||||
var base = methods[0].ast[dispatcherPos].sym
|
||||
result = base
|
||||
var paramLen = sonsLen(base.typ)
|
||||
var paramLen = len(base.typ)
|
||||
var nilchecks = newNodeI(nkStmtList, base.info)
|
||||
var disp = newNodeI(nkIfStmt, base.info)
|
||||
var ands = getSysMagic(g, unknownLineInfo(), "and", mAnd)
|
||||
@@ -288,7 +288,7 @@ proc generateMethodDispatchers*(g: ModuleGraph): PNode =
|
||||
result = newNode(nkStmtList)
|
||||
for bucket in 0 ..< len(g.methods):
|
||||
var relevantCols = initIntSet()
|
||||
for col in 1 ..< sonsLen(g.methods[bucket].methods[0].typ):
|
||||
for col in 1 ..< len(g.methods[bucket].methods[0].typ):
|
||||
if relevantCol(g.methods[bucket].methods, col): incl(relevantCols, col)
|
||||
if optMultiMethods notin g.config.globalOptions:
|
||||
# if multi-methods are not enabled, we are interested only in the first field
|
||||
|
||||
@@ -90,9 +90,6 @@
|
||||
# :unrollFinally = true
|
||||
# goto nearestFinally (or -1 if not exists)
|
||||
#
|
||||
# Every finally block calls closureIterEndFinally() upon its successful
|
||||
# completion.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# try:
|
||||
@@ -126,13 +123,14 @@
|
||||
# if :curExc.isNil:
|
||||
# return :tmpResult
|
||||
# else:
|
||||
# closureIterSetupExc(nil)
|
||||
# raise
|
||||
# state = -1 # Goto next state. In this case we just exit
|
||||
# break :stateLoop
|
||||
|
||||
import
|
||||
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, idents,
|
||||
renderer, types, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos
|
||||
ast, msgs, idents,
|
||||
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos
|
||||
|
||||
type
|
||||
Ctx = object
|
||||
@@ -174,7 +172,7 @@ proc newStateAssgn(ctx: var Ctx, toValue: PNode): PNode =
|
||||
proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode =
|
||||
# Creates state assignment:
|
||||
# :state = stateNo
|
||||
ctx.newStateAssgn(newIntTypeNode(nkIntLit, stateNo, ctx.g.getSysType(TLineInfo(), tyInt)))
|
||||
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), ctx.fn, ctx.fn.info)
|
||||
@@ -359,7 +357,7 @@ proc addElseToExcept(ctx: var Ctx, n: PNode) =
|
||||
block: # :unrollFinally = true
|
||||
branchBody.add(newTree(nkAsgn,
|
||||
ctx.newUnrollFinallyAccess(n.info),
|
||||
newIntTypeNode(nkIntLit, 1, ctx.g.getSysType(n.info, tyBool))))
|
||||
newIntTypeNode(1, ctx.g.getSysType(n.info, tyBool))))
|
||||
|
||||
block: # :curExc = getCurrentException()
|
||||
branchBody.add(newTree(nkAsgn,
|
||||
@@ -603,7 +601,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||
result.add(n)
|
||||
result.add(ctx.newEnvVarAccess(tmp))
|
||||
|
||||
of nkCallKinds:
|
||||
of nkCallKinds, nkChckRange, nkChckRangeF, nkChckRange64:
|
||||
var ns = false
|
||||
for i in 0 ..< n.len:
|
||||
n[i] = ctx.lowerStmtListExprs(n[i], ns)
|
||||
@@ -809,10 +807,11 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
|
||||
let retStmt = newTree(nkReturnStmt, asgn)
|
||||
let branch = newTree(nkElifBranch, cmp, retStmt)
|
||||
|
||||
# The C++ backend requires `getCurrentException` here.
|
||||
let raiseStmt = newTree(nkRaiseStmt, ctx.g.callCodegenProc("getCurrentException"))
|
||||
let nullifyExc = newTree(nkCall, newSymNode(ctx.g.getCompilerProc("closureIterSetupExc")), nilnode)
|
||||
nullifyExc.info = info
|
||||
let raiseStmt = newTree(nkRaiseStmt, curExc)
|
||||
raiseStmt.info = info
|
||||
let elseBranch = newTree(nkElse, raiseStmt)
|
||||
let elseBranch = newTree(nkElse, newTree(nkStmtList, nullifyExc, raiseStmt))
|
||||
|
||||
let ifBody = newTree(nkIfStmt, branch, elseBranch)
|
||||
let elifBranch = newTree(nkElifBranch, ctx.newUnrollFinallyAccess(info), ifBody)
|
||||
@@ -832,7 +831,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
|
||||
block: # :unrollFinally = true
|
||||
let asgn = newNodeI(nkAsgn, n.info)
|
||||
asgn.add(ctx.newUnrollFinallyAccess(n.info))
|
||||
asgn.add(newIntTypeNode(nkIntLit, 1, ctx.g.getSysType(n.info, tyBool)))
|
||||
asgn.add(newIntTypeNode(1, ctx.g.getSysType(n.info, tyBool)))
|
||||
result.add(asgn)
|
||||
|
||||
if n[0].kind != nkEmpty:
|
||||
@@ -854,156 +853,155 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
|
||||
|
||||
proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode =
|
||||
result = n
|
||||
case n.kind:
|
||||
of nkSkip:
|
||||
discard
|
||||
case n.kind
|
||||
of nkSkip: discard
|
||||
|
||||
of nkStmtList, nkStmtListExpr:
|
||||
result = addGotoOut(result, gotoOut)
|
||||
for i in 0 ..< n.len:
|
||||
if n[i].hasYields:
|
||||
# Create a new split
|
||||
let go = newNodeI(nkGotoState, n[i].info)
|
||||
n[i] = ctx.transformClosureIteratorBody(n[i], go)
|
||||
of nkStmtList, nkStmtListExpr:
|
||||
result = addGotoOut(result, gotoOut)
|
||||
for i in 0 ..< n.len:
|
||||
if n[i].hasYields:
|
||||
# Create a new split
|
||||
let go = newNodeI(nkGotoState, n[i].info)
|
||||
n[i] = ctx.transformClosureIteratorBody(n[i], go)
|
||||
|
||||
let s = newNodeI(nkStmtList, n[i + 1].info)
|
||||
for j in i + 1 ..< n.len:
|
||||
s.add(n[j])
|
||||
let s = newNodeI(nkStmtList, n[i + 1].info)
|
||||
for j in i + 1 ..< n.len:
|
||||
s.add(n[j])
|
||||
|
||||
n.sons.setLen(i + 1)
|
||||
discard ctx.newState(s, go)
|
||||
if ctx.transformClosureIteratorBody(s, gotoOut) != s:
|
||||
internalError(ctx.g.config, "transformClosureIteratorBody != s")
|
||||
break
|
||||
n.sons.setLen(i + 1)
|
||||
discard ctx.newState(s, go)
|
||||
if ctx.transformClosureIteratorBody(s, gotoOut) != s:
|
||||
internalError(ctx.g.config, "transformClosureIteratorBody != s")
|
||||
break
|
||||
|
||||
of nkYieldStmt:
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
result.add(n)
|
||||
result.add(gotoOut)
|
||||
of nkYieldStmt:
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
result.add(n)
|
||||
result.add(gotoOut)
|
||||
|
||||
of nkElse, nkElseExpr:
|
||||
result[0] = addGotoOut(result[0], gotoOut)
|
||||
result[0] = ctx.transformClosureIteratorBody(result[0], gotoOut)
|
||||
of nkElse, nkElseExpr:
|
||||
result[0] = addGotoOut(result[0], gotoOut)
|
||||
result[0] = ctx.transformClosureIteratorBody(result[0], gotoOut)
|
||||
|
||||
of nkElifBranch, nkElifExpr, nkOfBranch:
|
||||
result[^1] = addGotoOut(result[^1], gotoOut)
|
||||
result[^1] = ctx.transformClosureIteratorBody(result[^1], gotoOut)
|
||||
|
||||
of nkIfStmt, nkCaseStmt:
|
||||
for i in 0 ..< n.len:
|
||||
n[i] = ctx.transformClosureIteratorBody(n[i], gotoOut)
|
||||
if n[^1].kind != nkElse:
|
||||
# We don't have an else branch, but every possible branch has to end with
|
||||
# gotoOut, so add else here.
|
||||
let elseBranch = newTree(nkElse, gotoOut)
|
||||
n.add(elseBranch)
|
||||
|
||||
of nkWhileStmt:
|
||||
# while e:
|
||||
# s
|
||||
# ->
|
||||
# BEGIN_STATE:
|
||||
# if e:
|
||||
# s
|
||||
# goto BEGIN_STATE
|
||||
# else:
|
||||
# goto OUT
|
||||
|
||||
result = newNodeI(nkGotoState, n.info)
|
||||
|
||||
let s = newNodeI(nkStmtList, n.info)
|
||||
discard ctx.newState(s, result)
|
||||
let ifNode = newNodeI(nkIfStmt, n.info)
|
||||
let elifBranch = newNodeI(nkElifBranch, n.info)
|
||||
elifBranch.add(n[0])
|
||||
|
||||
var body = addGotoOut(n[1], result)
|
||||
|
||||
body = ctx.transformBreaksAndContinuesInWhile(body, result, gotoOut)
|
||||
body = ctx.transformClosureIteratorBody(body, result)
|
||||
|
||||
elifBranch.add(body)
|
||||
ifNode.add(elifBranch)
|
||||
of nkElifBranch, nkElifExpr, nkOfBranch:
|
||||
result[^1] = addGotoOut(result[^1], gotoOut)
|
||||
result[^1] = ctx.transformClosureIteratorBody(result[^1], gotoOut)
|
||||
|
||||
of nkIfStmt, nkCaseStmt:
|
||||
for i in 0 ..< n.len:
|
||||
n[i] = ctx.transformClosureIteratorBody(n[i], gotoOut)
|
||||
if n[^1].kind != nkElse:
|
||||
# We don't have an else branch, but every possible branch has to end with
|
||||
# gotoOut, so add else here.
|
||||
let elseBranch = newTree(nkElse, gotoOut)
|
||||
ifNode.add(elseBranch)
|
||||
s.add(ifNode)
|
||||
n.add(elseBranch)
|
||||
|
||||
of nkBlockStmt:
|
||||
result[1] = addGotoOut(result[1], gotoOut)
|
||||
result[1] = ctx.transformBreaksInBlock(result[1], result[0], gotoOut)
|
||||
result[1] = ctx.transformClosureIteratorBody(result[1], gotoOut)
|
||||
of nkWhileStmt:
|
||||
# while e:
|
||||
# s
|
||||
# ->
|
||||
# BEGIN_STATE:
|
||||
# if e:
|
||||
# s
|
||||
# goto BEGIN_STATE
|
||||
# else:
|
||||
# goto OUT
|
||||
|
||||
of nkTryStmt, nkHiddenTryStmt:
|
||||
# See explanation above about how this works
|
||||
ctx.hasExceptions = true
|
||||
result = newNodeI(nkGotoState, n.info)
|
||||
|
||||
result = newNodeI(nkGotoState, n.info)
|
||||
var tryBody = toStmtList(n[0])
|
||||
var exceptBody = ctx.collectExceptState(n)
|
||||
var finallyBody = newTree(nkStmtList, getFinallyNode(ctx, n))
|
||||
finallyBody = ctx.transformReturnsInTry(finallyBody)
|
||||
finallyBody.add(ctx.newEndFinallyNode(finallyBody.info))
|
||||
let s = newNodeI(nkStmtList, n.info)
|
||||
discard ctx.newState(s, result)
|
||||
let ifNode = newNodeI(nkIfStmt, n.info)
|
||||
let elifBranch = newNodeI(nkElifBranch, n.info)
|
||||
elifBranch.add(n[0])
|
||||
|
||||
# The following index calculation is based on the knowledge how state
|
||||
# indexes are assigned
|
||||
let tryIdx = ctx.states.len
|
||||
var exceptIdx, finallyIdx: int
|
||||
if exceptBody.kind != nkEmpty:
|
||||
exceptIdx = -(tryIdx + 1)
|
||||
finallyIdx = tryIdx + 2
|
||||
else:
|
||||
exceptIdx = tryIdx + 1
|
||||
finallyIdx = tryIdx + 1
|
||||
var body = addGotoOut(n[1], result)
|
||||
|
||||
let outToFinally = newNodeI(nkGotoState, finallyBody.info)
|
||||
body = ctx.transformBreaksAndContinuesInWhile(body, result, gotoOut)
|
||||
body = ctx.transformClosureIteratorBody(body, result)
|
||||
|
||||
block: # Create initial states.
|
||||
let oldExcHandlingState = ctx.curExcHandlingState
|
||||
ctx.curExcHandlingState = exceptIdx
|
||||
let realTryIdx = ctx.newState(tryBody, result)
|
||||
assert(realTryIdx == tryIdx)
|
||||
elifBranch.add(body)
|
||||
ifNode.add(elifBranch)
|
||||
|
||||
if exceptBody.kind != nkEmpty:
|
||||
ctx.curExcHandlingState = finallyIdx
|
||||
let realExceptIdx = ctx.newState(exceptBody, nil)
|
||||
assert(realExceptIdx == -exceptIdx)
|
||||
let elseBranch = newTree(nkElse, gotoOut)
|
||||
ifNode.add(elseBranch)
|
||||
s.add(ifNode)
|
||||
|
||||
ctx.curExcHandlingState = oldExcHandlingState
|
||||
let realFinallyIdx = ctx.newState(finallyBody, outToFinally)
|
||||
assert(realFinallyIdx == finallyIdx)
|
||||
of nkBlockStmt:
|
||||
result[1] = addGotoOut(result[1], gotoOut)
|
||||
result[1] = ctx.transformBreaksInBlock(result[1], result[0], gotoOut)
|
||||
result[1] = ctx.transformClosureIteratorBody(result[1], gotoOut)
|
||||
|
||||
block: # Subdivide the states
|
||||
let oldNearestFinally = ctx.nearestFinally
|
||||
ctx.nearestFinally = finallyIdx
|
||||
of nkTryStmt, nkHiddenTryStmt:
|
||||
# See explanation above about how this works
|
||||
ctx.hasExceptions = true
|
||||
|
||||
let oldExcHandlingState = ctx.curExcHandlingState
|
||||
|
||||
ctx.curExcHandlingState = exceptIdx
|
||||
|
||||
if ctx.transformReturnsInTry(tryBody) != tryBody:
|
||||
internalError(ctx.g.config, "transformReturnsInTry != tryBody")
|
||||
if ctx.transformClosureIteratorBody(tryBody, outToFinally) != tryBody:
|
||||
internalError(ctx.g.config, "transformClosureIteratorBody != tryBody")
|
||||
|
||||
ctx.curExcHandlingState = finallyIdx
|
||||
ctx.addElseToExcept(exceptBody)
|
||||
if ctx.transformReturnsInTry(exceptBody) != exceptBody:
|
||||
internalError(ctx.g.config, "transformReturnsInTry != exceptBody")
|
||||
if ctx.transformClosureIteratorBody(exceptBody, outToFinally) != exceptBody:
|
||||
internalError(ctx.g.config, "transformClosureIteratorBody != exceptBody")
|
||||
|
||||
ctx.curExcHandlingState = oldExcHandlingState
|
||||
ctx.nearestFinally = oldNearestFinally
|
||||
if ctx.transformClosureIteratorBody(finallyBody, gotoOut) != finallyBody:
|
||||
internalError(ctx.g.config, "transformClosureIteratorBody != finallyBody")
|
||||
|
||||
of nkGotoState, nkForStmt:
|
||||
internalError(ctx.g.config, "closure iter " & $n.kind)
|
||||
result = newNodeI(nkGotoState, n.info)
|
||||
var tryBody = toStmtList(n[0])
|
||||
var exceptBody = ctx.collectExceptState(n)
|
||||
var finallyBody = newTree(nkStmtList, getFinallyNode(ctx, n))
|
||||
finallyBody = ctx.transformReturnsInTry(finallyBody)
|
||||
finallyBody.add(ctx.newEndFinallyNode(finallyBody.info))
|
||||
|
||||
# The following index calculation is based on the knowledge how state
|
||||
# indexes are assigned
|
||||
let tryIdx = ctx.states.len
|
||||
var exceptIdx, finallyIdx: int
|
||||
if exceptBody.kind != nkEmpty:
|
||||
exceptIdx = -(tryIdx + 1)
|
||||
finallyIdx = tryIdx + 2
|
||||
else:
|
||||
for i in 0 ..< n.len:
|
||||
n[i] = ctx.transformClosureIteratorBody(n[i], gotoOut)
|
||||
exceptIdx = tryIdx + 1
|
||||
finallyIdx = tryIdx + 1
|
||||
|
||||
let outToFinally = newNodeI(nkGotoState, finallyBody.info)
|
||||
|
||||
block: # Create initial states.
|
||||
let oldExcHandlingState = ctx.curExcHandlingState
|
||||
ctx.curExcHandlingState = exceptIdx
|
||||
let realTryIdx = ctx.newState(tryBody, result)
|
||||
assert(realTryIdx == tryIdx)
|
||||
|
||||
if exceptBody.kind != nkEmpty:
|
||||
ctx.curExcHandlingState = finallyIdx
|
||||
let realExceptIdx = ctx.newState(exceptBody, nil)
|
||||
assert(realExceptIdx == -exceptIdx)
|
||||
|
||||
ctx.curExcHandlingState = oldExcHandlingState
|
||||
let realFinallyIdx = ctx.newState(finallyBody, outToFinally)
|
||||
assert(realFinallyIdx == finallyIdx)
|
||||
|
||||
block: # Subdivide the states
|
||||
let oldNearestFinally = ctx.nearestFinally
|
||||
ctx.nearestFinally = finallyIdx
|
||||
|
||||
let oldExcHandlingState = ctx.curExcHandlingState
|
||||
|
||||
ctx.curExcHandlingState = exceptIdx
|
||||
|
||||
if ctx.transformReturnsInTry(tryBody) != tryBody:
|
||||
internalError(ctx.g.config, "transformReturnsInTry != tryBody")
|
||||
if ctx.transformClosureIteratorBody(tryBody, outToFinally) != tryBody:
|
||||
internalError(ctx.g.config, "transformClosureIteratorBody != tryBody")
|
||||
|
||||
ctx.curExcHandlingState = finallyIdx
|
||||
ctx.addElseToExcept(exceptBody)
|
||||
if ctx.transformReturnsInTry(exceptBody) != exceptBody:
|
||||
internalError(ctx.g.config, "transformReturnsInTry != exceptBody")
|
||||
if ctx.transformClosureIteratorBody(exceptBody, outToFinally) != exceptBody:
|
||||
internalError(ctx.g.config, "transformClosureIteratorBody != exceptBody")
|
||||
|
||||
ctx.curExcHandlingState = oldExcHandlingState
|
||||
ctx.nearestFinally = oldNearestFinally
|
||||
if ctx.transformClosureIteratorBody(finallyBody, gotoOut) != finallyBody:
|
||||
internalError(ctx.g.config, "transformClosureIteratorBody != finallyBody")
|
||||
|
||||
of nkGotoState, nkForStmt:
|
||||
internalError(ctx.g.config, "closure iter " & $n.kind)
|
||||
|
||||
else:
|
||||
for i in 0 ..< n.len:
|
||||
n[i] = ctx.transformClosureIteratorBody(n[i], gotoOut)
|
||||
|
||||
proc stateFromGotoState(n: PNode): int =
|
||||
assert(n.kind == nkGotoState)
|
||||
@@ -1149,7 +1147,6 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
|
||||
|
||||
# :state = exceptionTable[:state]
|
||||
block:
|
||||
|
||||
# exceptionTable[:state]
|
||||
let getNextState = newTree(nkBracketExpr,
|
||||
ctx.createExceptionTable(),
|
||||
@@ -1164,7 +1161,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
|
||||
let cond = newTree(nkCall,
|
||||
ctx.g.getSysMagic(info, "==", mEqI).newSymNode(),
|
||||
ctx.newStateAccess(),
|
||||
newIntTypeNode(nkIntLit, 0, intTyp))
|
||||
newIntTypeNode(0, intTyp))
|
||||
cond.typ = boolTyp
|
||||
|
||||
let raiseStmt = newTree(nkRaiseStmt, ctx.g.emptyNode)
|
||||
@@ -1176,7 +1173,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
|
||||
block:
|
||||
let cond = newTree(nkCall,
|
||||
ctx.g.getSysMagic(info, "<", mLtI).newSymNode,
|
||||
newIntTypeNode(nkIntLit, 0, intTyp),
|
||||
newIntTypeNode(0, intTyp),
|
||||
ctx.newStateAccess())
|
||||
cond.typ = boolTyp
|
||||
|
||||
@@ -1188,7 +1185,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
|
||||
let cond = newTree(nkCall,
|
||||
ctx.g.getSysMagic(info, "<", mLtI).newSymNode,
|
||||
ctx.newStateAccess(),
|
||||
newIntTypeNode(nkIntLit, 0, intTyp))
|
||||
newIntTypeNode(0, intTyp))
|
||||
cond.typ = boolTyp
|
||||
|
||||
let negateState = newTree(nkCall,
|
||||
@@ -1289,7 +1286,7 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
|
||||
ctx.fn = fn
|
||||
|
||||
if getEnvParam(fn).isNil:
|
||||
# Lambda lifting was not done yet. Use temporary :state sym, which
|
||||
# Lambda lifting was not done yet. Use temporary :state sym, which will
|
||||
# be handled specially by lambda lifting. Local temp vars (if needed)
|
||||
# should folllow the same logic.
|
||||
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), fn, fn.info)
|
||||
|
||||
@@ -13,6 +13,8 @@ import
|
||||
options, idents, nimconf, scriptconfig, extccomp, commands, msgs,
|
||||
lineinfos, modulegraphs, condsyms, os, pathutils
|
||||
|
||||
from strutils import normalize
|
||||
|
||||
type
|
||||
NimProg* = ref object
|
||||
suggestMode*: bool
|
||||
@@ -72,7 +74,11 @@ proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: Confi
|
||||
runNimScriptIfExists(scriptFile)
|
||||
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
|
||||
if fileExists(scriptFile) and scriptFile == conf.projectFull:
|
||||
return false
|
||||
if conf.command == "":
|
||||
conf.command = "e"
|
||||
return false
|
||||
elif conf.command.normalize == "e":
|
||||
return false
|
||||
else:
|
||||
if scriptFile != conf.projectFull:
|
||||
runNimScriptIfExists(scriptFile)
|
||||
|
||||
@@ -17,6 +17,7 @@ template bootSwitch(name, expr, userString) =
|
||||
const name = if expr: " " & userString else: ""
|
||||
|
||||
bootSwitch(usedRelease, defined(release), "-d:release")
|
||||
bootSwitch(usedDanger, defined(danger), "-d:danger")
|
||||
bootSwitch(usedGnuReadline, defined(useLinenoise), "-d:useLinenoise")
|
||||
bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm")
|
||||
bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
|
||||
@@ -26,9 +27,11 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
|
||||
|
||||
import
|
||||
os, msgs, options, nversion, condsyms, strutils, extccomp, platform,
|
||||
wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils, lineinfos,
|
||||
wordrecg, parseutils, nimblecmd, parseopt, sequtils, lineinfos,
|
||||
pathutils, strtabs
|
||||
|
||||
from incremental import nimIncremental
|
||||
|
||||
# but some have deps to imported modules. Yay.
|
||||
bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
|
||||
bootSwitch(usedNativeStacktrace,
|
||||
@@ -47,15 +50,16 @@ const
|
||||
"Compiled at $4\n" &
|
||||
"Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n"
|
||||
|
||||
proc genFeatureDesc[T: enum](t: typedesc[T]): string {.compileTime.} =
|
||||
var x = ""
|
||||
for f in low(T)..high(T):
|
||||
if x.len > 0: x.add "|"
|
||||
x.add $f
|
||||
x
|
||||
|
||||
const
|
||||
Usage = slurp"../doc/basicopt.txt".replace(" //", " ")
|
||||
FeatureDesc = block:
|
||||
var x = ""
|
||||
for f in low(Feature)..high(Feature):
|
||||
if x.len > 0: x.add "|"
|
||||
x.add $f
|
||||
x
|
||||
AdvancedUsage = slurp"../doc/advopt.txt".replace(" //", " ") % FeatureDesc
|
||||
AdvancedUsage = slurp"../doc/advopt.txt".replace(" //", " ") % [genFeatureDesc(Feature), genFeatureDesc(LegacyFeature)]
|
||||
|
||||
proc getCommandLineDesc(conf: ConfigRef): string =
|
||||
result = (HelpMessage % [VersionAsString, platform.OS[conf.target.hostOS].name,
|
||||
@@ -96,7 +100,7 @@ proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) =
|
||||
when gitHash.len == 40:
|
||||
msgWriteln(conf, "git hash: " & gitHash, {msgStdout})
|
||||
|
||||
msgWriteln(conf, "active boot switches:" & usedRelease &
|
||||
msgWriteln(conf, "active boot switches:" & usedRelease & usedDanger &
|
||||
usedTinyC & usedGnuReadline & usedNativeStacktrace &
|
||||
usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC,
|
||||
{msgStdout})
|
||||
@@ -262,7 +266,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
|
||||
of "threadanalysis": result = contains(conf.globalOptions, optThreadAnalysis)
|
||||
of "stacktrace": result = contains(conf.options, optStackTrace)
|
||||
of "linetrace": result = contains(conf.options, optLineTrace)
|
||||
of "debugger": result = contains(conf.options, optEndb)
|
||||
of "debugger": result = contains(conf.globalOptions, optCDebug)
|
||||
of "profiler": result = contains(conf.options, optProfiler)
|
||||
of "memtracker": result = contains(conf.options, optMemTracker)
|
||||
of "checks", "x": result = conf.options * ChecksOptions == ChecksOptions
|
||||
@@ -275,8 +279,9 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
|
||||
of "fieldchecks": result = contains(conf.options, optFieldCheck)
|
||||
of "rangechecks": result = contains(conf.options, optRangeCheck)
|
||||
of "boundchecks": result = contains(conf.options, optBoundsCheck)
|
||||
of "refchecks": result = contains(conf.options, optRefCheck)
|
||||
of "overflowchecks": result = contains(conf.options, optOverflowCheck)
|
||||
of "movechecks": result = contains(conf.options, optMoveCheck)
|
||||
of "stylechecks": result = contains(conf.options, optStyleCheck)
|
||||
of "linedir": result = contains(conf.options, optLineDir)
|
||||
of "assertions", "a": result = contains(conf.options, optAssert)
|
||||
of "run", "r": result = contains(conf.globalOptions, optRun)
|
||||
@@ -432,30 +437,31 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
processOnOffSwitchG(conf, {optWholeProject}, arg, pass, info)
|
||||
of "gc":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
case arg.normalize
|
||||
of "boehm":
|
||||
conf.selectedGC = gcBoehm
|
||||
defineSymbol(conf.symbols, "boehmgc")
|
||||
of "refc":
|
||||
conf.selectedGC = gcRefc
|
||||
of "v2":
|
||||
message(conf, info, warnDeprecated, "--gc:v2 is deprecated; using default gc")
|
||||
of "markandsweep":
|
||||
conf.selectedGC = gcMarkAndSweep
|
||||
defineSymbol(conf.symbols, "gcmarkandsweep")
|
||||
of "destructors":
|
||||
conf.selectedGC = gcDestructors
|
||||
defineSymbol(conf.symbols, "gcdestructors")
|
||||
of "go":
|
||||
conf.selectedGC = gcGo
|
||||
defineSymbol(conf.symbols, "gogc")
|
||||
of "none":
|
||||
conf.selectedGC = gcNone
|
||||
defineSymbol(conf.symbols, "nogc")
|
||||
of "stack", "regions":
|
||||
conf.selectedGC= gcRegions
|
||||
defineSymbol(conf.symbols, "gcregions")
|
||||
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
|
||||
if pass in {passCmd2, passPP}:
|
||||
case arg.normalize
|
||||
of "boehm":
|
||||
conf.selectedGC = gcBoehm
|
||||
defineSymbol(conf.symbols, "boehmgc")
|
||||
of "refc":
|
||||
conf.selectedGC = gcRefc
|
||||
of "v2":
|
||||
message(conf, info, warnDeprecated, "--gc:v2 is deprecated; using default gc")
|
||||
of "markandsweep":
|
||||
conf.selectedGC = gcMarkAndSweep
|
||||
defineSymbol(conf.symbols, "gcmarkandsweep")
|
||||
of "destructors":
|
||||
conf.selectedGC = gcDestructors
|
||||
defineSymbol(conf.symbols, "gcdestructors")
|
||||
of "go":
|
||||
conf.selectedGC = gcGo
|
||||
defineSymbol(conf.symbols, "gogc")
|
||||
of "none":
|
||||
conf.selectedGC = gcNone
|
||||
defineSymbol(conf.symbols, "nogc")
|
||||
of "stack", "regions":
|
||||
conf.selectedGC= gcRegions
|
||||
defineSymbol(conf.symbols, "gcregions")
|
||||
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
|
||||
of "warnings", "w":
|
||||
if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf)
|
||||
of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf)
|
||||
@@ -468,24 +474,18 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "linetrace": processOnOffSwitch(conf, {optLineTrace}, arg, pass, info)
|
||||
of "debugger":
|
||||
case arg.normalize
|
||||
of "on", "endb":
|
||||
conf.options.incl optEndb
|
||||
defineSymbol(conf.symbols, "endb")
|
||||
of "off":
|
||||
conf.options.excl optEndb
|
||||
undefSymbol(conf.symbols, "endb")
|
||||
of "native", "gdb":
|
||||
incl(conf.globalOptions, optCDebug)
|
||||
conf.options = conf.options + {optLineDir} - {optEndb}
|
||||
of "on", "native", "gdb":
|
||||
conf.globalOptions.incl optCDebug
|
||||
conf.options.incl optLineDir
|
||||
#defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing
|
||||
undefSymbol(conf.symbols, "endb")
|
||||
of "off":
|
||||
conf.globalOptions.excl optCDebug
|
||||
else:
|
||||
localError(conf, info, "expected endb|gdb but found " & arg)
|
||||
localError(conf, info, "expected native|gdb|on|off but found " & arg)
|
||||
of "g": # alias for --debugger:native
|
||||
incl(conf.globalOptions, optCDebug)
|
||||
conf.options = conf.options + {optLineDir} - {optEndb}
|
||||
conf.globalOptions.incl optCDebug
|
||||
conf.options.incl optLineDir
|
||||
#defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing
|
||||
undefSymbol(conf.symbols, "endb")
|
||||
of "profiler":
|
||||
processOnOffSwitch(conf, {optProfiler}, arg, pass, info)
|
||||
if optProfiler in conf.options: defineSymbol(conf.symbols, "profiler")
|
||||
@@ -529,8 +529,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "fieldchecks": processOnOffSwitch(conf, {optFieldCheck}, arg, pass, info)
|
||||
of "rangechecks": processOnOffSwitch(conf, {optRangeCheck}, arg, pass, info)
|
||||
of "boundchecks": processOnOffSwitch(conf, {optBoundsCheck}, arg, pass, info)
|
||||
of "refchecks": processOnOffSwitch(conf, {optRefCheck}, arg, pass, info)
|
||||
of "overflowchecks": processOnOffSwitch(conf, {optOverflowCheck}, arg, pass, info)
|
||||
of "movechecks": processOnOffSwitch(conf, {optMoveCheck}, arg, pass, info)
|
||||
of "stylechecks": processOnOffSwitch(conf, {optStyleCheck}, arg, pass, info)
|
||||
of "linedir": processOnOffSwitch(conf, {optLineDir}, arg, pass, info)
|
||||
of "assertions", "a": processOnOffSwitch(conf, {optAssert}, arg, pass, info)
|
||||
of "deadcodeelim": discard # deprecated, dead code elim always on
|
||||
@@ -666,7 +667,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
helpOnError(conf, pass)
|
||||
of "symbolfiles": discard "ignore for backwards compat"
|
||||
of "incremental":
|
||||
when not defined(nimIncremental):
|
||||
when not nimIncremental:
|
||||
localError(conf, info, "the compiler was not built with " &
|
||||
"incremental compilation features; bootstrap with " &
|
||||
"-d:nimIncremental to enable")
|
||||
@@ -739,6 +740,11 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
conf.features.incl parseEnum[Feature](arg)
|
||||
except ValueError:
|
||||
localError(conf, info, "unknown experimental feature")
|
||||
of "legacy":
|
||||
try:
|
||||
conf.legacyFeatures.incl parseEnum[LegacyFeature](arg)
|
||||
except ValueError:
|
||||
localError(conf, info, "unknown obsolete feature")
|
||||
of "nocppexceptions":
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
incl(conf.globalOptions, optNoCppExceptions)
|
||||
@@ -777,13 +783,22 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "expandmacro":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
conf.macrosToExpand[arg] = "T"
|
||||
of "oldgensym":
|
||||
processOnOffSwitchG(conf, {optNimV019}, arg, pass, info)
|
||||
of "useversion":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
case arg
|
||||
of "1.0":
|
||||
discard "the default"
|
||||
else:
|
||||
localError(conf, info, "unknown Nim version; currently supported values are: {1.0}")
|
||||
of "":
|
||||
conf.projectName = "-"
|
||||
else:
|
||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
|
||||
else: invalidCmdLineOption(conf, pass, switch, info)
|
||||
|
||||
template gCmdLineInfo*(): untyped = newLineInfo(config, AbsoluteFile"command line", 1, 1)
|
||||
template gCmdLineInfo*(): untyped = newLineInfo(commandLineIdx, 1, 1)
|
||||
|
||||
proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
|
||||
var cmd, arg: string
|
||||
@@ -806,7 +821,7 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
|
||||
argsCount: var int; config: ConfigRef): bool =
|
||||
if argsCount == 0:
|
||||
# nim filename.nims is the same as "nim e filename.nims":
|
||||
if p.key.endswith(".nims"):
|
||||
if p.key.endsWith(".nims"):
|
||||
config.command = "e"
|
||||
incl(config.globalOptions, optWasNimscript)
|
||||
config.projectName = unixToNativePath(p.key)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# This module handles the conditional symbols.
|
||||
|
||||
import
|
||||
strtabs, platform, strutils, idents
|
||||
strtabs
|
||||
|
||||
from options import Feature
|
||||
from lineinfos import HintsToStr, WarningsToStr
|
||||
@@ -86,6 +86,8 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasSignatureHashInMacro")
|
||||
defineSymbol("nimHasDefault")
|
||||
defineSymbol("nimMacrosSizealignof")
|
||||
defineSymbol("nimNoZeroExtendMagic")
|
||||
defineSymbol("nimMacrosGetNodeId")
|
||||
for f in low(Feature)..high(Feature):
|
||||
defineSymbol("nimHas" & $f)
|
||||
|
||||
@@ -93,3 +95,8 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasWarning" & s)
|
||||
for s in HintsToStr:
|
||||
defineSymbol("nimHasHint" & s)
|
||||
|
||||
defineSymbol("nimFixedOwned")
|
||||
defineSymbol("nimHasStyleChecks")
|
||||
defineSymbol("nimToOpenArrayCString")
|
||||
defineSymbol("nimHasUsed")
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
# This module implements a dependency file generator.
|
||||
|
||||
import
|
||||
os, options, ast, astalgo, msgs, ropes, idents, passes, modulepaths,
|
||||
pathutils
|
||||
options, ast, ropes, idents, passes, modulepaths, pathutils
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
|
||||
@@ -35,14 +34,14 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode =
|
||||
let b = Backend(g.graph.backend)
|
||||
case n.kind
|
||||
of nkImportStmt:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
var imported = getModuleName(g.config, n.sons[i])
|
||||
addDependencyAux(b, g.module.name.s, imported)
|
||||
of nkFromStmt, nkImportExceptStmt:
|
||||
var imported = getModuleName(g.config, n.sons[0])
|
||||
addDependencyAux(b, g.module.name.s, imported)
|
||||
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
|
||||
for i in 0 ..< sonsLen(n): discard addDotDependency(c, n.sons[i])
|
||||
for i in 0 ..< len(n): discard addDotDependency(c, n.sons[i])
|
||||
else:
|
||||
discard
|
||||
|
||||
|
||||
103
compiler/dfa.nim
103
compiler/dfa.nim
@@ -29,7 +29,7 @@
|
||||
## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen.
|
||||
## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf
|
||||
|
||||
import ast, astalgo, types, intsets, tables, msgs, options, lineinfos, renderer
|
||||
import ast, types, intsets, lineinfos, renderer
|
||||
|
||||
from patterns import sameTrees
|
||||
|
||||
@@ -119,10 +119,10 @@ use(x)
|
||||
|
||||
Generates:
|
||||
|
||||
L0: fork L1
|
||||
L0: fork lab1
|
||||
join L0 # patched.
|
||||
goto Louter
|
||||
L1:
|
||||
lab1:
|
||||
def x
|
||||
join L0
|
||||
Louter:
|
||||
@@ -265,14 +265,14 @@ proc genLabel(c: Con): TPosition =
|
||||
|
||||
proc jmpBack(c: var Con, n: PNode, p = TPosition(0)) =
|
||||
let dist = p.int - c.code.len
|
||||
doAssert(-0x7fff < dist and dist < 0x7fff)
|
||||
doAssert(low(int) div 2 + 1 < dist and dist < high(int) div 2)
|
||||
c.code.add Instr(n: n, kind: goto, dest: dist)
|
||||
|
||||
proc patch(c: var Con, p: TPosition) =
|
||||
# patch with current index
|
||||
let p = p.int
|
||||
let diff = c.code.len - p
|
||||
doAssert(-0x7fff < diff and diff < 0x7fff)
|
||||
doAssert(low(int) div 2 + 1 < diff and diff < high(int) div 2)
|
||||
c.code[p].dest = diff
|
||||
|
||||
proc popBlock(c: var Con; oldLen: int) =
|
||||
@@ -354,24 +354,24 @@ when true:
|
||||
else:
|
||||
|
||||
proc genWhile(c: var Con; n: PNode) =
|
||||
# L1:
|
||||
# lab1:
|
||||
# cond, tmp
|
||||
# fork tmp, L2
|
||||
# fork tmp, lab2
|
||||
# body
|
||||
# jmp L1
|
||||
# L2:
|
||||
# jmp lab1
|
||||
# lab2:
|
||||
let oldForksLen = c.forks.len
|
||||
let L1 = c.genLabel
|
||||
let lab1 = c.genLabel
|
||||
withBlock(nil):
|
||||
if isTrue(n.sons[0]):
|
||||
c.gen(n.sons[1])
|
||||
c.jmpBack(n, L1)
|
||||
c.jmpBack(n, lab1)
|
||||
else:
|
||||
c.gen(n.sons[0])
|
||||
let L2 = c.forkI(n)
|
||||
let lab2 = c.forkI(n)
|
||||
c.gen(n.sons[1])
|
||||
c.jmpBack(n, L1)
|
||||
c.patch(L2)
|
||||
c.jmpBack(n, lab1)
|
||||
c.patch(lab2)
|
||||
setLen(c.forks, oldForksLen)
|
||||
|
||||
proc genBlock(c: var Con; n: PNode) =
|
||||
@@ -383,23 +383,23 @@ proc genJoins(c: var Con; n: PNode) =
|
||||
|
||||
proc genBreak(c: var Con; n: PNode) =
|
||||
genJoins(c, n)
|
||||
let L1 = c.gotoI(n)
|
||||
let lab1 = c.gotoI(n)
|
||||
if n.sons[0].kind == nkSym:
|
||||
#echo cast[int](n.sons[0].sym)
|
||||
for i in countdown(c.blocks.len-1, 0):
|
||||
if c.blocks[i].label == n.sons[0].sym:
|
||||
c.blocks[i].fixups.add L1
|
||||
c.blocks[i].fixups.add lab1
|
||||
return
|
||||
#globalError(n.info, "VM problem: cannot find 'break' target")
|
||||
else:
|
||||
c.blocks[c.blocks.high].fixups.add L1
|
||||
c.blocks[c.blocks.high].fixups.add lab1
|
||||
|
||||
template forkT(n, body) =
|
||||
let oldLen = c.forks.len
|
||||
let L1 = c.forkI(n)
|
||||
let lab1 = c.forkI(n)
|
||||
body
|
||||
c.patch(L1)
|
||||
c.joinI(L1, n)
|
||||
c.patch(lab1)
|
||||
c.joinI(lab1, n)
|
||||
setLen(c.forks, oldLen)
|
||||
|
||||
proc genIf(c: var Con, n: PNode) =
|
||||
@@ -415,15 +415,15 @@ proc genIf(c: var Con, n: PNode) =
|
||||
D
|
||||
|
||||
cond
|
||||
fork L1
|
||||
fork lab1
|
||||
A
|
||||
goto Lend
|
||||
L1:
|
||||
lab1:
|
||||
condB
|
||||
fork L2
|
||||
fork lab2
|
||||
B
|
||||
goto Lend2
|
||||
L2:
|
||||
lab2:
|
||||
condC
|
||||
fork L3
|
||||
C
|
||||
@@ -457,23 +457,23 @@ proc genIf(c: var Con, n: PNode) =
|
||||
|
||||
proc genAndOr(c: var Con; n: PNode) =
|
||||
# asgn dest, a
|
||||
# fork L1
|
||||
# fork lab1
|
||||
# asgn dest, b
|
||||
# L1:
|
||||
# lab1:
|
||||
# join F1
|
||||
c.gen(n.sons[1])
|
||||
forkT(n):
|
||||
c.gen(n.sons[2])
|
||||
|
||||
proc genCase(c: var Con; n: PNode) =
|
||||
# if (!expr1) goto L1;
|
||||
# if (!expr1) goto lab1;
|
||||
# thenPart
|
||||
# goto LEnd
|
||||
# L1:
|
||||
# if (!expr2) goto L2;
|
||||
# lab1:
|
||||
# if (!expr2) goto lab2;
|
||||
# thenPart2
|
||||
# goto LEnd
|
||||
# L2:
|
||||
# lab2:
|
||||
# elsePart
|
||||
# Lend:
|
||||
let isExhaustive = skipTypes(n.sons[0].typ,
|
||||
@@ -607,20 +607,15 @@ proc aliases(obj, field: PNode): bool =
|
||||
if sameTrees(obj, n): return true
|
||||
case n.kind
|
||||
of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv,
|
||||
nkObjDownConv, nkObjUpConv, nkHiddenDeref, nkDerefExpr:
|
||||
nkObjDownConv, nkObjUpConv, nkHiddenAddr, nkAddr, nkBracketExpr,
|
||||
nkHiddenDeref, nkDerefExpr:
|
||||
n = n[0]
|
||||
of nkBracketExpr:
|
||||
let x = n[0]
|
||||
if x.typ != nil and x.typ.skipTypes(abstractInst).kind == tyTuple:
|
||||
n = x
|
||||
else:
|
||||
break
|
||||
else:
|
||||
break
|
||||
return false
|
||||
|
||||
proc instrTargets*(ins: Instr; loc: PNode): bool =
|
||||
assert ins.kind in {def, use}
|
||||
proc useInstrTargets*(ins: Instr; loc: PNode): bool =
|
||||
assert ins.kind == use
|
||||
if ins.sym != nil and loc.kind == nkSym:
|
||||
result = ins.sym == loc.sym
|
||||
else:
|
||||
@@ -633,25 +628,33 @@ proc instrTargets*(ins: Instr; loc: PNode): bool =
|
||||
# use x; question does it affect 'x.f'? Yes.
|
||||
result = aliases(ins.n, loc) or aliases(loc, ins.n)
|
||||
|
||||
proc defInstrTargets*(ins: Instr; loc: PNode): bool =
|
||||
assert ins.kind == def
|
||||
if ins.sym != nil and loc.kind == nkSym:
|
||||
result = ins.sym == loc.sym
|
||||
else:
|
||||
result = ins.n == loc or sameTrees(ins.n, loc)
|
||||
if not result:
|
||||
# We can come here if loc is 'x.f' and ins.n is 'x' or the other way round.
|
||||
# def x.f; question: does it affect the full 'x'? No.
|
||||
# def x; question: does it affect the 'x.f'? Yes.
|
||||
# use x.f; question: does it affect the full 'x'? No.
|
||||
# use x; question does it affect 'x.f'? Yes.
|
||||
result = aliases(ins.n, loc)
|
||||
|
||||
proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool =
|
||||
var n = orig
|
||||
while true:
|
||||
case n.kind
|
||||
of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv,
|
||||
nkObjDownConv, nkObjUpConv:
|
||||
nkObjDownConv, nkObjUpConv, nkHiddenAddr, nkAddr, nkBracketExpr:
|
||||
n = n[0]
|
||||
of nkHiddenDeref, nkDerefExpr:
|
||||
# We "own" sinkparam[].loc but not ourVar[].location as it is a nasty
|
||||
# pointer indirection.
|
||||
n = n[0]
|
||||
return n.kind == nkSym and n.sym.owner == owner and (isSinkParam(n.sym) or
|
||||
n.sym.typ.skipTypes(abstractInst-{tyOwned}).kind in {tyOwned, tyVar})
|
||||
of nkBracketExpr:
|
||||
let x = n[0]
|
||||
if x.typ != nil and x.typ.skipTypes(abstractInst).kind == tyTuple:
|
||||
n = x
|
||||
else:
|
||||
break
|
||||
n.sym.typ.skipTypes(abstractInst-{tyOwned}).kind in {tyOwned})
|
||||
else:
|
||||
break
|
||||
# XXX Allow closure deref operations here if we know
|
||||
@@ -700,9 +703,9 @@ proc genCall(c: var Con; n: PNode) =
|
||||
# every call can potentially raise:
|
||||
if c.inTryStmt > 0 and canRaise(n[0]):
|
||||
# we generate the instruction sequence:
|
||||
# fork L1
|
||||
# fork lab1
|
||||
# goto exceptionHandler (except or finally)
|
||||
# L1:
|
||||
# lab1:
|
||||
# join F1
|
||||
let endGoto = c.forkI(n)
|
||||
c.tryStmtFixups.add c.gotoI(n)
|
||||
@@ -766,7 +769,7 @@ proc gen(c: var Con; n: PNode) =
|
||||
of nkBreakStmt: genBreak(c, n)
|
||||
of nkTryStmt, nkHiddenTryStmt: genTry(c, n)
|
||||
of nkStmtList, nkStmtListExpr, nkChckRangeF, nkChckRange64, nkChckRange,
|
||||
nkBracket, nkCurly, nkPar, nkTupleConstr, nkClosure, nkObjConstr:
|
||||
nkBracket, nkCurly, nkPar, nkTupleConstr, nkClosure, nkObjConstr, nkYieldStmt:
|
||||
for x in n: gen(c, x)
|
||||
of nkPragmaBlock: gen(c, n.lastSon)
|
||||
of nkDiscardStmt, nkObjDownConv, nkObjUpConv: gen(c, n.sons[0])
|
||||
|
||||
@@ -15,8 +15,8 @@ import
|
||||
ast, strutils, strtabs, options, msgs, os, ropes, idents,
|
||||
wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast,
|
||||
packages/docutils/rst, packages/docutils/rstgen,
|
||||
packages/docutils/highlite, json, xmltree, cgi, trees, types,
|
||||
typesrenderer, astalgo, modulepaths, lineinfos, sequtils, intsets,
|
||||
json, xmltree, cgi, trees, types,
|
||||
typesrenderer, astalgo, lineinfos, intsets,
|
||||
pathutils, trees
|
||||
|
||||
const
|
||||
@@ -406,6 +406,7 @@ proc runAllExamples(d: PDoc) =
|
||||
elif isDefined(d.conf, "objc"): "objc"
|
||||
else: "c"
|
||||
if os.execShellCmd(os.getAppFilename() & " " & backend &
|
||||
" --warning[UnusedImport]:off" &
|
||||
" --path:" & quoteShell(d.conf.projectPath) &
|
||||
" --nimcache:" & quoteShell(outputDir) &
|
||||
" -r " & quoteShell(outp)) != 0:
|
||||
@@ -415,12 +416,6 @@ proc runAllExamples(d: PDoc) =
|
||||
rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
|
||||
removeFile(outp.changeFileExt(ExeExt))
|
||||
|
||||
proc extractImports(n: PNode; result: PNode) =
|
||||
if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}:
|
||||
result.add copyTree(n)
|
||||
n.kind = nkEmpty
|
||||
return
|
||||
for i in 0..<n.safeLen: extractImports(n[i], result)
|
||||
|
||||
proc prepareExamples(d: PDoc; n: PNode) =
|
||||
var docComment = newTree(nkCommentStmt)
|
||||
@@ -430,12 +425,20 @@ proc prepareExamples(d: PDoc; n: PNode) =
|
||||
docComment,
|
||||
newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
|
||||
runnableExamples.info = n.info
|
||||
let imports = newTree(nkStmtList)
|
||||
var savedLastSon = copyTree n.lastSon
|
||||
extractImports(savedLastSon, imports)
|
||||
for imp in imports: runnableExamples.add imp
|
||||
runnableExamples.add newTree(nkBlockStmt, newNode(nkEmpty), copyTree savedLastSon)
|
||||
for a in n.lastSon: runnableExamples.add a
|
||||
testExample(d, runnableExamples)
|
||||
when false:
|
||||
proc extractImports(n: PNode; result: PNode) =
|
||||
if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}:
|
||||
result.add copyTree(n)
|
||||
n.kind = nkEmpty
|
||||
return
|
||||
for i in 0..<n.safeLen: extractImports(n[i], result)
|
||||
let imports = newTree(nkStmtList)
|
||||
var savedLastSon = copyTree n.lastSon
|
||||
extractImports(savedLastSon, imports)
|
||||
for imp in imports: runnableExamples.add imp
|
||||
runnableExamples.add newTree(nkBlockStmt, newNode(nkEmpty), copyTree savedLastSon)
|
||||
|
||||
proc getAllRunnableExamplesRec(d: PDoc; n, orig: PNode; dest: var Rope) =
|
||||
if n.info.fileIndex != orig.info.fileIndex: return
|
||||
@@ -680,7 +683,9 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
path = path[cwd.len+1 .. ^1].replace('\\', '/')
|
||||
let gitUrl = getConfigVar(d.conf, "git.url")
|
||||
if gitUrl.len > 0:
|
||||
let defaultBranch = if NimPatch mod 2 == 1: "devel" else: "master"
|
||||
let defaultBranch =
|
||||
if NimPatch mod 2 == 1: "devel"
|
||||
else: "version-$1-$2" % [$NimMajor, $NimMinor]
|
||||
let commit = getConfigVar(d.conf, "git.commit", defaultBranch)
|
||||
let develBranch = getConfigVar(d.conf, "git.devel", "devel")
|
||||
dispA(d.conf, seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc,
|
||||
@@ -867,13 +872,13 @@ proc generateDoc*(d: PDoc, n, orig: PNode) =
|
||||
when useEffectSystem: documentRaises(d.cache, n)
|
||||
genItem(d, n, n.sons[namePos], skConverter)
|
||||
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if n.sons[i].kind != nkCommentStmt:
|
||||
# order is always 'type var let const':
|
||||
genItem(d, n.sons[i], n.sons[i].sons[0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)))
|
||||
of nkStmtList:
|
||||
for i in 0 ..< sonsLen(n): generateDoc(d, n.sons[i], orig)
|
||||
for i in 0 ..< len(n): generateDoc(d, n.sons[i], orig)
|
||||
of nkWhenStmt:
|
||||
# generate documentation for the first branch only:
|
||||
if not checkForFalse(n.sons[0].sons[0]):
|
||||
@@ -921,13 +926,13 @@ proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) =
|
||||
when useEffectSystem: documentRaises(d.cache, n)
|
||||
d.add genJsonItem(d, n, n.sons[namePos], skConverter)
|
||||
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if n.sons[i].kind != nkCommentStmt:
|
||||
# order is always 'type var let const':
|
||||
d.add genJsonItem(d, n.sons[i], n.sons[i].sons[0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)))
|
||||
of nkStmtList:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
generateJson(d, n.sons[i], includeComments)
|
||||
of nkWhenStmt:
|
||||
# generate documentation for the first branch only:
|
||||
@@ -964,13 +969,13 @@ proc generateTags*(d: PDoc, n: PNode, r: var Rope) =
|
||||
when useEffectSystem: documentRaises(d.cache, n)
|
||||
r.add genTagsItem(d, n, n.sons[namePos], skConverter)
|
||||
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if n.sons[i].kind != nkCommentStmt:
|
||||
# order is always 'type var let const':
|
||||
r.add genTagsItem(d, n.sons[i], n.sons[i].sons[0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)))
|
||||
of nkStmtList:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
generateTags(d, n.sons[i], r)
|
||||
of nkWhenStmt:
|
||||
# generate documentation for the first branch only:
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
# semantic checking.
|
||||
|
||||
import
|
||||
os, options, ast, astalgo, msgs, ropes, idents, passes, docgen, lineinfos,
|
||||
pathutils
|
||||
options, ast, msgs, idents, passes, docgen, lineinfos, pathutils
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
|
||||
|
||||
@@ -138,13 +138,13 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer)
|
||||
proc getField(conf: ConfigRef, n: PNode; position: int): PSym =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
result = getField(conf, n.sons[i], position)
|
||||
if result != nil: return
|
||||
of nkRecCase:
|
||||
result = getField(conf, n.sons[0], position)
|
||||
if result != nil: return
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
case n.sons[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
result = getField(conf, lastSon(n.sons[i]), position)
|
||||
@@ -158,7 +158,7 @@ proc packObject(conf: ConfigRef, x: PNode, typ: PType, res: pointer) =
|
||||
internalAssert conf, x.kind in {nkObjConstr, nkPar, nkTupleConstr}
|
||||
# compute the field's offsets:
|
||||
discard getSize(conf, typ)
|
||||
for i in ord(x.kind == nkObjConstr) ..< sonsLen(x):
|
||||
for i in ord(x.kind == nkObjConstr) ..< len(x):
|
||||
var it = x.sons[i]
|
||||
if it.kind == nkExprColonExpr:
|
||||
internalAssert conf, it.sons[0].kind == nkSym
|
||||
@@ -245,7 +245,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode
|
||||
proc unpackObjectAdd(conf: ConfigRef, x: pointer, n, result: PNode) =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
unpackObjectAdd(conf, x, n.sons[i], result)
|
||||
of nkRecCase:
|
||||
globalError(conf, result.info, "case objects cannot be unpacked")
|
||||
@@ -275,7 +275,7 @@ proc unpackObject(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
globalError(conf, n.info, "cannot map value from FFI")
|
||||
if typ.n.isNil:
|
||||
globalError(conf, n.info, "cannot unpack unnamed tuple")
|
||||
for i in ord(n.kind == nkObjConstr) ..< sonsLen(n):
|
||||
for i in ord(n.kind == nkObjConstr) ..< len(n):
|
||||
var it = n.sons[i]
|
||||
if it.kind == nkExprColonExpr:
|
||||
internalAssert conf, it.sons[0].kind == nkSym
|
||||
@@ -289,7 +289,7 @@ proc unpackArray(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
|
||||
if n.isNil:
|
||||
result = newNode(nkBracket)
|
||||
result.typ = typ
|
||||
newSeq(result.sons, lengthOrd(conf, typ).int)
|
||||
newSeq(result.sons, lengthOrd(conf, typ).toInt)
|
||||
else:
|
||||
result = n
|
||||
if result.kind != nkBracket:
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
## Template evaluation engine. Now hygienic.
|
||||
|
||||
import
|
||||
strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer,
|
||||
lineinfos
|
||||
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents
|
||||
|
||||
type
|
||||
TemplCtx = object
|
||||
@@ -21,6 +20,7 @@ type
|
||||
mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
|
||||
# new symbol
|
||||
config: ConfigRef
|
||||
ic: IdentCache
|
||||
|
||||
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
|
||||
result = copyNode(a)
|
||||
@@ -38,7 +38,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
of nkSym:
|
||||
var s = templ.sym
|
||||
if (s.owner == nil and s.kind == skParam) or s.owner == c.owner:
|
||||
if s.kind == skParam and sfGenSym notin s.flags:
|
||||
if s.kind == skParam and {sfGenSym, sfTemplateParam} * s.flags == {sfTemplateParam}:
|
||||
handleParam actual.sons[s.position]
|
||||
elif (s.owner != nil) and (s.kind == skGenericParam or
|
||||
s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam):
|
||||
@@ -53,7 +53,11 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
#if x.kind == skParam and x.owner.kind == skModule:
|
||||
# internalAssert c.config, false
|
||||
idTablePut(c.mapping, s, x)
|
||||
result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
|
||||
if sfGenSym in s.flags and optNimV019 notin c.config.globalOptions:
|
||||
result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $x.id),
|
||||
if c.instLines: actual.info else: templ.info)
|
||||
else:
|
||||
result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
|
||||
else:
|
||||
result.add copyNode(c, templ, actual)
|
||||
of nkNone..nkIdent, nkType..nkNilLit: # atom
|
||||
@@ -64,7 +68,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
# "declarative" context (bug #9235).
|
||||
if c.isDeclarative:
|
||||
var res = copyNode(c, templ, actual)
|
||||
for i in 0 ..< sonsLen(templ):
|
||||
for i in 0 ..< len(templ):
|
||||
evalTemplateAux(templ.sons[i], actual, c, res)
|
||||
result.add res
|
||||
else:
|
||||
@@ -78,7 +82,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
c.isDeclarative = true
|
||||
isDeclarative = true
|
||||
var res = copyNode(c, templ, actual)
|
||||
for i in 0 ..< sonsLen(templ):
|
||||
for i in 0 ..< len(templ):
|
||||
evalTemplateAux(templ.sons[i], actual, c, res)
|
||||
result.add res
|
||||
if isDeclarative: c.isDeclarative = false
|
||||
@@ -161,7 +165,9 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
|
||||
result.typ = res.typ
|
||||
|
||||
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
|
||||
conf: ConfigRef; fromHlo=false): PNode =
|
||||
conf: ConfigRef;
|
||||
ic: IdentCache;
|
||||
fromHlo=false): PNode =
|
||||
inc(conf.evalTemplateCounter)
|
||||
if conf.evalTemplateCounter > evalTemplateLimit:
|
||||
globalError(conf, n.info, errTemplateInstantiationTooNested)
|
||||
@@ -173,6 +179,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
|
||||
ctx.owner = tmpl
|
||||
ctx.genSymOwner = genSymOwner
|
||||
ctx.config = conf
|
||||
ctx.ic = ic
|
||||
initIdTable(ctx.mapping)
|
||||
|
||||
let body = tmpl.getBody
|
||||
|
||||
@@ -416,7 +416,7 @@ proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) =
|
||||
localError(conf, info, "unknown C compiler: '$1'. Available options are: $2" % [ccname, ccList])
|
||||
conf.compileOptions = getConfigVar(conf, conf.cCompiler, ".options.always")
|
||||
conf.linkOptions = ""
|
||||
conf.ccompilerpath = getConfigVar(conf, conf.cCompiler, ".path")
|
||||
conf.cCompilerPath = getConfigVar(conf, conf.cCompiler, ".path")
|
||||
for i in low(CC) .. high(CC): undefSymbol(conf.symbols, CC[i].name)
|
||||
defineSymbol(conf.symbols, CC[conf.cCompiler].name)
|
||||
|
||||
@@ -443,10 +443,10 @@ proc initVars*(conf: ConfigRef) =
|
||||
defineSymbol(conf.symbols, CC[conf.cCompiler].name)
|
||||
addCompileOption(conf, getConfigVar(conf, conf.cCompiler, ".options.always"))
|
||||
#addLinkOption(getConfigVar(cCompiler, ".options.linker"))
|
||||
if len(conf.ccompilerpath) == 0:
|
||||
conf.ccompilerpath = getConfigVar(conf, conf.cCompiler, ".path")
|
||||
if len(conf.cCompilerPath) == 0:
|
||||
conf.cCompilerPath = getConfigVar(conf, conf.cCompiler, ".path")
|
||||
|
||||
proc completeCFilePath*(conf: ConfigRef; cfile: AbsoluteFile,
|
||||
proc completeCfilePath*(conf: ConfigRef; cfile: AbsoluteFile,
|
||||
createSubDir: bool = true): AbsoluteFile =
|
||||
result = completeGeneratedFilePath(conf, cfile, createSubDir)
|
||||
|
||||
@@ -591,7 +591,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, isMainFile = false): str
|
||||
for includeDir in items(conf.cIncludes):
|
||||
includeCmd.add(join([CC[c].includeCmd, includeDir.quoteShell]))
|
||||
|
||||
compilePattern = joinPath(conf.ccompilerpath, exe)
|
||||
compilePattern = joinPath(conf.cCompilerPath, exe)
|
||||
else:
|
||||
includeCmd = ""
|
||||
compilePattern = getCompilerExe(conf, c, cfile.cname)
|
||||
@@ -606,7 +606,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, isMainFile = false): str
|
||||
if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths(conf):
|
||||
toObjFile(conf, cf).string
|
||||
else:
|
||||
completeCFilePath(conf, toObjFile(conf, cf)).string
|
||||
completeCfilePath(conf, toObjFile(conf, cf)).string
|
||||
elif noAbsolutePaths(conf):
|
||||
extractFilename(cfile.obj.string)
|
||||
else:
|
||||
@@ -666,11 +666,11 @@ proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) =
|
||||
|
||||
proc addExternalFileToCompile*(conf: ConfigRef; filename: AbsoluteFile) =
|
||||
var c = Cfile(nimname: splitFile(filename).name, cname: filename,
|
||||
obj: toObjFile(conf, completeCFilePath(conf, filename, false)),
|
||||
obj: toObjFile(conf, completeCfilePath(conf, filename, false)),
|
||||
flags: {CfileFlag.External})
|
||||
addExternalFileToCompile(conf, c)
|
||||
|
||||
proc compileCFiles(conf: ConfigRef; list: CFileList, script: var Rope, cmds: var TStringSeq,
|
||||
proc compileCFiles(conf: ConfigRef; list: CfileList, script: var Rope, cmds: var TStringSeq,
|
||||
prettyCmds: var TStringSeq) =
|
||||
var currIdx = 0
|
||||
for it in list:
|
||||
@@ -704,7 +704,7 @@ proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile,
|
||||
# bug #6452: We must not use ``quoteShell`` here for ``linkerExe``
|
||||
if needsExeExt(conf): linkerExe = addFileExt(linkerExe, "exe")
|
||||
if noAbsolutePaths(conf): result = linkerExe
|
||||
else: result = joinPath(conf.cCompilerpath, linkerExe)
|
||||
else: result = joinPath(conf.cCompilerPath, linkerExe)
|
||||
let buildgui = if optGenGuiApp in conf.globalOptions and conf.target.targetOS == osWindows:
|
||||
CC[conf.cCompiler].buildGui
|
||||
else:
|
||||
@@ -856,7 +856,7 @@ proc linkViaResponseFile(conf: ConfigRef; cmd: string) =
|
||||
finally:
|
||||
removeFile(linkerArgs)
|
||||
|
||||
proc getObjFilePath(conf: ConfigRef, f: CFile): string =
|
||||
proc getObjFilePath(conf: ConfigRef, f: Cfile): string =
|
||||
if noAbsolutePaths(conf): f.obj.extractFilename
|
||||
else: f.obj.string
|
||||
|
||||
@@ -947,7 +947,9 @@ proc callCCompiler*(conf: ConfigRef) =
|
||||
generateScript(conf, script)
|
||||
|
||||
#from json import escapeJson
|
||||
import json
|
||||
import json, std / sha1
|
||||
|
||||
template hashNimExe(): string = $secureHashFile(os.getAppFilename())
|
||||
|
||||
proc writeJsonBuildInstructions*(conf: ConfigRef) =
|
||||
template lit(x: untyped) = f.write x
|
||||
@@ -960,17 +962,17 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
|
||||
f.write escapeJson(x)
|
||||
|
||||
proc cfiles(conf: ConfigRef; f: File; buf: var string; clist: CfileList, isExternal: bool) =
|
||||
var pastStart = false
|
||||
var i = 0
|
||||
for it in clist:
|
||||
if CfileFlag.Cached in it.flags: continue
|
||||
let compileCmd = getCompileCFileCmd(conf, it)
|
||||
if pastStart: lit "],\L"
|
||||
if i > 0: lit ",\L"
|
||||
lit "["
|
||||
str it.cname.string
|
||||
lit ", "
|
||||
str compileCmd
|
||||
pastStart = true
|
||||
lit "]\L"
|
||||
lit "]"
|
||||
inc i
|
||||
|
||||
proc linkfiles(conf: ConfigRef; f: File; buf, objfiles: var string; clist: CfileList;
|
||||
llist: seq[string]) =
|
||||
@@ -994,6 +996,19 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
|
||||
pastStart = true
|
||||
lit "\L"
|
||||
|
||||
proc nimfiles(conf: ConfigRef; f: File) =
|
||||
var i = 0
|
||||
for it in conf.m.fileInfos:
|
||||
if isAbsolute(it.fullPath.string):
|
||||
if i > 0: lit "],\L"
|
||||
lit "["
|
||||
str it.fullPath.string
|
||||
lit ", "
|
||||
str $secureHashFile(it.fullPath.string)
|
||||
inc i
|
||||
lit "]\L"
|
||||
|
||||
|
||||
var buf = newStringOfCap(50)
|
||||
|
||||
let jsonFile = conf.getNimcacheDir / RelativeFile(conf.projectName & ".json")
|
||||
@@ -1009,9 +1024,48 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
|
||||
|
||||
lit "],\L\"linkcmd\": "
|
||||
str getLinkCmd(conf, conf.absOutFile, objfiles)
|
||||
|
||||
if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"):
|
||||
lit ",\L\"cmdline\": "
|
||||
str conf.commandLine
|
||||
lit ",\L\"nimfiles\":[\L"
|
||||
nimfiles(conf, f)
|
||||
lit "],\L\"nimexe\": \L"
|
||||
str hashNimExe()
|
||||
lit "\L"
|
||||
|
||||
lit "\L}\L"
|
||||
close(f)
|
||||
|
||||
proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile): bool =
|
||||
let jsonFile = toGeneratedFile(conf, projectfile, "json")
|
||||
if not fileExists(jsonFile): return true
|
||||
if not fileExists(conf.absOutFile): return true
|
||||
result = false
|
||||
try:
|
||||
let data = json.parseFile(jsonFile.string)
|
||||
if not data.hasKey("nimfiles") or not data.hasKey("cmdline"):
|
||||
return true
|
||||
let oldCmdLine = data["cmdline"].getStr
|
||||
if conf.commandLine != oldCmdLine:
|
||||
return true
|
||||
if hashNimExe() != data["nimexe"].getStr:
|
||||
return true
|
||||
let nimfilesPairs = data["nimfiles"]
|
||||
doAssert nimfilesPairs.kind == JArray
|
||||
for p in nimfilesPairs:
|
||||
doAssert p.kind == JArray
|
||||
# >= 2 for forwards compatibility with potential later .json files:
|
||||
doAssert p.len >= 2
|
||||
let nimFilename = p[0].getStr
|
||||
let oldHashValue = p[1].getStr
|
||||
let newHashValue = $secureHashFile(nimFilename)
|
||||
if oldHashValue != newHashValue:
|
||||
return true
|
||||
except IOError, OSError, ValueError:
|
||||
echo "Warning: JSON processing failed: ", getCurrentExceptionMsg()
|
||||
result = true
|
||||
|
||||
proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) =
|
||||
let jsonFile = toGeneratedFile(conf, projectfile, "json")
|
||||
try:
|
||||
@@ -1026,7 +1080,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) =
|
||||
|
||||
add(cmds, c[1].getStr)
|
||||
let (_, name, _) = splitFile(c[0].getStr)
|
||||
add(prettyCmds, "CC: " & name)
|
||||
add(prettyCmds, "CC: " & demanglePackageName(name))
|
||||
|
||||
let prettyCb = proc (idx: int) =
|
||||
when declared(echo):
|
||||
@@ -1041,7 +1095,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) =
|
||||
echo getCurrentException().getStackTrace()
|
||||
quit "error evaluating JSON file: " & jsonFile.string
|
||||
|
||||
proc genMappingFiles(conf: ConfigRef; list: CFileList): Rope =
|
||||
proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope =
|
||||
for it in list:
|
||||
addf(result, "--file:r\"$1\"$N", [rope(it.cname.string)])
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
# This module implements Nim's standard template filter.
|
||||
|
||||
import
|
||||
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
||||
renderer, filters, lineinfos, pathutils
|
||||
llstream, strutils, ast, msgs, options,
|
||||
filters, lineinfos, pathutils
|
||||
|
||||
type
|
||||
TParseState = enum
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# This module implements Nim's simple filters and helpers for filters.
|
||||
|
||||
import
|
||||
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
||||
llstream, idents, strutils, ast, msgs, options,
|
||||
renderer, pathutils
|
||||
|
||||
proc invalidPragma(conf: ConfigRef; n: PNode) =
|
||||
@@ -20,7 +20,7 @@ proc invalidPragma(conf: ConfigRef; n: PNode) =
|
||||
proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode =
|
||||
result = nil
|
||||
if n.kind in {nkEmpty..nkNilLit}: return
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
if n.sons[i].kind == nkExprEqExpr:
|
||||
if n.sons[i].sons[0].kind != nkIdent: invalidPragma(conf, n)
|
||||
if cmpIgnoreStyle(n.sons[i].sons[0].ident.s, name) == 0:
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## Module that implements ``gorge`` for the compiler.
|
||||
|
||||
import msgs, std / sha1, os, osproc, streams, strutils, options,
|
||||
import msgs, std / sha1, os, osproc, streams, options,
|
||||
lineinfos, pathutils
|
||||
|
||||
proc readOutput(p: Process): (string, int) =
|
||||
@@ -35,7 +35,7 @@ proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (str
|
||||
var readSuccessful = false
|
||||
try:
|
||||
var p = startProcess(cmd, workingDir,
|
||||
options={poEvalCommand, poStderrToStdout})
|
||||
options={poEvalCommand, poStdErrToStdOut})
|
||||
if input.len != 0:
|
||||
p.inputStream.write(input)
|
||||
p.inputStream.close()
|
||||
@@ -49,7 +49,7 @@ proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (str
|
||||
else:
|
||||
try:
|
||||
var p = startProcess(cmd, workingDir,
|
||||
options={poEvalCommand, poStderrToStdout})
|
||||
options={poEvalCommand, poStdErrToStdOut})
|
||||
if input.len != 0:
|
||||
p.inputStream.write(input)
|
||||
p.inputStream.close()
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## This module implements the 'implies' relation for guards.
|
||||
|
||||
import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
|
||||
saturate, modulegraphs, options, lineinfos
|
||||
saturate, modulegraphs, options, lineinfos, int128
|
||||
|
||||
const
|
||||
someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
|
||||
@@ -35,8 +35,8 @@ const
|
||||
someMul = {mMulI, mMulF64}
|
||||
someDiv = {mDivI, mDivF64}
|
||||
someMod = {mModI}
|
||||
someMax = {mMaxI, mMaxF64}
|
||||
someMin = {mMinI, mMinF64}
|
||||
someMax = {mMaxI}
|
||||
someMin = {mMinI}
|
||||
someBinaryOp = someAdd+someSub+someMul+someMax+someMin
|
||||
|
||||
proc isValue(n: PNode): bool = n.kind in {nkCharLit..nkNilLit}
|
||||
@@ -442,8 +442,8 @@ proc sameTree*(a, b: PNode): bool =
|
||||
of nkType: result = a.typ == b.typ
|
||||
of nkEmpty, nkNilLit: result = true
|
||||
else:
|
||||
if sonsLen(a) == sonsLen(b):
|
||||
for i in 0 ..< sonsLen(a):
|
||||
if len(a) == len(b):
|
||||
for i in 0 ..< len(a):
|
||||
if not sameTree(a.sons[i], b.sons[i]): return
|
||||
result = true
|
||||
|
||||
@@ -522,7 +522,7 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication =
|
||||
var value = newIntNode(c.kind, c.intVal)
|
||||
let max = lastOrd(nil, x.typ)
|
||||
# don't iterate too often:
|
||||
if max - value.intVal < 1000:
|
||||
if max - getInt(value) < toInt128(1000):
|
||||
var i, pos, neg: int
|
||||
while value.intVal <= max:
|
||||
if inSet(aSet, value): inc pos
|
||||
@@ -981,9 +981,10 @@ proc buildElse(n: PNode; o: Operators): PNode =
|
||||
var s = newNodeIT(nkCurly, n.info, settype(n.sons[0]))
|
||||
for i in 1..n.len-2:
|
||||
let branch = n.sons[i]
|
||||
assert branch.kind == nkOfBranch
|
||||
for j in 0..branch.len-2:
|
||||
s.add(branch.sons[j])
|
||||
assert branch.kind != nkElse
|
||||
if branch.kind == nkOfBranch:
|
||||
for j in 0..branch.len-2:
|
||||
s.add(branch.sons[j])
|
||||
result = newNodeI(nkCall, n.info, 3)
|
||||
result.sons[0] = newSymNode(o.opContains)
|
||||
result.sons[1] = s
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# id. This module is essential for the compiler's performance.
|
||||
|
||||
import
|
||||
hashes, strutils, wordrecg
|
||||
hashes, wordrecg
|
||||
|
||||
type
|
||||
TIdObj* = object of RootObj
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## This module contains a simple persistent id generator.
|
||||
|
||||
import idents, strutils, os, options, pathutils
|
||||
import idents, strutils, options, pathutils
|
||||
|
||||
var gFrontEndId*: int
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
## This module implements the symbol importing mechanism.
|
||||
|
||||
import
|
||||
intsets, strutils, os, ast, astalgo, msgs, options, idents, lookups,
|
||||
semdata, passes, renderer, modulepaths, sigmatch, lineinfos
|
||||
intsets, ast, astalgo, msgs, options, idents, lookups,
|
||||
semdata, modulepaths, sigmatch, lineinfos, sets
|
||||
|
||||
proc readExceptSet*(c: PContext, n: PNode): IntSet =
|
||||
assert n.kind in {nkImportExceptStmt, nkExportExceptStmt}
|
||||
@@ -31,7 +31,7 @@ proc importPureEnumField*(c: PContext; s: PSym) =
|
||||
incl(c.ambiguousSymbols, checkB.id)
|
||||
incl(c.ambiguousSymbols, s.id)
|
||||
|
||||
proc rawImportSymbol(c: PContext, s: PSym) =
|
||||
proc rawImportSymbol(c: PContext, s, origin: PSym) =
|
||||
# This does not handle stubs, because otherwise loading on demand would be
|
||||
# pointless in practice. So importing stubs is fine here!
|
||||
# check if we have already a symbol of the same name:
|
||||
@@ -47,7 +47,7 @@ proc rawImportSymbol(c: PContext, s: PSym) =
|
||||
if s.kind == skType:
|
||||
var etyp = s.typ
|
||||
if etyp.kind in {tyBool, tyEnum}:
|
||||
for j in 0 ..< sonsLen(etyp.n):
|
||||
for j in 0 ..< len(etyp.n):
|
||||
var e = etyp.n.sons[j].sym
|
||||
if e.kind != skEnumField:
|
||||
internalError(c.config, s.info, "rawImportSymbol")
|
||||
@@ -63,13 +63,14 @@ proc rawImportSymbol(c: PContext, s: PSym) =
|
||||
check = nextIdentIter(it, c.importTable.symbols)
|
||||
if e != nil:
|
||||
if sfPure notin s.flags:
|
||||
rawImportSymbol(c, e)
|
||||
rawImportSymbol(c, e, origin)
|
||||
else:
|
||||
importPureEnumField(c, e)
|
||||
else:
|
||||
# rodgen assures that converters and patterns are no stubs
|
||||
if s.kind == skConverter: addConverter(c, s)
|
||||
if hasPattern(s): addPattern(c, s)
|
||||
if s.owner != origin:
|
||||
c.exportIndirections.incl((origin.id, s.id))
|
||||
|
||||
proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
|
||||
let ident = lookups.considerQuotedIdent(c, n)
|
||||
@@ -79,19 +80,19 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
|
||||
else:
|
||||
when false:
|
||||
if s.kind == skStub: loadStub(s)
|
||||
if s.kind notin ExportableSymKinds:
|
||||
internalError(c.config, n.info, "importSymbol: 2")
|
||||
let multiImport = s.kind notin ExportableSymKinds or s.kind in skProcKinds
|
||||
# for an enumeration we have to add all identifiers
|
||||
case s.kind
|
||||
of skProcKinds:
|
||||
if multiImport:
|
||||
# for a overloadable syms add all overloaded routines
|
||||
var it: TIdentIter
|
||||
var e = initIdentIter(it, fromMod.tab, s.name)
|
||||
while e != nil:
|
||||
if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3")
|
||||
rawImportSymbol(c, e)
|
||||
if s.kind in ExportableSymKinds:
|
||||
rawImportSymbol(c, e, fromMod)
|
||||
e = nextIdentIter(it, fromMod.tab)
|
||||
else: rawImportSymbol(c, s)
|
||||
else:
|
||||
rawImportSymbol(c, s, fromMod)
|
||||
suggestSym(c.config, n.info, s, c.graph.usageSym, false)
|
||||
|
||||
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
|
||||
@@ -103,14 +104,14 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
|
||||
if s.kind notin ExportableSymKinds:
|
||||
internalError(c.config, s.info, "importAllSymbols: " & $s.kind & " " & s.name.s)
|
||||
if exceptSet.isNil or s.name.id notin exceptSet:
|
||||
rawImportSymbol(c, s)
|
||||
rawImportSymbol(c, s, fromMod)
|
||||
s = nextIter(i, fromMod.tab)
|
||||
|
||||
proc importAllSymbols*(c: PContext, fromMod: PSym) =
|
||||
var exceptSet: IntSet
|
||||
importAllSymbolsExcept(c, fromMod, exceptSet)
|
||||
|
||||
proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
|
||||
proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym) =
|
||||
if n.isNil: return
|
||||
case n.kind
|
||||
of nkExportStmt:
|
||||
@@ -120,15 +121,16 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
|
||||
if s.kind == skModule:
|
||||
importAllSymbolsExcept(c, s, exceptSet)
|
||||
elif exceptSet.isNil or s.name.id notin exceptSet:
|
||||
rawImportSymbol(c, s)
|
||||
rawImportSymbol(c, s, fromMod)
|
||||
of nkExportExceptStmt:
|
||||
localError(c.config, n.info, "'export except' not implemented")
|
||||
else:
|
||||
for i in 0..safeLen(n)-1:
|
||||
importForwarded(c, n.sons[i], exceptSet)
|
||||
importForwarded(c, n.sons[i], exceptSet, fromMod)
|
||||
|
||||
proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym =
|
||||
result = realModule
|
||||
c.unusedImports.add((realModule, n.info))
|
||||
if n.kind != nkImportAs: discard
|
||||
elif n.len != 2 or n.sons[1].kind != nkIdent:
|
||||
localError(c.config, n.info, "module alias must be an identifier")
|
||||
@@ -139,7 +141,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym =
|
||||
|
||||
proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym =
|
||||
let f = checkModuleName(c.config, n)
|
||||
if f != InvalidFileIDX:
|
||||
if f != InvalidFileIdx:
|
||||
let L = c.graph.importStack.len
|
||||
let recursion = c.graph.importStack.find(f)
|
||||
c.graph.importStack.add f
|
||||
@@ -185,11 +187,11 @@ proc impMod(c: PContext; it: PNode; importStmtResult: PNode) =
|
||||
# ``addDecl`` needs to be done before ``importAllSymbols``!
|
||||
addDecl(c, m, it.info) # add symbol to symbol table of module
|
||||
importAllSymbolsExcept(c, m, emptySet)
|
||||
#importForwarded(c, m.ast, emptySet)
|
||||
#importForwarded(c, m.ast, emptySet, m)
|
||||
|
||||
proc evalImport*(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkImportStmt, n.info)
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
let it = n.sons[i]
|
||||
if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
|
||||
let sep = it[0]
|
||||
@@ -219,7 +221,7 @@ proc evalFrom*(c: PContext, n: PNode): PNode =
|
||||
if m != nil:
|
||||
n.sons[0] = newSymNode(m)
|
||||
addDecl(c, m, n.info) # add symbol to symbol table of module
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
if n.sons[i].kind != nkNilLit:
|
||||
importSymbol(c, n.sons[i], m)
|
||||
|
||||
@@ -232,4 +234,4 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode =
|
||||
n.sons[0] = newSymNode(m)
|
||||
addDecl(c, m, n.info) # add symbol to symbol table of module
|
||||
importAllSymbolsExcept(c, m, readExceptSet(c, n))
|
||||
#importForwarded(c, m.ast, exceptSet)
|
||||
#importForwarded(c, m.ast, exceptSet, m)
|
||||
|
||||
@@ -12,11 +12,12 @@
|
||||
|
||||
const nimIncremental* = defined(nimIncremental)
|
||||
|
||||
import options, lineinfos, pathutils
|
||||
import options, lineinfos
|
||||
|
||||
when nimIncremental:
|
||||
import ast, msgs, intsets, btrees, db_sqlite, std / sha1
|
||||
import ast, msgs, intsets, btrees, db_sqlite, std / sha1, pathutils
|
||||
from strutils import parseInt
|
||||
from os import isAbsolute
|
||||
|
||||
type
|
||||
Writer* = object
|
||||
@@ -47,7 +48,7 @@ when nimIncremental:
|
||||
|
||||
proc hashFileCached*(conf: ConfigRef; fileIdx: FileIndex; fullpath: AbsoluteFile): string =
|
||||
result = msgs.getHash(conf, fileIdx)
|
||||
if result.len == 0:
|
||||
if result.len == 0 and isAbsolute(string fullpath):
|
||||
result = $secureHashFile(string fullpath)
|
||||
msgs.setHash(conf, fileIdx, result)
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ to do it.
|
||||
]#
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents,
|
||||
strutils, options, dfa, lowerings, tables, modulegraphs, msgs,
|
||||
lineinfos, parampatterns, sighashes
|
||||
|
||||
@@ -150,10 +150,11 @@ type
|
||||
graph: ModuleGraph
|
||||
emptyNode: PNode
|
||||
otherRead: PNode
|
||||
inLoop: int
|
||||
uninit: IntSet # set of uninit'ed vars
|
||||
uninitComputed: bool
|
||||
|
||||
const toDebug = ""
|
||||
const toDebug = "" # "server" # "serverNimAsyncContinue"
|
||||
|
||||
template dbg(body) =
|
||||
when toDebug.len > 0:
|
||||
@@ -165,12 +166,12 @@ proc isLastRead(location: PNode; c: var Con; pc, comesFrom: int): int =
|
||||
while pc < c.g.len:
|
||||
case c.g[pc].kind
|
||||
of def:
|
||||
if instrTargets(c.g[pc], location):
|
||||
if defInstrTargets(c.g[pc], location):
|
||||
# the path lead to a redefinition of 's' --> abandon it.
|
||||
return high(int)
|
||||
inc pc
|
||||
of use:
|
||||
if instrTargets(c.g[pc], location):
|
||||
if useInstrTargets(c.g[pc], location):
|
||||
c.otherRead = c.g[pc].n
|
||||
return -1
|
||||
inc pc
|
||||
@@ -310,6 +311,8 @@ proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) =
|
||||
m.add "; try to make "
|
||||
m.add renderTree(ri)
|
||||
m.add " a 'sink' parameter"
|
||||
m.add "; routine: "
|
||||
m.add c.owner.name.s
|
||||
localError(c.graph.config, ri.info, errGenerated, m)
|
||||
|
||||
proc makePtrType(c: Con, baseType: PType): PType =
|
||||
@@ -319,7 +322,7 @@ proc makePtrType(c: Con, baseType: PType): PType =
|
||||
proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
|
||||
var op = t.attachedOps[kind]
|
||||
|
||||
if op == nil:
|
||||
if op == nil or op.ast[genericParamsPos].kind != nkEmpty:
|
||||
# give up and find the canonical type instead:
|
||||
let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct})
|
||||
let canon = c.graph.canonTypes.getOrDefault(h)
|
||||
@@ -337,10 +340,23 @@ proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
|
||||
addrExp.add(dest)
|
||||
result = newTree(nkCall, newSymNode(op), addrExp)
|
||||
|
||||
when false:
|
||||
proc preventMoveRef(dest, ri: PNode): bool =
|
||||
let lhs = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
var ri = ri
|
||||
if ri.kind in nkCallKinds and ri[0].kind == nkSym and ri[0].sym.magic == mUnown:
|
||||
ri = ri[1]
|
||||
let rhs = ri.typ.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
result = lhs.kind == tyRef and rhs.kind == tyOwned
|
||||
|
||||
proc canBeMoved(t: PType): bool {.inline.} =
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
result = t.kind != tyRef and t.attachedOps[attachedSink] != nil
|
||||
|
||||
proc genSink(c: Con; t: PType; dest, ri: PNode): PNode =
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
let k = if t.attachedOps[attachedSink] != nil: attachedSink
|
||||
else: attachedAsgn
|
||||
else: attachedAsgn
|
||||
if t.attachedOps[k] != nil:
|
||||
result = genOp(c, t, k, dest, ri)
|
||||
else:
|
||||
@@ -349,8 +365,10 @@ proc genSink(c: Con; t: PType; dest, ri: PNode): PNode =
|
||||
# we generate a fast assignment in this case:
|
||||
result = newTree(nkFastAsgn, dest)
|
||||
|
||||
proc genCopy(c: Con; t: PType; dest, ri: PNode): PNode =
|
||||
proc genCopy(c: var Con; t: PType; dest, ri: PNode): PNode =
|
||||
if tfHasOwned in t.flags:
|
||||
# try to improve the error message here:
|
||||
if c.otherRead == nil: discard isLastRead(ri, c)
|
||||
checkForErrorPragma(c, t, ri, "=")
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
result = genOp(c, t, attachedAsgn, dest, ri)
|
||||
@@ -410,7 +428,7 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode =
|
||||
add(v, vpart)
|
||||
|
||||
result.add v
|
||||
result.add genWasMoved(n, c)
|
||||
result.add genWasMoved(skipConv(n), c)
|
||||
result.add tempAsNode
|
||||
|
||||
proc sinkParamIsLastReadCheck(c: var Con, s: PNode) =
|
||||
@@ -419,17 +437,6 @@ proc sinkParamIsLastReadCheck(c: var Con, s: PNode) =
|
||||
localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s &
|
||||
"` is already consumed at " & toFileLineCol(c. graph.config, s.info))
|
||||
|
||||
proc isSinkTypeForParam(t: PType): bool =
|
||||
# a parameter like 'seq[owned T]' must not be used only once, but its
|
||||
# elements must, so we detect this case here:
|
||||
result = t.skipTypes({tyGenericInst, tyAlias}).kind in {tySink, tyOwned}
|
||||
when false:
|
||||
if isSinkType(t):
|
||||
if t.skipTypes({tyGenericInst, tyAlias}).kind in {tyArray, tyVarargs, tyOpenArray, tySequence}:
|
||||
result = false
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc passCopyToSink(n: PNode; c: var Con): PNode =
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
let tmp = getTemp(c, n.typ, n.info)
|
||||
@@ -448,6 +455,25 @@ proc passCopyToSink(n: PNode; c: var Con): PNode =
|
||||
result.add newTree(nkAsgn, tmp, p(n, c))
|
||||
result.add tmp
|
||||
|
||||
proc isDangerousSeq(t: PType): bool {.inline.} =
|
||||
let t = t.skipTypes(abstractInst)
|
||||
result = t.kind == tySequence and tfHasOwned notin t.sons[0].flags
|
||||
|
||||
proc containsConstSeq(n: PNode): bool =
|
||||
if n.kind == nkBracket and n.len > 0 and n.typ != nil and isDangerousSeq(n.typ):
|
||||
return true
|
||||
result = false
|
||||
case n.kind
|
||||
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
|
||||
result = containsConstSeq(n[1])
|
||||
of nkObjConstr, nkClosure:
|
||||
for i in 1 ..< n.len:
|
||||
if containsConstSeq(n[i]): return true
|
||||
of nkCurly, nkBracket, nkPar, nkTupleConstr:
|
||||
for i in 0 ..< n.len:
|
||||
if containsConstSeq(n[i]): return true
|
||||
else: discard
|
||||
|
||||
proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||
template pArgIfTyped(argPart: PNode): PNode =
|
||||
# typ is nil if we are in if/case expr branch with noreturn
|
||||
@@ -464,7 +490,12 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||
result.add arg[0]
|
||||
for i in 1..<arg.len:
|
||||
result.add pArg(arg[i], c, i < L and isSinkTypeForParam(parameters[i]))
|
||||
elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkBracket, nkCharLit..nkTripleStrLit}:
|
||||
elif arg.containsConstSeq:
|
||||
# const sequences are not mutable and so we need to pass a copy to the
|
||||
# sink parameter (bug #11524). Note that the string implemenation is
|
||||
# different and can deal with 'const string sunk into var'.
|
||||
result = passCopyToSink(arg, c)
|
||||
elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkCharLit..nkTripleStrLit}:
|
||||
discard "object construction to sink parameter: nothing to do"
|
||||
result = arg
|
||||
elif arg.kind == nkSym and isSinkParam(arg.sym):
|
||||
@@ -472,7 +503,7 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||
# to disable the destructor which we have not elided
|
||||
sinkParamIsLastReadCheck(c, arg)
|
||||
result = destructiveMoveVar(arg, c)
|
||||
elif arg.kind == nkSym and arg.sym.kind in InterestingSyms and isLastRead(arg, c):
|
||||
elif isAnalysableFieldAccess(arg, c.owner) and isLastRead(arg, c):
|
||||
# it is the last read, can be sinked. We need to reset the memory
|
||||
# to disable the destructor which we have not elided
|
||||
result = destructiveMoveVar(arg, c)
|
||||
@@ -500,7 +531,7 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||
result.add p(arg[0], c)
|
||||
for i in 1..<arg.len:
|
||||
var branch: PNode
|
||||
if arg[i].kind == nkOfbranch:
|
||||
if arg[i].kind == nkOfBranch:
|
||||
branch = arg[i] # of branch conditions are constants
|
||||
branch[^1] = pArgIfTyped(arg[i][^1])
|
||||
elif arg[i].kind in {nkElifBranch, nkElifExpr}:
|
||||
@@ -511,8 +542,6 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||
branch = copyNode(arg[i])
|
||||
branch.add pArgIfTyped(arg[i][0])
|
||||
result.add branch
|
||||
elif isAnalysableFieldAccess(arg, c.owner) and isLastRead(arg, c):
|
||||
result = destructiveMoveVar(arg, c)
|
||||
else:
|
||||
# an object that is not temporary but passed to a 'sink' parameter
|
||||
# results in a copy.
|
||||
@@ -580,7 +609,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||
result.add p(ri[0], c)
|
||||
for i in 1..<ri.len:
|
||||
var branch: PNode
|
||||
if ri[i].kind == nkOfbranch:
|
||||
if ri[i].kind == nkOfBranch:
|
||||
branch = ri[i] # of branch conditions are constants
|
||||
branch[^1] = moveOrCopyIfTyped(ri[i][^1])
|
||||
elif ri[i].kind in {nkElifBranch, nkElifExpr}:
|
||||
@@ -593,7 +622,10 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||
result.add branch
|
||||
of nkBracket:
|
||||
# array constructor
|
||||
result = genSink(c, dest.typ, dest, ri)
|
||||
if ri.len > 0 and isDangerousSeq(ri.typ):
|
||||
result = genCopy(c, dest.typ, dest, ri)
|
||||
else:
|
||||
result = genSink(c, dest.typ, dest, ri)
|
||||
let ri2 = copyTree(ri)
|
||||
for i in 0..<ri.len:
|
||||
# everything that is passed to an array constructor is consumed,
|
||||
@@ -611,7 +643,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||
of nkTupleConstr, nkClosure:
|
||||
result = genSink(c, dest.typ, dest, ri)
|
||||
let ri2 = copyTree(ri)
|
||||
for i in 0..<ri.len:
|
||||
for i in ord(ri.kind == nkClosure)..<ri.len:
|
||||
# everything that is passed to an tuple constructor is consumed,
|
||||
# so these all act like 'sink' parameters:
|
||||
if ri[i].kind == nkExprColonExpr:
|
||||
@@ -629,7 +661,8 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||
var snk = genSink(c, dest.typ, dest, ri)
|
||||
snk.add ri
|
||||
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
|
||||
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and isLastRead(ri, c):
|
||||
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
|
||||
isLastRead(ri, c) and canBeMoved(dest.typ):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
var snk = genSink(c, dest.typ, dest, ri)
|
||||
snk.add ri
|
||||
@@ -661,7 +694,8 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||
result = genCopy(c, dest.typ, dest, ri)
|
||||
result.add p(ri, c)
|
||||
else:
|
||||
if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c):
|
||||
if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and
|
||||
canBeMoved(dest.typ):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
var snk = genSink(c, dest.typ, dest, ri)
|
||||
snk.add ri
|
||||
@@ -721,7 +755,7 @@ proc p(n: PNode; c: var Con): PNode =
|
||||
for i in 0..<n.len:
|
||||
let it = n[i]
|
||||
let L = it.len
|
||||
let ri = it[L-1]
|
||||
var ri = it[L-1]
|
||||
if it.kind == nkVarTuple and hasDestructor(ri.typ):
|
||||
let x = lowerTupleUnpacking(c.graph, it, c.owner)
|
||||
result.add p(x, c)
|
||||
@@ -735,6 +769,8 @@ proc p(n: PNode; c: var Con): PNode =
|
||||
# make sure it's destroyed at the end of the proc:
|
||||
if not isUnpackedTuple(it[0].sym):
|
||||
c.destroys.add genDestroy(c, v.typ, v)
|
||||
if ri.kind == nkEmpty and c.inLoop > 0:
|
||||
ri = genDefaultCall(v.typ, c, v.info)
|
||||
if ri.kind != nkEmpty:
|
||||
let r = moveOrCopy(v, ri, c)
|
||||
result.add r
|
||||
@@ -757,8 +793,12 @@ proc p(n: PNode; c: var Con): PNode =
|
||||
else:
|
||||
result = n
|
||||
of nkAsgn, nkFastAsgn:
|
||||
if hasDestructor(n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda, nkClosure}:
|
||||
result = moveOrCopy(n[0], n[1], c)
|
||||
if hasDestructor(n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda}:
|
||||
# rule (self-assignment-removal):
|
||||
if n[1].kind == nkSym and n[0].kind == nkSym and n[0].sym == n[1].sym:
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
else:
|
||||
result = moveOrCopy(n[0], n[1], c)
|
||||
else:
|
||||
result = copyNode(n)
|
||||
recurse(n, result)
|
||||
@@ -777,20 +817,31 @@ proc p(n: PNode; c: var Con): PNode =
|
||||
result[1][0] = p(result[1][0], c)
|
||||
of nkRaiseStmt:
|
||||
if optNimV2 in c.graph.config.globalOptions and n[0].kind != nkEmpty:
|
||||
let t = n[0].typ
|
||||
let tmp = getTemp(c, t, n.info)
|
||||
var m = genCopyNoCheck(c, t, tmp, n[0])
|
||||
if n[0].kind in nkCallKinds:
|
||||
let call = copyNode(n[0])
|
||||
recurse(n[0], call)
|
||||
result = copyNode(n)
|
||||
result.add call
|
||||
else:
|
||||
let t = n[0].typ
|
||||
let tmp = getTemp(c, t, n.info)
|
||||
var m = genCopyNoCheck(c, t, tmp, n[0])
|
||||
|
||||
m.add p(n[0], c)
|
||||
result = newTree(nkStmtList, genWasMoved(tmp, c), m)
|
||||
var toDisarm = n[0]
|
||||
if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon
|
||||
if toDisarm.kind == nkSym and toDisarm.sym.owner == c.owner:
|
||||
result.add genWasMoved(toDisarm, c)
|
||||
result.add newTree(nkRaiseStmt, tmp)
|
||||
m.add p(n[0], c)
|
||||
result = newTree(nkStmtList, genWasMoved(tmp, c), m)
|
||||
var toDisarm = n[0]
|
||||
if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon
|
||||
if toDisarm.kind == nkSym and toDisarm.sym.owner == c.owner:
|
||||
result.add genWasMoved(toDisarm, c)
|
||||
result.add newTree(nkRaiseStmt, tmp)
|
||||
else:
|
||||
result = copyNode(n)
|
||||
recurse(n, result)
|
||||
of nkForStmt, nkParForStmt, nkWhileStmt:
|
||||
inc c.inLoop
|
||||
result = copyNode(n)
|
||||
recurse(n, result)
|
||||
dec c.inLoop
|
||||
else:
|
||||
result = copyNode(n)
|
||||
recurse(n, result)
|
||||
|
||||
@@ -6,10 +6,10 @@ Name: "Nim"
|
||||
Version: "$version"
|
||||
Platforms: """
|
||||
windows: i386;amd64
|
||||
linux: i386;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv64
|
||||
linux: i386;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv64
|
||||
macosx: i386;amd64;powerpc64
|
||||
solaris: i386;amd64;sparc;sparc64
|
||||
freebsd: i386;amd64
|
||||
freebsd: i386;amd64;powerpc64
|
||||
netbsd: i386;amd64
|
||||
openbsd: i386;amd64
|
||||
dragonfly: i386;amd64
|
||||
@@ -86,6 +86,8 @@ Files: "bin/nimsuggest.exe"
|
||||
Files: "bin/nimble.exe"
|
||||
Files: "bin/vccexe.exe"
|
||||
Files: "bin/nimgrab.exe"
|
||||
Files: "bin/nimpretty.exe"
|
||||
Files: "bin/testament.exe"
|
||||
|
||||
Files: "koch.exe"
|
||||
Files: "finish.exe"
|
||||
|
||||
669
compiler/int128.nim
Normal file
669
compiler/int128.nim
Normal file
@@ -0,0 +1,669 @@
|
||||
## This module is for compiler internal use only. For reliable error
|
||||
## messages and range checks, the compiler needs a data type that can
|
||||
## hold all from ``low(BiggestInt)`` to ``high(BiggestUInt)``, This
|
||||
## type is for that purpose.
|
||||
|
||||
from math import trunc
|
||||
|
||||
type
|
||||
Int128* = object
|
||||
udata: array[4,uint32]
|
||||
|
||||
template sdata(arg: Int128, idx: int): int32 =
|
||||
# udata and sdata was supposed to be in a union, but unions are
|
||||
# handled incorrectly in the VM.
|
||||
cast[ptr int32](arg.udata[idx].unsafeAddr)[]
|
||||
|
||||
# encoding least significant int first (like LittleEndian)
|
||||
|
||||
const
|
||||
Zero* = Int128(udata: [0'u32,0,0,0])
|
||||
One* = Int128(udata: [1'u32,0,0,0])
|
||||
Ten* = Int128(udata: [10'u32,0,0,0])
|
||||
Min = Int128(udata: [0'u32,0,0,0x80000000'u32])
|
||||
Max = Int128(udata: [high(uint32),high(uint32),high(uint32),uint32(high(int32))])
|
||||
NegOne* = Int128(udata: [0xffffffff'u32,0xffffffff'u32,0xffffffff'u32,0xffffffff'u32])
|
||||
|
||||
template low*(t: typedesc[Int128]): Int128 = Min
|
||||
template high*(t: typedesc[Int128]): Int128 = Max
|
||||
|
||||
proc `$`*(a: Int128): string
|
||||
|
||||
proc toInt128*[T: SomeInteger](arg: T): Int128 =
|
||||
when 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)
|
||||
else:
|
||||
when sizeof(arg) <= 4:
|
||||
result.sdata(0) = int32(arg)
|
||||
if arg < 0: # sign extend
|
||||
result.sdata(1) = -1
|
||||
result.sdata(2) = -1
|
||||
result.sdata(3) = -1
|
||||
else:
|
||||
let tmp = int64(arg)
|
||||
result.udata[0] = uint32(tmp and 0xffffffff)
|
||||
result.sdata(1) = int32(tmp shr 32)
|
||||
if arg < 0: # sign extend
|
||||
result.sdata(2) = -1
|
||||
result.sdata(3) = -1
|
||||
|
||||
template isNegative(arg: Int128): bool =
|
||||
arg.sdata(3) < 0
|
||||
|
||||
template isNegative(arg: int32): bool =
|
||||
arg < 0
|
||||
|
||||
proc bitconcat(a,b: uint32): uint64 =
|
||||
(uint64(a) shl 32) or uint64(b)
|
||||
|
||||
proc bitsplit(a: uint64): (uint32,uint32) =
|
||||
(cast[uint32](a shr 32), cast[uint32](a))
|
||||
|
||||
proc toInt64*(arg: Int128): int64 =
|
||||
if isNegative(arg):
|
||||
assert(arg.sdata(3) == -1, "out of range")
|
||||
assert(arg.sdata(2) == -1, "out of range")
|
||||
else:
|
||||
assert(arg.sdata(3) == 0, "out of range")
|
||||
assert(arg.sdata(2) == 0, "out of range")
|
||||
|
||||
cast[int64](bitconcat(arg.udata[1], arg.udata[0]))
|
||||
|
||||
proc toInt32*(arg: Int128): int32 =
|
||||
if isNegative(arg):
|
||||
assert(arg.sdata(3) == -1, "out of range")
|
||||
assert(arg.sdata(2) == -1, "out of range")
|
||||
assert(arg.sdata(1) == -1, "out of range")
|
||||
else:
|
||||
assert(arg.sdata(3) == 0, "out of range")
|
||||
assert(arg.sdata(2) == 0, "out of range")
|
||||
assert(arg.sdata(1) == 0, "out of range")
|
||||
|
||||
arg.sdata(0)
|
||||
|
||||
proc toInt16*(arg: Int128): int16 =
|
||||
if isNegative(arg):
|
||||
assert(arg.sdata(3) == -1, "out of range")
|
||||
assert(arg.sdata(2) == -1, "out of range")
|
||||
assert(arg.sdata(1) == -1, "out of range")
|
||||
else:
|
||||
assert(arg.sdata(3) == 0, "out of range")
|
||||
assert(arg.sdata(2) == 0, "out of range")
|
||||
assert(arg.sdata(1) == 0, "out of range")
|
||||
|
||||
int16(arg.sdata(0))
|
||||
|
||||
proc toInt8*(arg: Int128): int8 =
|
||||
if isNegative(arg):
|
||||
assert(arg.sdata(3) == -1, "out of range")
|
||||
assert(arg.sdata(2) == -1, "out of range")
|
||||
assert(arg.sdata(1) == -1, "out of range")
|
||||
else:
|
||||
assert(arg.sdata(3) == 0, "out of range")
|
||||
assert(arg.sdata(2) == 0, "out of range")
|
||||
assert(arg.sdata(1) == 0, "out of range")
|
||||
|
||||
int8(arg.sdata(0))
|
||||
|
||||
proc toInt*(arg: Int128): int =
|
||||
when sizeof(int) == 4:
|
||||
cast[int](toInt32(arg))
|
||||
else:
|
||||
cast[int](toInt64(arg))
|
||||
|
||||
proc toUInt64*(arg: Int128): uint64 =
|
||||
assert(arg.udata[3] == 0)
|
||||
assert(arg.udata[2] == 0)
|
||||
bitconcat(arg.udata[1], arg.udata[0])
|
||||
|
||||
proc toUInt32*(arg: Int128): uint32 =
|
||||
assert(arg.udata[3] == 0)
|
||||
assert(arg.udata[2] == 0)
|
||||
assert(arg.udata[1] == 0)
|
||||
arg.udata[0]
|
||||
|
||||
proc toUInt16*(arg: Int128): uint16 =
|
||||
assert(arg.udata[3] == 0)
|
||||
assert(arg.udata[2] == 0)
|
||||
assert(arg.udata[1] == 0)
|
||||
uint16(arg.udata[0])
|
||||
|
||||
proc toUInt8*(arg: Int128): uint8 =
|
||||
assert(arg.udata[3] == 0)
|
||||
assert(arg.udata[2] == 0)
|
||||
assert(arg.udata[1] == 0)
|
||||
uint8(arg.udata[0])
|
||||
|
||||
proc toUInt*(arg: Int128): uint =
|
||||
when sizeof(int) == 4:
|
||||
cast[uint](toInt32(arg))
|
||||
else:
|
||||
cast[uint](toInt64(arg))
|
||||
|
||||
proc castToInt64*(arg: Int128): int64 =
|
||||
## Conversion to int64 without range check.
|
||||
cast[int64](bitconcat(arg.udata[1], arg.udata[0]))
|
||||
|
||||
proc castToUInt64*(arg: Int128): uint64 =
|
||||
## Conversion to uint64 without range check.
|
||||
cast[uint64](bitconcat(arg.udata[1], arg.udata[0]))
|
||||
|
||||
proc addToHex(result: var string; arg: uint32) =
|
||||
for i in 0 ..< 8:
|
||||
let idx = (arg shr ((7-i) * 4)) and 0xf
|
||||
result.add "0123456789abcdef"[idx]
|
||||
|
||||
proc addToHex*(result: var string; arg: Int128) =
|
||||
var i = 3
|
||||
while i >= 0:
|
||||
result.addToHex(arg.udata[i])
|
||||
i -= 1
|
||||
|
||||
proc toHex*(arg: Int128): string =
|
||||
result.addToHex(arg)
|
||||
|
||||
proc inc*(a: var Int128, y: uint32 = 1) =
|
||||
let input = a
|
||||
a.udata[0] += y
|
||||
if unlikely(a.udata[0] < y):
|
||||
a.udata[1].inc
|
||||
if unlikely(a.udata[1] == 0):
|
||||
a.udata[2].inc
|
||||
if unlikely(a.udata[2] == 0):
|
||||
a.udata[3].inc
|
||||
doAssert(a.sdata(3) != low(int32), "overflow")
|
||||
|
||||
proc cmp*(a,b: Int128): int =
|
||||
let tmp1 = cmp(a.sdata(3), b.sdata(3))
|
||||
if tmp1 != 0: return tmp1
|
||||
let tmp2 = cmp(a.udata[2], b.udata[2])
|
||||
if tmp2 != 0: return tmp2
|
||||
let tmp3 = cmp(a.udata[1], b.udata[1])
|
||||
if tmp3 != 0: return tmp3
|
||||
let tmp4 = cmp(a.udata[0], b.udata[0])
|
||||
return tmp4
|
||||
|
||||
proc `<`*(a,b: Int128): bool =
|
||||
cmp(a,b) < 0
|
||||
|
||||
proc `<=`*(a,b: Int128): bool =
|
||||
cmp(a,b) <= 0
|
||||
|
||||
proc `==`*(a,b: Int128): bool =
|
||||
if a.udata[0] != b.udata[0]: return false
|
||||
if a.udata[1] != b.udata[1]: return false
|
||||
if a.udata[2] != b.udata[2]: return false
|
||||
if a.udata[3] != b.udata[3]: return false
|
||||
return true
|
||||
|
||||
proc inplaceBitnot(a: var Int128) =
|
||||
a.udata[0] = not a.udata[0]
|
||||
a.udata[1] = not a.udata[1]
|
||||
a.udata[2] = not a.udata[2]
|
||||
a.udata[3] = not a.udata[3]
|
||||
|
||||
proc bitnot*(a: Int128): Int128 =
|
||||
result.udata[0] = not a.udata[0]
|
||||
result.udata[1] = not a.udata[1]
|
||||
result.udata[2] = not a.udata[2]
|
||||
result.udata[3] = not a.udata[3]
|
||||
|
||||
proc bitand*(a,b: Int128): Int128 =
|
||||
result.udata[0] = a.udata[0] and b.udata[0]
|
||||
result.udata[1] = a.udata[1] and b.udata[1]
|
||||
result.udata[2] = a.udata[2] and b.udata[2]
|
||||
result.udata[3] = a.udata[3] and b.udata[3]
|
||||
|
||||
proc bitor*(a,b: Int128): Int128 =
|
||||
result.udata[0] = a.udata[0] or b.udata[0]
|
||||
result.udata[1] = a.udata[1] or b.udata[1]
|
||||
result.udata[2] = a.udata[2] or b.udata[2]
|
||||
result.udata[3] = a.udata[3] or b.udata[3]
|
||||
|
||||
proc bitxor*(a,b: Int128): Int128 =
|
||||
result.udata[0] = a.udata[0] xor b.udata[0]
|
||||
result.udata[1] = a.udata[1] xor b.udata[1]
|
||||
result.udata[2] = a.udata[2] xor b.udata[2]
|
||||
result.udata[3] = a.udata[3] xor b.udata[3]
|
||||
|
||||
proc `shr`*(a: Int128, b: int): Int128 =
|
||||
let b = b and 127
|
||||
if b < 32:
|
||||
result.sdata(3) = a.sdata(3) shr b
|
||||
result.udata[2] = cast[uint32](bitconcat(a.udata[3], a.udata[2]) shr b)
|
||||
result.udata[1] = cast[uint32](bitconcat(a.udata[2], a.udata[1]) shr b)
|
||||
result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr b)
|
||||
elif b < 64:
|
||||
if isNegative(a):
|
||||
result.sdata(3) = -1
|
||||
result.sdata(2) = a.sdata(3) shr (b and 31)
|
||||
result.udata[1] = cast[uint32](bitconcat(a.udata[2], a.udata[1]) shr (b and 31))
|
||||
result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr (b and 31))
|
||||
elif b < 96:
|
||||
if isNegative(a):
|
||||
result.sdata(3) = -1
|
||||
result.sdata(2) = -1
|
||||
result.sdata(1) = a.sdata(3) shr (b and 31)
|
||||
result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr (b and 31))
|
||||
else: # b < 128
|
||||
if isNegative(a):
|
||||
result.sdata(3) = -1
|
||||
result.sdata(2) = -1
|
||||
result.sdata(1) = -1
|
||||
result.sdata(0) = a.sdata(3) shr (b and 31)
|
||||
|
||||
proc `shl`*(a: Int128, b: int): Int128 =
|
||||
let b = b and 127
|
||||
if b < 32:
|
||||
result.udata[0] = a.udata[0] shl b
|
||||
result.udata[1] = cast[uint32]((bitconcat(a.udata[1], a.udata[0]) shl b) shr 32)
|
||||
result.udata[2] = cast[uint32]((bitconcat(a.udata[2], a.udata[1]) shl b) shr 32)
|
||||
result.udata[3] = cast[uint32]((bitconcat(a.udata[3], a.udata[2]) shl b) shr 32)
|
||||
elif b < 64:
|
||||
result.udata[0] = 0
|
||||
result.udata[1] = a.udata[0] shl (b and 31)
|
||||
result.udata[2] = cast[uint32]((bitconcat(a.udata[1], a.udata[0]) shl (b and 31)) shr 32)
|
||||
result.udata[3] = cast[uint32]((bitconcat(a.udata[2], a.udata[1]) shl (b and 31)) shr 32)
|
||||
elif b < 96:
|
||||
result.udata[0] = 0
|
||||
result.udata[1] = 0
|
||||
result.udata[2] = a.udata[0] shl (b and 31)
|
||||
result.udata[3] = cast[uint32]((bitconcat(a.udata[1], a.udata[0]) shl (b and 31)) shr 32)
|
||||
else:
|
||||
result.udata[0] = 0
|
||||
result.udata[1] = 0
|
||||
result.udata[2] = 0
|
||||
result.udata[3] = a.udata[0] shl (b and 31)
|
||||
|
||||
proc `+`*(a,b: Int128): Int128 =
|
||||
let tmp0 = uint64(a.udata[0]) + uint64(b.udata[0])
|
||||
result.udata[0] = cast[uint32](tmp0)
|
||||
let tmp1 = uint64(a.udata[1]) + uint64(b.udata[1]) + (tmp0 shr 32)
|
||||
result.udata[1] = cast[uint32](tmp1)
|
||||
let tmp2 = uint64(a.udata[2]) + uint64(b.udata[2]) + (tmp1 shr 32)
|
||||
result.udata[2] = cast[uint32](tmp2)
|
||||
let tmp3 = uint64(a.udata[3]) + uint64(b.udata[3]) + (tmp2 shr 32)
|
||||
result.udata[3] = cast[uint32](tmp3)
|
||||
|
||||
proc `+=`*(a: var Int128, b: Int128) =
|
||||
a = a + b
|
||||
|
||||
proc `-`*(a: Int128): Int128 =
|
||||
result = bitnot(a)
|
||||
result.inc
|
||||
|
||||
proc `-`*(a,b: Int128): Int128 =
|
||||
a + (-b)
|
||||
|
||||
proc `-=`*(a: var Int128, b: Int128) =
|
||||
a = a - b
|
||||
|
||||
proc abs*(a: Int128): Int128 =
|
||||
if isNegative(a):
|
||||
-a
|
||||
else:
|
||||
a
|
||||
|
||||
proc abs(a: int32): int =
|
||||
if a < 0: -a else: a
|
||||
|
||||
proc `*`(a: Int128, b: uint32): Int128 =
|
||||
let tmp0 = uint64(a.udata[0]) * uint64(b)
|
||||
let tmp1 = uint64(a.udata[1]) * uint64(b)
|
||||
let tmp2 = uint64(a.udata[2]) * uint64(b)
|
||||
let tmp3 = uint64(a.udata[3]) * uint64(b)
|
||||
|
||||
if unlikely(tmp3 > uint64(high(int32))):
|
||||
assert(false, "overflow")
|
||||
|
||||
result.udata[0] = cast[uint32](tmp0)
|
||||
result.udata[1] = cast[uint32](tmp1) + cast[uint32](tmp0 shr 32)
|
||||
result.udata[2] = cast[uint32](tmp2) + cast[uint32](tmp1 shr 32)
|
||||
result.udata[3] = cast[uint32](tmp3) + cast[uint32](tmp2 shr 32)
|
||||
|
||||
proc `*`*(a: Int128, b: int32): Int128 =
|
||||
let isNegative = isNegative(a) xor isNegative(b)
|
||||
result = a * cast[uint32](abs(b))
|
||||
if b < 0:
|
||||
result = -result
|
||||
|
||||
proc `*=`*(a: var Int128, b: int32): Int128 =
|
||||
result = result * b
|
||||
|
||||
proc makeInt128(high,low: uint64): Int128 =
|
||||
result.udata[0] = cast[uint32](low)
|
||||
result.udata[1] = cast[uint32](low shr 32)
|
||||
result.udata[2] = cast[uint32](high)
|
||||
result.udata[3] = cast[uint32](high shr 32)
|
||||
|
||||
proc high64(a: Int128): uint64 =
|
||||
bitconcat(a.udata[3], a.udata[2])
|
||||
|
||||
proc low64(a: Int128): uint64 =
|
||||
bitconcat(a.udata[1], a.udata[0])
|
||||
|
||||
proc `*`*(lhs,rhs: Int128): Int128 =
|
||||
let isNegative = isNegative(lhs) xor isNegative(rhs)
|
||||
|
||||
let
|
||||
a = cast[uint64](lhs.udata[0])
|
||||
b = cast[uint64](lhs.udata[1])
|
||||
c = cast[uint64](lhs.udata[2])
|
||||
d = cast[uint64](lhs.udata[3])
|
||||
|
||||
e = cast[uint64](rhs.udata[0])
|
||||
f = cast[uint64](rhs.udata[1])
|
||||
g = cast[uint64](rhs.udata[2])
|
||||
h = cast[uint64](rhs.udata[3])
|
||||
|
||||
|
||||
let a32 = cast[uint64](lhs.udata[1])
|
||||
let a00 = cast[uint64](lhs.udata[0])
|
||||
let b32 = cast[uint64](rhs.udata[1])
|
||||
let b00 = cast[uint64](rhs.udata[0])
|
||||
|
||||
result = makeInt128(high64(lhs) * low64(rhs) + low64(lhs) * high64(rhs) + a32 * b32, a00 * b00)
|
||||
result = result + toInt128(a32 * b00) shl 32
|
||||
result = result + toInt128(a00 * b32) shl 32
|
||||
|
||||
if isNegative != isNegative(result):
|
||||
assert(false, "overflow")
|
||||
|
||||
proc `*=`*(a: var Int128, b: Int128) =
|
||||
a = a * b
|
||||
|
||||
import bitops
|
||||
|
||||
proc fastLog2*(a: Int128): int =
|
||||
if a.udata[3] != 0:
|
||||
return 96 + fastLog2(a.udata[3])
|
||||
if a.udata[2] != 0:
|
||||
return 64 + fastLog2(a.udata[2])
|
||||
if a.udata[1] != 0:
|
||||
return 32 + fastLog2(a.udata[1])
|
||||
if a.udata[0] != 0:
|
||||
return fastLog2(a.udata[0])
|
||||
|
||||
proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
|
||||
assert(divisor != Zero)
|
||||
let isNegativeA = isNegative(dividend)
|
||||
let isNegativeB = isNegative(divisor)
|
||||
|
||||
var dividend = abs(dividend)
|
||||
let divisor = abs(divisor)
|
||||
|
||||
if divisor > dividend:
|
||||
result.quotient = Zero
|
||||
result.remainder = dividend
|
||||
return
|
||||
|
||||
if divisor == dividend:
|
||||
result.quotient = One
|
||||
result.remainder = Zero
|
||||
return
|
||||
|
||||
var denominator = divisor
|
||||
var quotient = Zero
|
||||
|
||||
# Left aligns the MSB of the denominator and the dividend.
|
||||
let shift = fastLog2(dividend) - fastLog2(denominator)
|
||||
denominator = denominator shl shift
|
||||
|
||||
# Uses shift-subtract algorithm to divide dividend by denominator. The
|
||||
# remainder will be left in dividend.
|
||||
for i in 0 .. shift:
|
||||
quotient = quotient shl 1
|
||||
if dividend >= denominator:
|
||||
dividend = dividend - denominator
|
||||
quotient = bitor(quotient, One)
|
||||
|
||||
denominator = denominator shr 1
|
||||
|
||||
if isNegativeA xor isNegativeB:
|
||||
result.quotient = -quotient
|
||||
else:
|
||||
result.quotient = quotient
|
||||
if isNegativeB:
|
||||
result.remainder = -dividend
|
||||
else:
|
||||
result.remainder = dividend
|
||||
|
||||
proc `div`*(a,b: Int128): Int128 =
|
||||
let (a,b) = divMod(a,b)
|
||||
return a
|
||||
|
||||
proc `mod`*(a,b: Int128): Int128 =
|
||||
let (a,b) = divMod(a,b)
|
||||
return b
|
||||
|
||||
proc addInt128*(result: var string; value: Int128) =
|
||||
let initialSize = result.len
|
||||
if value == Zero:
|
||||
result.add "0"
|
||||
elif value == low(Int128):
|
||||
result.add "-170141183460469231731687303715884105728"
|
||||
else:
|
||||
let isNegative = isNegative(value)
|
||||
var value = abs(value)
|
||||
while value > Zero:
|
||||
let (quot, rem) = divMod(value, Ten)
|
||||
result.add "0123456789"[rem.toInt64]
|
||||
value = quot
|
||||
if isNegative:
|
||||
result.add '-'
|
||||
|
||||
var i = initialSize
|
||||
var j = high(result)
|
||||
while i < j:
|
||||
swap(result[i], result[j])
|
||||
i += 1
|
||||
j -= 1
|
||||
|
||||
proc `$`*(a: Int128): string =
|
||||
result.addInt128(a)
|
||||
|
||||
proc parseDecimalInt128*(arg: string, pos: int = 0): Int128 =
|
||||
assert(pos < arg.len)
|
||||
assert(arg[pos] in {'-','0'..'9'})
|
||||
|
||||
var isNegative = false
|
||||
var pos = pos
|
||||
if arg[pos] == '-':
|
||||
isNegative = true
|
||||
pos += 1
|
||||
|
||||
result = Zero
|
||||
while pos < arg.len and arg[pos] in '0' .. '9':
|
||||
result = result * Ten
|
||||
result.inc(uint32(arg[pos]) - uint32('0'))
|
||||
pos += 1
|
||||
|
||||
if isNegative:
|
||||
result = -result
|
||||
|
||||
# fluff
|
||||
|
||||
proc `<`*(a: Int128, b: BiggestInt): bool =
|
||||
cmp(a,toInt128(b)) < 0
|
||||
|
||||
proc `<`*(a: BiggestInt, b: Int128): bool =
|
||||
cmp(toInt128(a), b) < 0
|
||||
|
||||
proc `<=`*(a: Int128, b: BiggestInt): bool =
|
||||
cmp(a,toInt128(b)) <= 0
|
||||
|
||||
proc `<=`*(a: BiggestInt, b: Int128): bool =
|
||||
cmp(toInt128(a), b) <= 0
|
||||
|
||||
proc `==`*(a: Int128, b: BiggestInt): bool =
|
||||
a == toInt128(b)
|
||||
|
||||
proc `==`*(a: BiggestInt, b: Int128): bool =
|
||||
toInt128(a) == b
|
||||
|
||||
proc `-`*(a: BiggestInt, b: Int128): Int128 =
|
||||
toInt128(a) - b
|
||||
|
||||
proc `-`*(a: Int128, b: BiggestInt): Int128 =
|
||||
a - toInt128(b)
|
||||
|
||||
proc `+`*(a: BiggestInt, b: Int128): Int128 =
|
||||
toInt128(a) + b
|
||||
|
||||
proc `+`*(a: Int128, b: BiggestInt): Int128 =
|
||||
a + toInt128(b)
|
||||
|
||||
proc toFloat64*(arg: Int128): float64 =
|
||||
let isNegative = isNegative(arg)
|
||||
let arg = abs(arg)
|
||||
|
||||
let a = float64(bitconcat(arg.udata[1], arg.udata[0]))
|
||||
let b = float64(bitconcat(arg.udata[3], arg.udata[2]))
|
||||
|
||||
result = a + 18446744073709551616'f64 * b # a + 2^64 * b
|
||||
if isNegative:
|
||||
result = -result
|
||||
|
||||
proc ldexp(x: float64, exp: cint): float64 {.importc: "ldexp", header: "<math.h>".}
|
||||
|
||||
template bitor(a,b,c: Int128): Int128 = bitor(bitor(a,b), c)
|
||||
|
||||
proc toInt128*(arg: float64): Int128 =
|
||||
let isNegative = arg < 0
|
||||
assert(arg < 0x47E0000000000000'f64, "out of range")
|
||||
assert(arg >= 0xC7E0000000000000'f64, "out of range")
|
||||
let v0 = ldexp(abs(arg), -100)
|
||||
let w0 = uint64(trunc(v0))
|
||||
let v1 = ldexp(v0 - float64(w0), 50)
|
||||
let w1 = uint64(trunc(v1))
|
||||
let v2 = ldexp(v1 - float64(w1), 50)
|
||||
let w2 = uint64(trunc(v2))
|
||||
|
||||
let res = bitor(toInt128(w0) shl 100, toInt128(w1) shl 50, toInt128(w2))
|
||||
if isNegative:
|
||||
return -res
|
||||
else:
|
||||
return res
|
||||
|
||||
proc maskUInt64*(arg: Int128): Int128 {.noinit, inline.} =
|
||||
result.udata[0] = arg.udata[0]
|
||||
result.udata[1] = arg.udata[1]
|
||||
result.udata[2] = 0
|
||||
result.udata[3] = 0
|
||||
|
||||
proc maskUInt32*(arg: Int128): Int128 {.noinit, inline.} =
|
||||
result.udata[0] = arg.udata[0]
|
||||
result.udata[1] = 0
|
||||
result.udata[2] = 0
|
||||
result.udata[3] = 0
|
||||
|
||||
proc maskUInt16*(arg: Int128): Int128 {.noinit, inline.} =
|
||||
result.udata[0] = arg.udata[0] and 0xffff
|
||||
result.udata[1] = 0
|
||||
result.udata[2] = 0
|
||||
result.udata[3] = 0
|
||||
|
||||
proc maskUInt8*(arg: Int128): Int128 {.noinit, inline.} =
|
||||
result.udata[0] = arg.udata[0] and 0xff
|
||||
result.udata[1] = 0
|
||||
result.udata[2] = 0
|
||||
result.udata[3] = 0
|
||||
|
||||
proc maskBytes*(arg: Int128, numbytes: int): Int128 {.noinit.} =
|
||||
case numbytes
|
||||
of 1:
|
||||
return maskUInt8(arg)
|
||||
of 2:
|
||||
return maskUInt16(arg)
|
||||
of 4:
|
||||
return maskUInt32(arg)
|
||||
of 8:
|
||||
return maskUInt64(arg)
|
||||
else:
|
||||
assert(false, "masking only implemented for 1, 2, 4 and 8 bytes")
|
||||
|
||||
|
||||
|
||||
|
||||
when isMainModule:
|
||||
let (a,b) = divMod(Ten,Ten)
|
||||
|
||||
doAssert $One == "1"
|
||||
doAssert $Ten == "10"
|
||||
doAssert $Zero == "0"
|
||||
let c = parseDecimalInt128("12345678989876543210123456789")
|
||||
doAssert $c == "12345678989876543210123456789"
|
||||
|
||||
var d : array[39, Int128]
|
||||
d[0] = parseDecimalInt128("1")
|
||||
d[1] = parseDecimalInt128("10")
|
||||
d[2] = parseDecimalInt128("100")
|
||||
d[3] = parseDecimalInt128("1000")
|
||||
d[4] = parseDecimalInt128("10000")
|
||||
d[5] = parseDecimalInt128("100000")
|
||||
d[6] = parseDecimalInt128("1000000")
|
||||
d[7] = parseDecimalInt128("10000000")
|
||||
d[8] = parseDecimalInt128("100000000")
|
||||
d[9] = parseDecimalInt128("1000000000")
|
||||
d[10] = parseDecimalInt128("10000000000")
|
||||
d[11] = parseDecimalInt128("100000000000")
|
||||
d[12] = parseDecimalInt128("1000000000000")
|
||||
d[13] = parseDecimalInt128("10000000000000")
|
||||
d[14] = parseDecimalInt128("100000000000000")
|
||||
d[15] = parseDecimalInt128("1000000000000000")
|
||||
d[16] = parseDecimalInt128("10000000000000000")
|
||||
d[17] = parseDecimalInt128("100000000000000000")
|
||||
d[18] = parseDecimalInt128("1000000000000000000")
|
||||
d[19] = parseDecimalInt128("10000000000000000000")
|
||||
d[20] = parseDecimalInt128("100000000000000000000")
|
||||
d[21] = parseDecimalInt128("1000000000000000000000")
|
||||
d[22] = parseDecimalInt128("10000000000000000000000")
|
||||
d[23] = parseDecimalInt128("100000000000000000000000")
|
||||
d[24] = parseDecimalInt128("1000000000000000000000000")
|
||||
d[25] = parseDecimalInt128("10000000000000000000000000")
|
||||
d[26] = parseDecimalInt128("100000000000000000000000000")
|
||||
d[27] = parseDecimalInt128("1000000000000000000000000000")
|
||||
d[28] = parseDecimalInt128("10000000000000000000000000000")
|
||||
d[29] = parseDecimalInt128("100000000000000000000000000000")
|
||||
d[30] = parseDecimalInt128("1000000000000000000000000000000")
|
||||
d[31] = parseDecimalInt128("10000000000000000000000000000000")
|
||||
d[32] = parseDecimalInt128("100000000000000000000000000000000")
|
||||
d[33] = parseDecimalInt128("1000000000000000000000000000000000")
|
||||
d[34] = parseDecimalInt128("10000000000000000000000000000000000")
|
||||
d[35] = parseDecimalInt128("100000000000000000000000000000000000")
|
||||
d[36] = parseDecimalInt128("1000000000000000000000000000000000000")
|
||||
d[37] = parseDecimalInt128("10000000000000000000000000000000000000")
|
||||
d[38] = parseDecimalInt128("100000000000000000000000000000000000000")
|
||||
|
||||
for i in 0 ..< d.len:
|
||||
for j in 0 ..< d.len:
|
||||
doAssert(cmp(d[i], d[j]) == cmp(i,j))
|
||||
if i + j < d.len:
|
||||
doAssert d[i] * d[j] == d[i+j]
|
||||
if i - j >= 0:
|
||||
doAssert d[i] div d[j] == d[i-j]
|
||||
|
||||
var sum: Int128
|
||||
|
||||
for it in d:
|
||||
sum += it
|
||||
|
||||
doAssert $sum == "111111111111111111111111111111111111111"
|
||||
|
||||
for it in d.mitems:
|
||||
it = -it
|
||||
|
||||
for i in 0 ..< d.len:
|
||||
for j in 0 ..< d.len:
|
||||
doAssert(cmp(d[i], d[j]) == -cmp(i,j))
|
||||
if i + j < d.len:
|
||||
doAssert d[i] * d[j] == -d[i+j]
|
||||
if i - j >= 0:
|
||||
doAssert d[i] div d[j] == -d[i-j]
|
||||
|
||||
doAssert $high(Int128) == "170141183460469231731687303715884105727"
|
||||
doAssert $low(Int128) == "-170141183460469231731687303715884105728"
|
||||
@@ -29,11 +29,11 @@ implements the required case distinction.
|
||||
|
||||
|
||||
import
|
||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
|
||||
nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os, tables,
|
||||
times, ropes, math, passes, ccgutils, wordrecg, renderer,
|
||||
ast, strutils, trees, magicsys, options,
|
||||
nversion, msgs, idents, types, tables,
|
||||
ropes, math, passes, ccgutils, wordrecg, renderer,
|
||||
intsets, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
|
||||
pathutils, transf
|
||||
transf
|
||||
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
@@ -389,8 +389,6 @@ const # magic checked op; magic unchecked op;
|
||||
["", ""], # BitxorI
|
||||
["nimMin", "nimMin"], # MinI
|
||||
["nimMax", "nimMax"], # MaxI
|
||||
["nimMin", "nimMin"], # MinF64
|
||||
["nimMax", "nimMax"], # MaxF64
|
||||
["", ""], # addU
|
||||
["", ""], # subU
|
||||
["", ""], # mulU
|
||||
@@ -430,20 +428,6 @@ const # magic checked op; magic unchecked op;
|
||||
["", ""], # BitnotI
|
||||
["", ""], # UnaryPlusF64
|
||||
["", ""], # UnaryMinusF64
|
||||
["", ""], # AbsF64
|
||||
["Ze8ToI", "Ze8ToI"], # mZe8ToI
|
||||
["Ze8ToI64", "Ze8ToI64"], # mZe8ToI64
|
||||
["Ze16ToI", "Ze16ToI"], # mZe16ToI
|
||||
["Ze16ToI64", "Ze16ToI64"], # mZe16ToI64
|
||||
["Ze32ToI64", "Ze32ToI64"], # mZe32ToI64
|
||||
["ZeIToI64", "ZeIToI64"], # mZeIToI64
|
||||
["toU8", "toU8"], # toU8
|
||||
["toU16", "toU16"], # toU16
|
||||
["toU32", "toU32"], # toU32
|
||||
["", ""], # ToFloat
|
||||
["", ""], # ToBiggestFloat
|
||||
["", ""], # ToInt
|
||||
["", ""], # ToBiggestInt
|
||||
["nimCharToStr", "nimCharToStr"],
|
||||
["nimBoolToStr", "nimBoolToStr"],
|
||||
["cstrToNimstr", "cstrToNimstr"],
|
||||
@@ -491,7 +475,7 @@ template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
a, tmp = x.rdLoc
|
||||
b, tmp2 = y.rdLoc
|
||||
when "$3" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x)
|
||||
when "$4" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x)
|
||||
when "$4" in frmt: (b, tmp2) = maybeMakeTemp(p, n[2], y)
|
||||
|
||||
r.res = frmt % [a, b, tmp, tmp2]
|
||||
r.kind = resExpr
|
||||
@@ -544,7 +528,7 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||
xLoc,yLoc: Rope
|
||||
let i = ord(optOverflowCheck notin p.options)
|
||||
useMagic(p, jsMagics[op][i])
|
||||
if sonsLen(n) > 2:
|
||||
if len(n) > 2:
|
||||
gen(p, n.sons[1], x)
|
||||
gen(p, n.sons[2], y)
|
||||
xLoc = x.rdLoc
|
||||
@@ -579,23 +563,21 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||
of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)")
|
||||
of mMinI: applyFormat("nimMin($1, $2)", "nimMin($1, $2)")
|
||||
of mMaxI: applyFormat("nimMax($1, $2)", "nimMax($1, $2)")
|
||||
of mMinF64: applyFormat("nimMin($1, $2)", "nimMin($1, $2)")
|
||||
of mMaxF64: applyFormat("nimMax($1, $2)", "nimMax($1, $2)")
|
||||
of mAddU: applyFormat("", "")
|
||||
of msubU: applyFormat("", "")
|
||||
of mmulU: applyFormat("", "")
|
||||
of mdivU: applyFormat("", "")
|
||||
of mmodU: applyFormat("($1 % $2)", "($1 % $2)")
|
||||
of mSubU: applyFormat("", "")
|
||||
of mMulU: applyFormat("", "")
|
||||
of mDivU: applyFormat("", "")
|
||||
of mModU: applyFormat("($1 % $2)", "($1 % $2)")
|
||||
of mEqI: applyFormat("($1 == $2)", "($1 == $2)")
|
||||
of mLeI: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mLtI: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mEqF64: applyFormat("($1 == $2)", "($1 == $2)")
|
||||
of mLeF64: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mLtF64: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mleU: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mltU: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mleU64: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mltU64: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mLeU: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mLtU: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mLeU64: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mLtU64: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
of mEqEnum: applyFormat("($1 == $2)", "($1 == $2)")
|
||||
of mLeEnum: applyFormat("($1 <= $2)", "($1 <= $2)")
|
||||
of mLtEnum: applyFormat("($1 < $2)", "($1 < $2)")
|
||||
@@ -620,20 +602,6 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||
of mBitnotI: applyFormat("~($1)", "~($1)")
|
||||
of mUnaryPlusF64: applyFormat("+($1)", "+($1)")
|
||||
of mUnaryMinusF64: applyFormat("-($1)", "-($1)")
|
||||
of mAbsF64: applyFormat("Math.abs($1)", "Math.abs($1)")
|
||||
of mZe8ToI: applyFormat("Ze8ToI($1)", "Ze8ToI($1)")
|
||||
of mZe8ToI64: applyFormat("Ze8ToI64($1)", "Ze8ToI64($1)")
|
||||
of mZe16ToI: applyFormat("Ze16ToI($1)", "Ze16ToI($1)")
|
||||
of mZe16ToI64: applyFormat("Ze16ToI64($1)", "Ze16ToI64($1)")
|
||||
of mZe32ToI64: applyFormat("Ze32ToI64($1)", "Ze32ToI64($1)")
|
||||
of mZeIToI64: applyFormat("ZeIToI64($1)", "ZeIToI64($1)")
|
||||
of mtoU8: applyFormat("toU8($1)", "toU8($1)")
|
||||
of mtoU16: applyFormat("toU16($1)", "toU16($1)")
|
||||
of mtoU32: applyFormat("toU32($1)", "toU32($1)")
|
||||
of mToFloat: applyFormat("$1", "$1")
|
||||
of mToBiggestFloat: applyFormat("$1", "$1")
|
||||
of mToInt: applyFormat("Math.trunc($1)", "Math.trunc($1)")
|
||||
of mToBiggestInt: applyFormat("Math.trunc($1)", "Math.trunc($1)")
|
||||
of mCharToStr: applyFormat("nimCharToStr($1)", "nimCharToStr($1)")
|
||||
of mBoolToStr: applyFormat("nimBoolToStr($1)", "nimBoolToStr($1)")
|
||||
of mIntToStr: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")")
|
||||
@@ -684,11 +652,7 @@ proc genLineDir(p: PProc, n: PNode) =
|
||||
if optLineDir in p.options:
|
||||
lineF(p, "// line $2 \"$1\"$n",
|
||||
[rope(toFilename(p.config, n.info)), rope(line)])
|
||||
if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and
|
||||
((p.prc == nil) or sfPure notin p.prc.flags):
|
||||
useMagic(p, "endb")
|
||||
lineF(p, "endb($1);$n", [rope(line)])
|
||||
elif hasFrameInfo(p):
|
||||
if hasFrameInfo(p):
|
||||
lineF(p, "F.line = $1;$n", [rope(line)])
|
||||
|
||||
proc genWhileStmt(p: PProc, n: PNode) =
|
||||
@@ -749,7 +713,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.res = getTemp(p)
|
||||
inc(p.unique)
|
||||
var i = 1
|
||||
var length = sonsLen(n)
|
||||
var length = len(n)
|
||||
var catchBranchesExist = length > 1 and n.sons[i].kind == nkExceptBranch
|
||||
if catchBranchesExist:
|
||||
add(p.body, "++excHandler;\L")
|
||||
@@ -767,7 +731,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||
" lastJSError = EXC;$n --excHandler;$n", [])
|
||||
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
||||
while i < length and n.sons[i].kind == nkExceptBranch:
|
||||
let blen = sonsLen(n.sons[i])
|
||||
let blen = len(n.sons[i])
|
||||
if blen == 1:
|
||||
# general except section:
|
||||
generalCatchBranchExists = true
|
||||
@@ -858,11 +822,11 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if not isEmptyType(n.typ):
|
||||
r.kind = resVal
|
||||
r.res = getTemp(p)
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
let it = n.sons[i]
|
||||
case it.kind
|
||||
of nkOfBranch:
|
||||
for j in 0 .. sonsLen(it) - 2:
|
||||
for j in 0 .. len(it) - 2:
|
||||
let e = it.sons[j]
|
||||
if e.kind == nkRange:
|
||||
var v = copyNode(e.sons[0])
|
||||
@@ -930,7 +894,7 @@ proc genBreakStmt(p: PProc, n: PNode) =
|
||||
proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
||||
genLineDir(p, n)
|
||||
p.body.add p.indentLine(nil)
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
let it = n[i]
|
||||
case it.kind
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
@@ -968,9 +932,9 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if not isEmptyType(n.typ):
|
||||
r.kind = resVal
|
||||
r.res = getTemp(p)
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
let it = n.sons[i]
|
||||
if sonsLen(it) != 1:
|
||||
if len(it) != 1:
|
||||
if i > 0:
|
||||
lineF(p, "else {$n", [])
|
||||
inc(toClose)
|
||||
@@ -987,7 +951,7 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
||||
|
||||
proc generateHeader(p: PProc, typ: PType): Rope =
|
||||
result = nil
|
||||
for i in 1 ..< sonsLen(typ.n):
|
||||
for i in 1 ..< len(typ.n):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
var param = typ.n.sons[i].sym
|
||||
if isCompileTimeOnly(param.typ): continue
|
||||
@@ -1000,7 +964,7 @@ proc generateHeader(p: PProc, typ: PType): Rope =
|
||||
add(result, "_Idx")
|
||||
|
||||
proc countJsParams(typ: PType): int =
|
||||
for i in 1 ..< sonsLen(typ.n):
|
||||
for i in 1 ..< len(typ.n):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
var param = typ.n.sons[i].sym
|
||||
if isCompileTimeOnly(param.typ): continue
|
||||
@@ -1175,9 +1139,10 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
|
||||
|
||||
useMagic(p, "raiseFieldError")
|
||||
useMagic(p, "makeNimstrLit")
|
||||
let msg = genFieldError(field, disc)
|
||||
lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError(makeNimstrLit($5)); }$n",
|
||||
setx.res, tmp, disc.loc.r, if negCheck: ~"!==" else: ~"===",
|
||||
makeJSString(field.name.s))
|
||||
makeJSString(msg))
|
||||
|
||||
if addrTyp != nil and mapType(p, addrTyp) == etyBaseIndex:
|
||||
r.typ = etyBaseIndex
|
||||
@@ -1191,7 +1156,7 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
|
||||
proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var
|
||||
a, b: TCompRes
|
||||
first: BiggestInt
|
||||
first: Int128
|
||||
r.typ = etyBaseIndex
|
||||
let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
|
||||
gen(p, m.sons[0], a)
|
||||
@@ -1200,8 +1165,8 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
let (x, tmp) = maybeMakeTemp(p, m[0], a)
|
||||
r.address = x
|
||||
var typ = skipTypes(m.sons[0].typ, abstractPtrs)
|
||||
if typ.kind == tyArray: first = firstOrd(p.config, typ.sons[0])
|
||||
else: first = 0
|
||||
if typ.kind == tyArray:
|
||||
first = firstOrd(p.config, typ.sons[0])
|
||||
if optBoundsCheck in p.options:
|
||||
useMagic(p, "chckIndx")
|
||||
r.res = "chckIndx($1, $2, $3.length+$2-1)-$2" % [b.res, rope(first), tmp]
|
||||
@@ -1440,13 +1405,13 @@ proc genArgs(p: PProc, n: PNode, r: var TCompRes; start=1) =
|
||||
|
||||
var typ = skipTypes(n.sons[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
assert(len(typ) == len(typ.n))
|
||||
var emitted = start-1
|
||||
|
||||
for i in start ..< sonsLen(n):
|
||||
for i in start ..< len(n):
|
||||
let it = n.sons[i]
|
||||
var paramType: PNode = nil
|
||||
if i < sonsLen(typ):
|
||||
if i < len(typ):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
paramType = typ.n.sons[i]
|
||||
if paramType.typ.isCompileTimeOnly: continue
|
||||
@@ -1474,7 +1439,7 @@ proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType;
|
||||
" but got only: " & $(n.len-1))
|
||||
let it = n[i]
|
||||
var paramType: PNode = nil
|
||||
if i < sonsLen(typ):
|
||||
if i < len(typ):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
paramType = typ.n.sons[i]
|
||||
if paramType.typ.isCompileTimeOnly: return
|
||||
@@ -1562,7 +1527,7 @@ proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
||||
useMagic(p, "toJSStr") # Used in rawEcho
|
||||
useMagic(p, "rawEcho")
|
||||
add(r.res, "rawEcho(")
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
let it = n.sons[i]
|
||||
if it.typ.isCompileTimeOnly: continue
|
||||
if i > 0: add(r.res, ", ")
|
||||
@@ -1578,11 +1543,11 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope
|
||||
proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output: var Rope) =
|
||||
case rec.kind
|
||||
of nkRecList:
|
||||
for i in 0 ..< sonsLen(rec):
|
||||
for i in 0 ..< len(rec):
|
||||
createRecordVarAux(p, rec.sons[i], excludedFieldIDs, output)
|
||||
of nkRecCase:
|
||||
createRecordVarAux(p, rec.sons[0], excludedFieldIDs, output)
|
||||
for i in 1 ..< sonsLen(rec):
|
||||
for i in 1 ..< len(rec):
|
||||
createRecordVarAux(p, lastSon(rec.sons[i]), excludedFieldIDs, output)
|
||||
of nkSym:
|
||||
# Do not produce code for void types
|
||||
@@ -1609,9 +1574,9 @@ proc arrayTypeForElemType(typ: PType): string =
|
||||
of tyInt, tyInt32: "Int32Array"
|
||||
of tyInt16: "Int16Array"
|
||||
of tyInt8: "Int8Array"
|
||||
of tyUint, tyUint32: "Uint32Array"
|
||||
of tyUint16: "Uint16Array"
|
||||
of tyUint8: "Uint8Array"
|
||||
of tyUInt, tyUInt32: "Uint32Array"
|
||||
of tyUInt16: "Uint16Array"
|
||||
of tyUInt8: "Uint8Array"
|
||||
of tyFloat32: "Float32Array"
|
||||
of tyFloat64, tyFloat: "Float64Array"
|
||||
else: ""
|
||||
@@ -1629,8 +1594,10 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
result = putToSeq("{}", indirect)
|
||||
of tyBool:
|
||||
result = putToSeq("false", indirect)
|
||||
of tyNil:
|
||||
result = putToSeq("null", indirect)
|
||||
of tyArray:
|
||||
let length = int(lengthOrd(p.config, t))
|
||||
let length = toInt(lengthOrd(p.config, t))
|
||||
let e = elemType(t)
|
||||
let jsTyp = arrayTypeForElemType(e)
|
||||
if jsTyp.len > 0:
|
||||
@@ -1652,7 +1619,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
if indirect: result = "[$1]" % [result]
|
||||
of tyTuple:
|
||||
result = rope("{")
|
||||
for i in 0..<t.sonsLen:
|
||||
for i in 0..<t.len:
|
||||
if i > 0: add(result, ", ")
|
||||
addf(result, "Field$1: $2", [i.rope,
|
||||
createVar(p, t.sons[i], false)])
|
||||
@@ -1753,7 +1720,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||
lineF(p, "}$n")
|
||||
|
||||
proc genVarStmt(p: PProc, n: PNode) =
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
var a = n.sons[i]
|
||||
if a.kind != nkCommentStmt:
|
||||
if a.kind == nkVarTuple:
|
||||
@@ -1811,15 +1778,15 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
else:
|
||||
r.res.add("($1 || []).concat(" % [a.res])
|
||||
|
||||
for i in 2 .. sonsLen(n) - 2:
|
||||
for i in 2 .. len(n) - 2:
|
||||
gen(p, n.sons[i], a)
|
||||
if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar:
|
||||
r.res.add("[$1]," % [a.res])
|
||||
else:
|
||||
r.res.add("$1 || []," % [a.res])
|
||||
|
||||
gen(p, n.sons[sonsLen(n) - 1], a)
|
||||
if skipTypes(n.sons[sonsLen(n) - 1].typ, abstractVarRange).kind == tyChar:
|
||||
gen(p, n.sons[len(n) - 1], a)
|
||||
if skipTypes(n.sons[len(n) - 1].typ, abstractVarRange).kind == tyChar:
|
||||
r.res.add("[$1])" % [a.res])
|
||||
else:
|
||||
r.res.add("$1 || [])" % [a.res])
|
||||
@@ -2058,8 +2025,14 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of mParseBiggestFloat:
|
||||
useMagic(p, "nimParseBiggestFloat")
|
||||
genCall(p, n, r)
|
||||
of mArray:
|
||||
genCall(p, n, r)
|
||||
of mSlice:
|
||||
# arr.slice([begin[, end]]): 'end' is exclusive
|
||||
var x, y, z: TCompRes
|
||||
gen(p, n.sons[1], x)
|
||||
gen(p, n.sons[2], y)
|
||||
gen(p, n.sons[3], z)
|
||||
r.res = "($1.slice($2, $3+1))" % [x.rdLoc, y.rdLoc, z.rdLoc]
|
||||
r.kind = resExpr
|
||||
else:
|
||||
genCall(p, n, r)
|
||||
#else internalError(p.config, e.info, 'genMagic: ' + magicToStr[op]);
|
||||
@@ -2070,7 +2043,7 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
useMagic(p, "setConstr")
|
||||
r.res = rope("setConstr(")
|
||||
r.kind = resExpr
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if i > 0: add(r.res, ", ")
|
||||
var it = n.sons[i]
|
||||
if it.kind == nkRange:
|
||||
@@ -2092,7 +2065,7 @@ proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
r.res = rope("[")
|
||||
r.kind = resExpr
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if i > 0: add(r.res, ", ")
|
||||
gen(p, n.sons[i], a)
|
||||
if a.typ == etyBaseIndex:
|
||||
@@ -2109,7 +2082,7 @@ proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
r.res = rope("{")
|
||||
r.kind = resExpr
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if i > 0: add(r.res, ", ")
|
||||
var it = n.sons[i]
|
||||
if it.kind == nkExprColonExpr: it = it.sons[1]
|
||||
@@ -2129,7 +2102,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.kind = resExpr
|
||||
var initList : Rope
|
||||
var fieldIDs = initIntSet()
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
if i > 1: add(initList, ", ")
|
||||
var it = n.sons[i]
|
||||
internalAssert p.config, it.kind == nkExprColonExpr
|
||||
@@ -2264,7 +2237,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
if prc.typ.sons[0] != nil and sfPure notin prc.flags:
|
||||
resultSym = prc.ast.sons[resultPos].sym
|
||||
let mname = mangleName(p.module, resultSym)
|
||||
if not isindirect(resultSym) and
|
||||
if not isIndirect(resultSym) and
|
||||
resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and
|
||||
mapType(p, resultSym.typ) == etyBaseIndex:
|
||||
resultAsgn = p.indentLine(("var $# = null;$n") % [mname])
|
||||
@@ -2278,8 +2251,8 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
else:
|
||||
returnStmt = "return $#;$n" % [a.res]
|
||||
|
||||
let transformed_body = transformBody(oldProc.module.graph, prc, cache = false)
|
||||
p.nested: genStmt(p, transformed_body)
|
||||
let transformedBody = transformBody(oldProc.module.graph, prc, cache = false)
|
||||
p.nested: genStmt(p, transformedBody)
|
||||
|
||||
var def: Rope
|
||||
if not prc.constraint.isNil:
|
||||
@@ -2409,7 +2382,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
let f = n.floatVal
|
||||
case classify(f)
|
||||
of fcNaN:
|
||||
of fcNan:
|
||||
r.res = rope"NaN"
|
||||
of fcNegZero:
|
||||
r.res = rope"-0.0"
|
||||
@@ -2463,7 +2436,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
# this shows the distinction is nice for backends and should be kept
|
||||
# in the frontend
|
||||
let isExpr = not isEmptyType(n.typ)
|
||||
for i in 0 ..< sonsLen(n) - isExpr.ord:
|
||||
for i in 0 ..< len(n) - isExpr.ord:
|
||||
genStmt(p, n.sons[i])
|
||||
if isExpr:
|
||||
gen(p, lastSon(n), r)
|
||||
@@ -2559,7 +2532,7 @@ proc genModule(p: PProc, n: PNode) =
|
||||
add(p.body, frameCreate(p,
|
||||
makeJSString("module " & p.module.module.name.s),
|
||||
makeJSString(toFilename(p.config, p.module.module.info))))
|
||||
let n_transformed = transformStmt(p.module.graph, p.module.module, n)
|
||||
let transformedN = transformStmt(p.module.graph, p.module.module, n)
|
||||
if p.config.hcrOn and n.kind == nkStmtList:
|
||||
let moduleSym = p.module.module
|
||||
var moduleLoadedVar = rope(moduleSym.name.s) & "_loaded" &
|
||||
@@ -2567,7 +2540,7 @@ proc genModule(p: PProc, n: PNode) =
|
||||
lineF(p, "var $1;$n", [moduleLoadedVar])
|
||||
var inGuardedBlock = false
|
||||
|
||||
addHcrInitGuards(p, n_transformed, moduleLoadedVar, inGuardedBlock)
|
||||
addHcrInitGuards(p, transformedN, moduleLoadedVar, inGuardedBlock)
|
||||
|
||||
if inGuardedBlock:
|
||||
dec p.extraIndent
|
||||
@@ -2575,7 +2548,7 @@ proc genModule(p: PProc, n: PNode) =
|
||||
|
||||
lineF(p, "$1 = true;$n", [moduleLoadedVar])
|
||||
else:
|
||||
genStmt(p, n_transformed)
|
||||
genStmt(p, transformedN)
|
||||
|
||||
if optStackTrace in p.options:
|
||||
add(p.body, frameDestroy(p))
|
||||
@@ -2600,7 +2573,7 @@ proc wholeCode(graph: ModuleGraph; m: BModule): Rope =
|
||||
attachProc(p, prc)
|
||||
|
||||
var disp = generateMethodDispatchers(graph)
|
||||
for i in 0..sonsLen(disp)-1:
|
||||
for i in 0..len(disp)-1:
|
||||
let prc = disp.sons[i].sym
|
||||
if not globals.generatedSyms.containsOrIncl(prc.id):
|
||||
var p = newProc(globals, m, nil, m.module.options)
|
||||
|
||||
@@ -7,8 +7,12 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# included from jsgen.nim
|
||||
|
||||
## Type info generation for the JS backend.
|
||||
|
||||
proc rope(arg: Int128): Rope = rope($arg)
|
||||
|
||||
proc genTypeInfo(p: PProc, typ: PType): Rope
|
||||
proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
|
||||
var
|
||||
@@ -19,7 +23,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
|
||||
result = nil
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
length = sonsLen(n)
|
||||
length = len(n)
|
||||
if length == 1:
|
||||
result = genObjectFields(p, typ, n.sons[0])
|
||||
else:
|
||||
@@ -37,7 +41,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
|
||||
[mangleName(p.module, field), s,
|
||||
makeJSString(field.name.s)]
|
||||
of nkRecCase:
|
||||
length = sonsLen(n)
|
||||
length = len(n)
|
||||
if (n.sons[0].kind != nkSym): internalError(p.config, n.info, "genObjectFields")
|
||||
field = n.sons[0].sym
|
||||
s = genTypeInfo(p, field.typ)
|
||||
@@ -46,9 +50,9 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
|
||||
u = nil
|
||||
case b.kind
|
||||
of nkOfBranch:
|
||||
if sonsLen(b) < 2:
|
||||
if len(b) < 2:
|
||||
internalError(p.config, b.info, "genObjectFields; nkOfBranch broken")
|
||||
for j in 0 .. sonsLen(b) - 2:
|
||||
for j in 0 .. len(b) - 2:
|
||||
if u != nil: add(u, ", ")
|
||||
if b.sons[j].kind == nkRange:
|
||||
addf(u, "[$1, $2]", [rope(getOrdValue(b.sons[j].sons[0])),
|
||||
@@ -101,7 +105,7 @@ proc genTupleInfo(p: PProc, typ: PType, name: Rope) =
|
||||
addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
|
||||
|
||||
proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
|
||||
let length = sonsLen(typ.n)
|
||||
let length = len(typ.n)
|
||||
var s: Rope = nil
|
||||
for i in 0 ..< length:
|
||||
if (typ.n.sons[i].kind != nkSym): internalError(p.config, typ.n.info, "genEnumInfo")
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
# This file implements lambda lifting for the transformator.
|
||||
|
||||
import
|
||||
intsets, strutils, options, ast, astalgo, trees, treetab, msgs,
|
||||
intsets, strutils, options, ast, astalgo, msgs,
|
||||
idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos,
|
||||
transf
|
||||
transf, liftdestructors
|
||||
|
||||
discard """
|
||||
The basic approach is that captured vars need to be put on the heap and
|
||||
@@ -257,6 +257,8 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add newCall(getSysSym(g, n.info, "internalNew"), env)
|
||||
if optNimV2 in g.config.globalOptions:
|
||||
createTypeBoundOps(g, nil, env.typ, n.info)
|
||||
result.add makeClosure(g, iter, env, n.info)
|
||||
|
||||
proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode =
|
||||
@@ -324,6 +326,7 @@ proc asOwnedRef(c: DetectionPass; t: PType): PType =
|
||||
if optNimV2 in c.graph.config.globalOptions:
|
||||
assert t.kind == tyRef
|
||||
result = newType(tyOwned, t.owner)
|
||||
result.flags.incl tfHasOwned
|
||||
result.rawAddSon t
|
||||
else:
|
||||
result = t
|
||||
@@ -341,7 +344,7 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
|
||||
# with cycles properly, so it's better to produce a weak ref (=ptr) here.
|
||||
# This seems to be generally correct but since it's a bit risky it's only
|
||||
# enabled for gcDestructors.
|
||||
let fieldType = if c.graph.config.selectedGc == gcDestructors:
|
||||
let fieldType = if false: # c.graph.config.selectedGC == gcDestructors:
|
||||
c.getEnvTypeForOwnerUp(dep, info) #getHiddenParam(dep).typ
|
||||
else:
|
||||
c.getEnvTypeForOwner(dep, info)
|
||||
@@ -490,6 +493,7 @@ type
|
||||
processed: IntSet
|
||||
envVars: Table[int, PNode]
|
||||
inContainer: int
|
||||
unownedEnvVars: Table[int, PNode] # only required for --newruntime
|
||||
|
||||
proc initLiftingPass(fn: PSym): LiftingPass =
|
||||
result.processed = initIntSet()
|
||||
@@ -514,9 +518,9 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
localError(g.config, n.info, "internal error: environment misses: " & s.name.s)
|
||||
result = n
|
||||
|
||||
proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType): PNode =
|
||||
var v = newSym(skVar, getIdent(cache, envName), owner, owner.info)
|
||||
incl(v.flags, sfShadowed)
|
||||
proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo): PNode =
|
||||
var v = newSym(skVar, getIdent(cache, envName), owner, info)
|
||||
v.flags = {sfShadowed, sfGeneratedOp}
|
||||
v.typ = typ
|
||||
result = newSymNode(v)
|
||||
when false:
|
||||
@@ -528,16 +532,21 @@ proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType): PNode =
|
||||
result = newSymNode(v)
|
||||
|
||||
proc setupEnvVar(owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode =
|
||||
c: var LiftingPass; info: TLineInfo): PNode =
|
||||
if owner.isIterator:
|
||||
return getHiddenParam(d.graph, owner).newSymNode
|
||||
result = c.envvars.getOrDefault(owner.id)
|
||||
result = c.envVars.getOrDefault(owner.id)
|
||||
if result.isNil:
|
||||
let envVarType = d.ownerToType.getOrDefault(owner.id)
|
||||
if envVarType.isNil:
|
||||
localError d.graph.config, owner.info, "internal error: could not determine closure type"
|
||||
result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType))
|
||||
result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info)
|
||||
c.envVars[owner.id] = result
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), owner, info)
|
||||
v.flags = {sfShadowed, sfGeneratedOp}
|
||||
v.typ = envVarType
|
||||
c.unownedEnvVars[owner.id] = newSymNode(v)
|
||||
|
||||
proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode =
|
||||
let p = getHiddenParam(g, owner)
|
||||
@@ -550,20 +559,34 @@ proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode =
|
||||
result = rawIndirectAccess(result, upField, p.info)
|
||||
|
||||
proc rawClosureCreation(owner: PSym;
|
||||
d: DetectionPass; c: var LiftingPass): PNode =
|
||||
d: DetectionPass; c: var LiftingPass;
|
||||
info: TLineInfo): PNode =
|
||||
result = newNodeI(nkStmtList, owner.info)
|
||||
|
||||
var env: PNode
|
||||
if owner.isIterator:
|
||||
env = getHiddenParam(d.graph, owner).newSymNode
|
||||
else:
|
||||
env = setupEnvVar(owner, d, c)
|
||||
env = setupEnvVar(owner, d, c, info)
|
||||
if env.kind == nkSym:
|
||||
var v = newNodeI(nkVarSection, env.info)
|
||||
addVar(v, env)
|
||||
result.add(v)
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
let unowned = c.unownedEnvVars[owner.id]
|
||||
assert unowned != nil
|
||||
addVar(v, unowned)
|
||||
|
||||
# add 'new' statement:
|
||||
result.add(newCall(getSysSym(d.graph, env.info, "internalNew"), env))
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
let unowned = c.unownedEnvVars[owner.id]
|
||||
assert unowned != nil
|
||||
let env2 = copyTree(env)
|
||||
env2.typ = unowned.typ
|
||||
result.add newAsgnStmt(unowned, env2, env.info)
|
||||
createTypeBoundOps(d.graph, nil, unowned.typ, env.info)
|
||||
|
||||
# add assignment statements for captured parameters:
|
||||
for i in 1..<owner.typ.n.len:
|
||||
let local = owner.typ.n[i].sym
|
||||
@@ -583,6 +606,18 @@ proc rawClosureCreation(owner: PSym;
|
||||
# oldenv, env.info))
|
||||
else:
|
||||
localError(d.graph.config, env.info, "internal error: cannot create up reference")
|
||||
# we are not in the sem'check phase anymore! so pass 'nil' for the PContext
|
||||
# and hope for the best:
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
createTypeBoundOps(d.graph, nil, env.typ, owner.info)
|
||||
|
||||
proc finishClosureCreation(owner: PSym; d: DetectionPass; c: LiftingPass;
|
||||
info: TLineInfo; res: PNode) =
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
let unowned = c.unownedEnvVars[owner.id]
|
||||
assert unowned != nil
|
||||
let nilLit = newNodeIT(nkNilLit, info, unowned.typ)
|
||||
res.add newAsgnStmt(unowned, nilLit, info)
|
||||
|
||||
proc closureCreationForIter(iter: PNode;
|
||||
d: DetectionPass; c: var LiftingPass): PNode =
|
||||
@@ -602,10 +637,12 @@ proc closureCreationForIter(iter: PNode;
|
||||
addVar(vs, vnode)
|
||||
result.add(vs)
|
||||
result.add(newCall(getSysSym(d.graph, iter.info, "internalNew"), vnode))
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
createTypeBoundOps(d.graph, nil, vnode.typ, iter.info)
|
||||
|
||||
let upField = lookupInRecord(v.typ.skipTypes({tyOwned, tyRef}).n, getIdent(d.graph.cache, upName))
|
||||
if upField != nil:
|
||||
let u = setupEnvVar(owner, d, c)
|
||||
let u = setupEnvVar(owner, d, c, iter.info)
|
||||
if u.typ.skipTypes({tyOwned, tyRef}) == upField.typ.skipTypes({tyOwned, tyRef}):
|
||||
result.add(newAsgnStmt(rawIndirectAccess(vnode, upField, iter.info),
|
||||
u, iter.info))
|
||||
@@ -615,7 +652,9 @@ proc closureCreationForIter(iter: PNode;
|
||||
|
||||
proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode =
|
||||
let access = setupEnvVar(owner, d, c)
|
||||
var access = setupEnvVar(owner, d, c, n.info)
|
||||
if optNimV2 in d.graph.config.globalOptions:
|
||||
access = c.unownedEnvVars[owner.id]
|
||||
let obj = access.typ.skipTypes({tyOwned, tyRef})
|
||||
let field = getFieldFromObj(obj, n.sym)
|
||||
if field != nil:
|
||||
@@ -641,7 +680,7 @@ proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
|
||||
result = closureCreationForIter(n, d, c)
|
||||
elif s.skipGenericOwner == owner:
|
||||
# direct dependency, so use the outer's env variable:
|
||||
result = makeClosure(d.graph, s, setupEnvVar(owner, d, c), n.info)
|
||||
result = makeClosure(d.graph, s, setupEnvVar(owner, d, c, n.info), n.info)
|
||||
else:
|
||||
let available = getHiddenParam(d.graph, owner)
|
||||
let wanted = getHiddenParam(d.graph, s).typ
|
||||
@@ -671,10 +710,11 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c.inContainer = 0
|
||||
var body = transformBody(d.graph, s)
|
||||
body = liftCapturedVars(body, s, d, c)
|
||||
if c.envvars.getOrDefault(s.id).isNil:
|
||||
if c.envVars.getOrDefault(s.id).isNil:
|
||||
s.transformedBody = body
|
||||
else:
|
||||
s.transformedBody = newTree(nkStmtList, rawClosureCreation(s, d, c), body)
|
||||
s.transformedBody = newTree(nkStmtList, rawClosureCreation(s, d, c, n.info), body)
|
||||
finishClosureCreation(s, d, c, n.info, s.transformedBody)
|
||||
c.inContainer = oldInContainer
|
||||
|
||||
if s.typ.callConv == ccClosure:
|
||||
@@ -718,7 +758,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
# transform, let's not touch the LHS in order to make the lifting pass
|
||||
# correct when `result` is lifted
|
||||
n[0].sons[1] = liftCapturedVars(n[0].sons[1], owner, d, c)
|
||||
else: assert n[0].kind == nkEmpty
|
||||
else:
|
||||
n.sons[0] = liftCapturedVars(n[0], owner, d, c)
|
||||
else:
|
||||
if owner.isIterator:
|
||||
if nfLL in n.flags:
|
||||
@@ -810,8 +851,9 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
|
||||
var c = initLiftingPass(fn)
|
||||
result = liftCapturedVars(body, fn, d, c)
|
||||
# echo renderTree(result, {renderIds})
|
||||
if c.envvars.getOrDefault(fn.id) != nil:
|
||||
result = newTree(nkStmtList, rawClosureCreation(fn, d, c), result)
|
||||
if c.envVars.getOrDefault(fn.id) != nil:
|
||||
result = newTree(nkStmtList, rawClosureCreation(fn, d, c, body.info), result)
|
||||
finishClosureCreation(fn, d, c, body.info, result)
|
||||
else:
|
||||
result = body
|
||||
#if fn.name.s == "get2":
|
||||
@@ -879,6 +921,9 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add(newCall(getSysSym(g, env.info, "internalNew"), env.newSymNode))
|
||||
if optNimV2 in g.config.globalOptions:
|
||||
createTypeBoundOps(g, nil, env.typ, body.info)
|
||||
|
||||
elif op.kind == nkStmtListExpr:
|
||||
let closure = op.lastSon
|
||||
if closure.kind == nkClosure:
|
||||
@@ -888,7 +933,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
|
||||
|
||||
var loopBody = newNodeI(nkStmtList, body.info, 3)
|
||||
var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
|
||||
whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(g, body.info, tyBool))
|
||||
whileLoop.sons[0] = newIntTypeNode(1, getSysType(g, body.info, tyBool))
|
||||
whileLoop.sons[1] = loopBody
|
||||
result.add whileLoop
|
||||
|
||||
|
||||
@@ -9,13 +9,10 @@
|
||||
|
||||
## Layouter for nimpretty.
|
||||
|
||||
import idents, lexer, lineinfos, llstream, options, msgs, strutils,
|
||||
pathutils
|
||||
from os import changeFileExt
|
||||
from sequtils import delete
|
||||
import idents, lexer, lineinfos, llstream, options, msgs, strutils, pathutils
|
||||
|
||||
const
|
||||
MaxLineLen = 80
|
||||
MinLineLen = 15
|
||||
|
||||
type
|
||||
SplitKind = enum
|
||||
@@ -25,9 +22,14 @@ type
|
||||
detectSemicolonKind, useSemicolon, dontTouch
|
||||
|
||||
LayoutToken = enum
|
||||
ltSpaces, ltNewline, ltTab,
|
||||
ltSpaces,
|
||||
ltCrucialNewline, ## a semantically crucial newline (indentation!)
|
||||
ltSplittingNewline, ## newline used for splitting up long
|
||||
## expressions (like after a comma or a binary operator)
|
||||
ltTab,
|
||||
ltOptionalNewline, ## optional newline introduced by nimpretty
|
||||
ltComment, ltLit, ltKeyword, ltExportMarker, ltIdent,
|
||||
ltOther, ltOpr,
|
||||
ltOther, ltOpr, ltSomeParLe, ltSomeParRi,
|
||||
ltBeginSection, ltEndSection
|
||||
|
||||
Emitter* = object
|
||||
@@ -36,7 +38,7 @@ type
|
||||
lastTok: TTokType
|
||||
inquote, lastTokWasTerse: bool
|
||||
semicolons: SemicolonKind
|
||||
col, lastLineNumber, lineSpan, indentLevel, indWidth*: int
|
||||
col, lastLineNumber, lineSpan, indentLevel, indWidth*, inSection: int
|
||||
keepIndents*: int
|
||||
doIndentMore*: int
|
||||
kinds: seq[LayoutToken]
|
||||
@@ -44,10 +46,11 @@ type
|
||||
indentStack: seq[int]
|
||||
fixedUntil: int # marks where we must not go in the content
|
||||
altSplitPos: array[SplitKind, int] # alternative split positions
|
||||
maxLineLen*: int
|
||||
|
||||
proc openEmitter*(em: var Emitter, cache: IdentCache;
|
||||
config: ConfigRef, fileIdx: FileIndex) =
|
||||
let fullPath = Absolutefile config.toFullPath(fileIdx)
|
||||
let fullPath = AbsoluteFile config.toFullPath(fileIdx)
|
||||
if em.indWidth == 0:
|
||||
em.indWidth = getIndentWidth(fileIdx, llStreamOpen(fullPath, fmRead),
|
||||
cache, config)
|
||||
@@ -63,17 +66,20 @@ proc openEmitter*(em: var Emitter, cache: IdentCache;
|
||||
|
||||
proc computeMax(em: Emitter; pos: int): int =
|
||||
var p = pos
|
||||
var extraSpace = 0
|
||||
result = 0
|
||||
while p < em.tokens.len and em.kinds[p] != ltEndSection:
|
||||
var lhs = 0
|
||||
var lineLen = 0
|
||||
var foundTab = false
|
||||
while p < em.tokens.len and em.kinds[p] != ltEndSection:
|
||||
if em.kinds[p] == ltNewline:
|
||||
if foundTab and lineLen <= MaxLineLen: result = max(result, lhs)
|
||||
if em.kinds[p] in {ltCrucialNewline, ltSplittingNewline}:
|
||||
if foundTab and lineLen <= em.maxLineLen:
|
||||
result = max(result, lhs + extraSpace)
|
||||
inc p
|
||||
break
|
||||
if em.kinds[p] == ltTab:
|
||||
extraSpace = if em.kinds[p-1] == ltSpaces: 0 else: 1
|
||||
foundTab = true
|
||||
else:
|
||||
if not foundTab:
|
||||
@@ -84,46 +90,17 @@ proc computeMax(em: Emitter; pos: int): int =
|
||||
proc computeRhs(em: Emitter; pos: int): int =
|
||||
var p = pos
|
||||
result = 0
|
||||
while p < em.tokens.len and em.kinds[p] != ltNewline:
|
||||
while p < em.tokens.len and em.kinds[p] notin {ltCrucialNewline, ltSplittingNewline}:
|
||||
inc result, em.tokens[p].len
|
||||
inc p
|
||||
|
||||
proc closeEmitter*(em: var Emitter) =
|
||||
let outFile = em.config.absOutFile
|
||||
proc isLongEnough(lineLen, startPos, endPos: int): bool =
|
||||
result = lineLen > MinLineLen and endPos > startPos + 4
|
||||
|
||||
var content = newStringOfCap(16_000)
|
||||
var maxLhs = 0
|
||||
var lineLen = 0
|
||||
var lineBegin = 0
|
||||
for i in 0..em.tokens.high:
|
||||
case em.kinds[i]
|
||||
of ltBeginSection:
|
||||
maxLhs = computeMax(em, lineBegin)
|
||||
of ltEndSection:
|
||||
maxLhs = 0
|
||||
of ltTab:
|
||||
if maxLhs == 0 or computeRhs(em, i)+maxLhs > MaxLineLen:
|
||||
content.add ' '
|
||||
else:
|
||||
let spaces = max(maxLhs - lineLen + 1, 1)
|
||||
for j in 1..spaces: content.add ' '
|
||||
of ltNewline:
|
||||
content.add em.tokens[i]
|
||||
lineLen = 0
|
||||
lineBegin = i+1
|
||||
else:
|
||||
content.add em.tokens[i]
|
||||
inc lineLen, em.tokens[i].len
|
||||
|
||||
if fileExists(outFile) and readFile(outFile.string) == content:
|
||||
discard "do nothing, see #9499"
|
||||
return
|
||||
var f = llStreamOpen(outFile, fmWrite)
|
||||
if f == nil:
|
||||
rawMessage(em.config, errGenerated, "cannot open file: " & outFile.string)
|
||||
return
|
||||
f.llStreamWrite content
|
||||
llStreamClose(f)
|
||||
proc findNewline(em: Emitter; p, lineLen: var int) =
|
||||
while p < em.tokens.len and em.kinds[p] notin {ltCrucialNewline, ltSplittingNewline}:
|
||||
inc lineLen, em.tokens[p].len
|
||||
inc p
|
||||
|
||||
proc countNewlines(s: string): int =
|
||||
result = 0
|
||||
@@ -137,17 +114,169 @@ proc calcCol(em: var Emitter; s: string) =
|
||||
dec i
|
||||
inc em.col
|
||||
|
||||
proc optionalIsGood(em: var Emitter; pos, currentLen: int): bool =
|
||||
let ourIndent = em.tokens[pos].len
|
||||
var p = pos+1
|
||||
var lineLen = 0
|
||||
em.findNewline(p, lineLen)
|
||||
if p == pos+1: # optionalNewline followed by another newline
|
||||
result = false
|
||||
elif em.kinds[p-1] == ltComment and currentLen+lineLen < em.maxLineLen+MinLineLen:
|
||||
result = false
|
||||
elif p+1 < em.tokens.len and em.kinds[p+1] == ltSpaces and
|
||||
em.kinds[p-1] == ltOptionalNewline:
|
||||
if em.tokens[p+1].len == ourIndent:
|
||||
# concatenate lines with the same indententation
|
||||
var nlPos = p
|
||||
var lineLenTotal = lineLen
|
||||
inc p
|
||||
em.findNewline(p, lineLenTotal)
|
||||
if isLongEnough(lineLenTotal, nlPos, p):
|
||||
em.kinds[nlPos] = ltOptionalNewline
|
||||
if em.kinds[nlPos+1] == ltSpaces:
|
||||
# inhibit extra spaces when concatenating two lines
|
||||
em.tokens[nlPos+1] = if em.tokens[nlPos-2] == ",": " " else: ""
|
||||
result = true
|
||||
elif em.tokens[p+1].len < ourIndent:
|
||||
result = isLongEnough(lineLen, pos, p)
|
||||
elif em.kinds[pos+1] in {ltOther, ltSomeParLe, ltSomeParRi}: # note: pos+1, not p+1
|
||||
result = false
|
||||
else:
|
||||
result = isLongEnough(lineLen, pos, p)
|
||||
|
||||
proc lenOfNextTokens(em: Emitter; pos: int): int =
|
||||
result = 0
|
||||
for i in 1 ..< em.tokens.len-pos:
|
||||
if em.kinds[pos+i] in {ltCrucialNewline, ltSplittingNewline, ltOptionalNewline}: break
|
||||
inc result, em.tokens[pos+i].len
|
||||
|
||||
proc guidingInd(em: Emitter; pos: int): int =
|
||||
var i = pos - 1
|
||||
while i >= 0 and em.kinds[i] != ltSomeParLe:
|
||||
dec i
|
||||
while i+1 <= em.kinds.high and em.kinds[i] != ltSomeParRi:
|
||||
if em.kinds[i] == ltSplittingNewline and em.kinds[i+1] == ltSpaces:
|
||||
return em.tokens[i+1].len
|
||||
inc i
|
||||
result = -1
|
||||
|
||||
proc closeEmitter*(em: var Emitter) =
|
||||
template defaultCase() =
|
||||
content.add em.tokens[i]
|
||||
inc lineLen, em.tokens[i].len
|
||||
|
||||
let outFile = em.config.absOutFile
|
||||
|
||||
var content = newStringOfCap(16_000)
|
||||
var maxLhs = 0
|
||||
var lineLen = 0
|
||||
var lineBegin = 0
|
||||
var openPars = 0
|
||||
var i = 0
|
||||
while i <= em.tokens.high:
|
||||
when defined(debug):
|
||||
echo (token: em.tokens[i], kind: em.kinds[i])
|
||||
case em.kinds[i]
|
||||
of ltBeginSection:
|
||||
maxLhs = computeMax(em, lineBegin)
|
||||
of ltEndSection:
|
||||
maxLhs = 0
|
||||
lineBegin = i+1
|
||||
of ltTab:
|
||||
if i >= 2 and em.kinds[i-2] in {ltCrucialNewline, ltSplittingNewline} and
|
||||
em.kinds[i-1] in {ltCrucialNewline, ltSplittingNewline, ltSpaces}:
|
||||
# a previous section has ended
|
||||
maxLhs = 0
|
||||
|
||||
if maxLhs == 0:
|
||||
if em.kinds[i-1] != ltSpaces:
|
||||
content.add em.tokens[i]
|
||||
inc lineLen, em.tokens[i].len
|
||||
else:
|
||||
# pick the shorter indentation token:
|
||||
var spaces = maxLhs - lineLen
|
||||
if spaces < em.tokens[i].len or computeRhs(em, i+1)+maxLhs <= em.maxLineLen+MinLineLen:
|
||||
if spaces <= 0 and content[^1] notin {' ', '\L'}: spaces = 1
|
||||
for j in 1..spaces: content.add ' '
|
||||
inc lineLen, spaces
|
||||
else:
|
||||
content.add em.tokens[i]
|
||||
inc lineLen, em.tokens[i].len
|
||||
of ltCrucialNewline, ltSplittingNewline:
|
||||
content.add em.tokens[i]
|
||||
lineLen = 0
|
||||
lineBegin = i+1
|
||||
of ltOptionalNewline:
|
||||
let totalLineLen = lineLen + lenOfNextTokens(em, i)
|
||||
if totalLineLen > em.maxLineLen and optionalIsGood(em, i, lineLen):
|
||||
if i-1 >= 0 and em.kinds[i-1] == ltSpaces:
|
||||
let spaces = em.tokens[i-1].len
|
||||
content.setLen(content.len - spaces)
|
||||
content.add "\L"
|
||||
let guide = if openPars > 0: guidingInd(em, i) else: -1
|
||||
if guide >= 0:
|
||||
content.add repeat(' ', guide)
|
||||
lineLen = guide
|
||||
else:
|
||||
content.add em.tokens[i]
|
||||
lineLen = em.tokens[i].len
|
||||
lineBegin = i+1
|
||||
if i+1 < em.kinds.len and em.kinds[i+1] == ltSpaces:
|
||||
# inhibit extra spaces at the start of a new line
|
||||
inc i
|
||||
of ltLit:
|
||||
let lineSpan = countNewlines(em.tokens[i])
|
||||
if lineSpan > 0:
|
||||
em.calcCol(em.tokens[i])
|
||||
lineLen = em.col
|
||||
else:
|
||||
inc lineLen, em.tokens[i].len
|
||||
content.add em.tokens[i]
|
||||
of ltSomeParLe:
|
||||
inc openPars
|
||||
defaultCase()
|
||||
of ltSomeParRi:
|
||||
doAssert openPars > 0
|
||||
dec openPars
|
||||
defaultCase()
|
||||
else:
|
||||
defaultCase()
|
||||
inc i
|
||||
|
||||
if fileExists(outFile) and readFile(outFile.string) == content:
|
||||
discard "do nothing, see #9499"
|
||||
return
|
||||
var f = llStreamOpen(outFile, fmWrite)
|
||||
if f == nil:
|
||||
rawMessage(em.config, errGenerated, "cannot open file: " & outFile.string)
|
||||
return
|
||||
f.llStreamWrite content
|
||||
llStreamClose(f)
|
||||
|
||||
proc wr(em: var Emitter; x: string; lt: LayoutToken) =
|
||||
em.tokens.add x
|
||||
em.kinds.add lt
|
||||
inc em.col, x.len
|
||||
assert em.tokens.len == em.kinds.len
|
||||
|
||||
proc wrNewline(em: var Emitter) =
|
||||
proc wrNewline(em: var Emitter; kind = ltCrucialNewline) =
|
||||
em.tokens.add "\L"
|
||||
em.kinds.add ltNewline
|
||||
em.kinds.add kind
|
||||
em.col = 0
|
||||
|
||||
proc newlineWasSplitting*(em: var Emitter) =
|
||||
if em.kinds.len >= 3 and em.kinds[^3] == ltCrucialNewline:
|
||||
em.kinds[^3] = ltSplittingNewline
|
||||
|
||||
#[
|
||||
Splitting newlines can occur:
|
||||
- after commas, semicolon, '[', '('.
|
||||
- after binary operators, '='.
|
||||
- after ':' type
|
||||
|
||||
We only need parser support for the "after type" case.
|
||||
]#
|
||||
|
||||
proc wrSpaces(em: var Emitter; spaces: int) =
|
||||
if spaces > 0:
|
||||
wr(em, strutils.repeat(' ', spaces), ltSpaces)
|
||||
@@ -158,8 +287,19 @@ proc wrSpace(em: var Emitter) =
|
||||
proc wrTab(em: var Emitter) =
|
||||
wr(em, " ", ltTab)
|
||||
|
||||
proc beginSection*(em: var Emitter) = wr(em, "", ltBeginSection)
|
||||
proc endSection*(em: var Emitter) = wr(em, "", ltEndSection)
|
||||
proc beginSection*(em: var Emitter) =
|
||||
let pos = max(0, em.tokens.len-2)
|
||||
em.tokens.insert "", pos
|
||||
em.kinds.insert ltBeginSection, pos
|
||||
inc em.inSection
|
||||
|
||||
#wr(em, "", ltBeginSection)
|
||||
proc endSection*(em: var Emitter) =
|
||||
em.tokens.insert "", em.tokens.len-2
|
||||
em.kinds.insert ltEndSection, em.kinds.len-2
|
||||
dec em.inSection
|
||||
|
||||
#wr(em, "", ltEndSection)
|
||||
|
||||
proc removeSpaces(em: var Emitter) =
|
||||
while em.kinds.len > 0 and em.kinds[^1] == ltSpaces:
|
||||
@@ -168,87 +308,72 @@ proc removeSpaces(em: var Emitter) =
|
||||
setLen(em.kinds, em.kinds.len-1)
|
||||
dec em.col, tokenLen
|
||||
|
||||
template goodCol(col): bool = col in 40..MaxLineLen
|
||||
|
||||
const
|
||||
openPars = {tkParLe, tkParDotLe,
|
||||
tkBracketLe, tkBracketLeColon, tkCurlyDotLe,
|
||||
tkCurlyLe}
|
||||
tkBracketLe, tkBracketDotLe, tkBracketLeColon,
|
||||
tkCurlyDotLe, tkCurlyLe}
|
||||
closedPars = {tkParRi, tkParDotRi,
|
||||
tkBracketRi, tkCurlyDotRi,
|
||||
tkCurlyRi}
|
||||
tkBracketRi, tkBracketDotRi,
|
||||
tkCurlyDotRi, tkCurlyRi}
|
||||
|
||||
splitters = openPars + {tkComma, tkSemicolon}
|
||||
splitters = openPars + {tkComma, tkSemiColon} # do not add 'tkColon' here!
|
||||
oprSet = {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
|
||||
tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor}
|
||||
|
||||
template rememberSplit(kind) =
|
||||
if goodCol(em.col):
|
||||
em.altSplitPos[kind] = em.tokens.len
|
||||
template goodCol(col): bool = col >= em.maxLineLen div 2
|
||||
|
||||
template moreIndent(em): int =
|
||||
(if em.doIndentMore > 0: em.indWidth*2 else: em.indWidth)
|
||||
if em.doIndentMore > 0: em.indWidth*2 else: em.indWidth
|
||||
|
||||
proc softLinebreak(em: var Emitter, lit: string) =
|
||||
# XXX Use an algorithm that is outlined here:
|
||||
# https://llvm.org/devmtg/2013-04/jasper-slides.pdf
|
||||
# +2 because we blindly assume a comma or ' &' might follow
|
||||
if not em.inquote and em.col+lit.len+2 >= MaxLineLen:
|
||||
if em.lastTok in splitters:
|
||||
# bug #10295, check first if even more indentation would help:
|
||||
let spaces = em.indentLevel+moreIndent(em)
|
||||
if spaces < em.col:
|
||||
removeSpaces em
|
||||
wrNewline(em)
|
||||
em.col = 0
|
||||
wrSpaces em, spaces
|
||||
else:
|
||||
# search backwards for a good split position:
|
||||
for a in mitems(em.altSplitPos):
|
||||
if a > em.fixedUntil:
|
||||
var spaces = 0
|
||||
while a+spaces < em.kinds.len and em.kinds[a+spaces] == ltSpaces:
|
||||
inc spaces
|
||||
if spaces > 0:
|
||||
delete(em.tokens, a, a+spaces-1)
|
||||
delete(em.kinds, a, a+spaces-1)
|
||||
em.kinds.insert(ltNewline, a)
|
||||
em.tokens.insert("\L", a)
|
||||
em.kinds.insert(ltSpaces, a+1)
|
||||
em.tokens.insert(repeat(' ', em.indentLevel+moreIndent(em)), a+1)
|
||||
# recompute em.col:
|
||||
var i = em.kinds.len-1
|
||||
em.col = 0
|
||||
while i >= 0 and em.kinds[i] != ltNewline:
|
||||
inc em.col, em.tokens[i].len
|
||||
dec i
|
||||
# mark position as "already split here"
|
||||
a = -1
|
||||
break
|
||||
template rememberSplit(kind) =
|
||||
if goodCol(em.col) and not em.inquote:
|
||||
let spaces = em.indentLevel+moreIndent(em)
|
||||
if spaces < em.col and spaces > 0:
|
||||
wr(em, strutils.repeat(' ', spaces), ltOptionalNewline)
|
||||
#em.altSplitPos[kind] = em.tokens.len
|
||||
|
||||
proc emitMultilineComment(em: var Emitter, lit: string, col: int) =
|
||||
proc emitMultilineComment(em: var Emitter, lit: string, col: int; dontIndent: bool) =
|
||||
# re-align every line in the multi-line comment:
|
||||
var i = 0
|
||||
var lastIndent = em.indentStack[^1]
|
||||
var lastIndent = if em.keepIndents > 0: em.indentLevel else: em.indentStack[^1]
|
||||
var b = 0
|
||||
var dontIndent = dontIndent
|
||||
var hasEmptyLine = false
|
||||
for commentLine in splitLines(lit):
|
||||
let stripped = commentLine.strip()
|
||||
var a = 0
|
||||
while a < commentLine.len and commentLine[a] == ' ': inc a
|
||||
if i == 0:
|
||||
discard
|
||||
elif stripped.len == 0:
|
||||
wrNewline em
|
||||
if i == 0 and (commentLine.endsWith("\\") or commentLine.endsWith("[")):
|
||||
dontIndent = true
|
||||
wr em, commentLine, ltComment
|
||||
elif dontIndent:
|
||||
if i > 0: wrNewline em
|
||||
wr em, commentLine, ltComment
|
||||
else:
|
||||
if a > lastIndent:
|
||||
b += em.indWidth
|
||||
lastIndent = a
|
||||
elif a < lastIndent:
|
||||
b -= em.indWidth
|
||||
lastIndent = a
|
||||
wrNewline em
|
||||
wrSpaces em, col + b
|
||||
wr em, stripped, ltComment
|
||||
let stripped = commentLine.strip()
|
||||
if i == 0:
|
||||
if em.kinds.len > 0 and em.kinds[^1] != ltTab:
|
||||
wr(em, "", ltTab)
|
||||
elif stripped.len == 0:
|
||||
wrNewline em
|
||||
hasEmptyLine = true
|
||||
else:
|
||||
var a = 0
|
||||
while a < commentLine.len and commentLine[a] == ' ': inc a
|
||||
|
||||
if a > lastIndent:
|
||||
b += em.indWidth
|
||||
lastIndent = a
|
||||
elif a < lastIndent:
|
||||
b -= em.indWidth
|
||||
lastIndent = a
|
||||
wrNewline em
|
||||
if not hasEmptyLine or col + b < 15:
|
||||
if col + b > 0:
|
||||
wr(em, repeat(' ', col+b), ltTab)
|
||||
else:
|
||||
wr(em, "", ltTab)
|
||||
else:
|
||||
wr(em, repeat(' ', a), ltSpaces)
|
||||
wr em, stripped, ltComment
|
||||
inc i
|
||||
|
||||
proc lastChar(s: string): char =
|
||||
@@ -257,20 +382,20 @@ proc lastChar(s: string): char =
|
||||
proc endsInWhite(em: Emitter): bool =
|
||||
var i = em.tokens.len-1
|
||||
while i >= 0 and em.kinds[i] in {ltBeginSection, ltEndSection}: dec(i)
|
||||
result = if i >= 0: em.kinds[i] in {ltSpaces, ltNewline, ltTab} else: true
|
||||
result = if i >= 0: em.kinds[i] in {ltSpaces, ltCrucialNewline, ltSplittingNewline, ltTab} else: true
|
||||
|
||||
proc endsInNewline(em: Emitter): bool =
|
||||
var i = em.tokens.len-1
|
||||
while i >= 0 and em.kinds[i] in {ltBeginSection, ltEndSection, ltSpaces}: dec(i)
|
||||
result = if i >= 0: em.kinds[i] in {ltNewline, ltTab} else: true
|
||||
result = if i >= 0: em.kinds[i] in {ltCrucialNewline, ltSplittingNewline, ltTab} else: true
|
||||
|
||||
proc endsInAlpha(em: Emitter): bool =
|
||||
var i = em.tokens.len-1
|
||||
while i >= 0 and em.kinds[i] in {ltBeginSection, ltEndSection}: dec(i)
|
||||
result = if i >= 0: em.tokens[i].lastChar in SymChars+{'_'} else: false
|
||||
|
||||
proc emitComment(em: var Emitter; tok: TToken) =
|
||||
let col = em.col
|
||||
proc emitComment(em: var Emitter; tok: TToken; dontIndent: bool) =
|
||||
var col = em.col
|
||||
let lit = strip fileSection(em.config, em.fid, tok.commentOffsetA, tok.commentOffsetB)
|
||||
em.lineSpan = countNewlines(lit)
|
||||
if em.lineSpan > 0: calcCol(em, lit)
|
||||
@@ -281,7 +406,8 @@ proc emitComment(em: var Emitter; tok: TToken) =
|
||||
else:
|
||||
if not endsInWhite(em):
|
||||
wrTab em
|
||||
emitMultilineComment(em, lit, col)
|
||||
inc col
|
||||
emitMultilineComment(em, lit, col, dontIndent)
|
||||
|
||||
proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
|
||||
template wasExportMarker(em): bool =
|
||||
@@ -303,19 +429,25 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
|
||||
return
|
||||
|
||||
var preventComment = false
|
||||
if tok.tokType == tkComment and tok.line == em.lastLineNumber and tok.indent >= 0:
|
||||
if tok.tokType == tkComment and tok.line == em.lastLineNumber:
|
||||
# we have an inline comment so handle it before the indentation token:
|
||||
emitComment(em, tok)
|
||||
emitComment(em, tok, dontIndent = (em.inSection == 0))
|
||||
preventComment = true
|
||||
em.fixedUntil = em.tokens.high
|
||||
|
||||
elif tok.indent >= 0:
|
||||
var newlineKind = ltCrucialNewline
|
||||
if em.keepIndents > 0:
|
||||
em.indentLevel = tok.indent
|
||||
elif (em.lastTok in (splitters + oprSet) and tok.tokType notin closedPars):
|
||||
elif (em.lastTok in (splitters + oprSet) and
|
||||
tok.tokType notin (closedPars - {tkBracketDotRi})):
|
||||
if tok.tokType in openPars and tok.indent > em.indentStack[^1]:
|
||||
while em.indentStack[^1] < tok.indent:
|
||||
em.indentStack.add(em.indentStack[^1] + em.indWidth)
|
||||
# aka: we are in an expression context:
|
||||
let alignment = tok.indent - em.indentStack[^1]
|
||||
let alignment = max(tok.indent - em.indentStack[^1], 0)
|
||||
em.indentLevel = alignment + em.indentStack.high * em.indWidth
|
||||
newlineKind = ltSplittingNewline
|
||||
else:
|
||||
if tok.indent > em.indentStack[^1]:
|
||||
em.indentStack.add tok.indent
|
||||
@@ -335,7 +467,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
|
||||
]#
|
||||
# remove trailing whitespace:
|
||||
removeSpaces em
|
||||
wrNewline em
|
||||
wrNewline em, newlineKind
|
||||
for i in 2..tok.line - em.lastLineNumber: wrNewline(em)
|
||||
wrSpaces em, em.indentLevel
|
||||
em.fixedUntil = em.tokens.high
|
||||
@@ -346,20 +478,15 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
|
||||
if endsInAlpha(em):
|
||||
wrSpace em
|
||||
elif not em.inquote and not endsInWhite(em) and
|
||||
em.lastTok notin openPars and not em.lastTokWasTerse:
|
||||
em.lastTok notin (openPars+{tkOpr, tkDotDot}) and not em.lastTokWasTerse:
|
||||
#and tok.tokType in oprSet
|
||||
wrSpace em
|
||||
|
||||
if not em.inquote:
|
||||
wr(em, TokTypeToStr[tok.tokType], ltKeyword)
|
||||
|
||||
case tok.tokType
|
||||
of tkAnd: rememberSplit(splitAnd)
|
||||
of tkOr: rememberSplit(splitOr)
|
||||
of tkIn, tkNotin:
|
||||
if tok.tokType in {tkAnd, tkOr, tkIn, tkNotin}:
|
||||
rememberSplit(splitIn)
|
||||
wrSpace em
|
||||
else: discard
|
||||
else:
|
||||
# keywords in backticks are not normalized:
|
||||
wr(em, tok.ident.s, ltIdent)
|
||||
@@ -367,22 +494,18 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
|
||||
of tkColon:
|
||||
wr(em, TokTypeToStr[tok.tokType], ltOther)
|
||||
wrSpace em
|
||||
of tkSemicolon, tkComma:
|
||||
of tkSemiColon, tkComma:
|
||||
wr(em, TokTypeToStr[tok.tokType], ltOther)
|
||||
rememberSplit(splitComma)
|
||||
wrSpace em
|
||||
of tkParDotLe, tkParLe, tkBracketDotLe, tkBracketLe,
|
||||
tkCurlyLe, tkCurlyDotLe, tkBracketLeColon:
|
||||
of openPars:
|
||||
if tok.strongSpaceA > 0 and not em.endsInWhite and not em.wasExportMarker:
|
||||
wrSpace em
|
||||
wr(em, TokTypeToStr[tok.tokType], ltOther)
|
||||
wr(em, TokTypeToStr[tok.tokType], ltSomeParLe)
|
||||
rememberSplit(splitParLe)
|
||||
of tkParRi,
|
||||
tkBracketRi, tkCurlyRi,
|
||||
tkBracketDotRi,
|
||||
tkCurlyDotRi,
|
||||
tkParDotRi,
|
||||
tkColonColon:
|
||||
of closedPars:
|
||||
wr(em, TokTypeToStr[tok.tokType], ltSomeParRi)
|
||||
of tkColonColon:
|
||||
wr(em, TokTypeToStr[tok.tokType], ltOther)
|
||||
of tkDot:
|
||||
lastTokWasTerse = true
|
||||
@@ -392,8 +515,8 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
|
||||
wr(em, TokTypeToStr[tok.tokType], ltOther)
|
||||
if not em.inquote: wrSpace(em)
|
||||
of tkOpr, tkDotDot:
|
||||
if ((tok.strongSpaceA == 0 and tok.strongSpaceB == 0) or em.inquote) and
|
||||
tok.ident.s notin ["<", ">", "<=", ">=", "==", "!="]:
|
||||
if em.inquote or ((tok.strongSpaceA == 0 and tok.strongSpaceB == 0) and
|
||||
tok.ident.s notin ["<", ">", "<=", ">=", "==", "!="]):
|
||||
# bug #9504: remember to not spacify a keyword:
|
||||
lastTokWasTerse = true
|
||||
# if not surrounded by whitespace, don't produce any whitespace either:
|
||||
@@ -413,10 +536,9 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
|
||||
em.inquote = not em.inquote
|
||||
of tkComment:
|
||||
if not preventComment:
|
||||
emitComment(em, tok)
|
||||
emitComment(em, tok, dontIndent = false)
|
||||
of tkIntLit..tkStrLit, tkRStrLit, tkTripleStrLit, tkGStrLit, tkGTripleStrLit, tkCharLit:
|
||||
let lit = fileSection(em.config, em.fid, tok.offsetA, tok.offsetB)
|
||||
softLinebreak(em, lit)
|
||||
if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wrSpace(em)
|
||||
em.lineSpan = countNewlines(lit)
|
||||
if em.lineSpan > 0: calcCol(em, lit)
|
||||
@@ -424,7 +546,6 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
|
||||
of tkEof: discard
|
||||
else:
|
||||
let lit = if tok.ident != nil: tok.ident.s else: tok.literal
|
||||
softLinebreak(em, lit)
|
||||
if endsInAlpha(em): wrSpace(em)
|
||||
wr em, lit, ltIdent
|
||||
|
||||
@@ -439,6 +560,11 @@ proc endsWith(em: Emitter; k: varargs[string]): bool =
|
||||
if em.tokens[em.tokens.len - k.len + i] != k[i]: return false
|
||||
return true
|
||||
|
||||
proc rfind(em: Emitter, t: string): int =
|
||||
for i in 1 .. 5:
|
||||
if em.tokens[^i] == t:
|
||||
return i
|
||||
|
||||
proc starWasExportMarker*(em: var Emitter) =
|
||||
if em.endsWith(" ", "*", " "):
|
||||
setLen(em.tokens, em.tokens.len-3)
|
||||
@@ -449,11 +575,13 @@ proc starWasExportMarker*(em: var Emitter) =
|
||||
|
||||
proc commaWasSemicolon*(em: var Emitter) =
|
||||
if em.semicolons == detectSemicolonKind:
|
||||
em.semicolons = if em.endsWith(",", " "): dontTouch else: useSemicolon
|
||||
if em.semicolons == useSemicolon and em.endsWith(",", " "):
|
||||
em.tokens[em.tokens.len-2] = ";"
|
||||
em.semicolons = if em.rfind(";") > 0: useSemicolon else: dontTouch
|
||||
if em.semicolons == useSemicolon:
|
||||
let commaPos = em.rfind(",")
|
||||
if commaPos > 0:
|
||||
em.tokens[^commaPos] = ";"
|
||||
|
||||
proc curlyRiWasPragma*(em: var Emitter) =
|
||||
if em.endsWith("}"):
|
||||
em.tokens[em.tokens.len-1] = ".}"
|
||||
em.tokens[^1] = ".}"
|
||||
inc em.col
|
||||
|
||||
@@ -146,10 +146,6 @@ type
|
||||
previousToken: TLineInfo
|
||||
config*: ConfigRef
|
||||
|
||||
when defined(nimpretty):
|
||||
var
|
||||
gIndentationWidth*: int
|
||||
|
||||
proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
|
||||
result = newLineInfo(L.fileIdx, tok.line, tok.col)
|
||||
when defined(nimpretty):
|
||||
@@ -173,7 +169,7 @@ proc isNimIdentifier*(s: string): bool =
|
||||
inc(i)
|
||||
result = true
|
||||
|
||||
proc tokToStr*(tok: TToken): string =
|
||||
proc `$`*(tok: TToken): string =
|
||||
case tok.tokType
|
||||
of tkIntLit..tkInt64Lit: result = $tok.iNumber
|
||||
of tkFloatLit..tkFloat64Lit: result = $tok.fNumber
|
||||
@@ -188,11 +184,11 @@ proc tokToStr*(tok: TToken): string =
|
||||
|
||||
proc prettyTok*(tok: TToken): string =
|
||||
if isKeyword(tok.tokType): result = "keyword " & tok.ident.s
|
||||
else: result = tokToStr(tok)
|
||||
else: result = $tok
|
||||
|
||||
proc printTok*(conf: ConfigRef; tok: TToken) =
|
||||
msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" &
|
||||
TokTypeToStr[tok.tokType] & " " & tokToStr(tok))
|
||||
TokTypeToStr[tok.tokType] & " " & $tok)
|
||||
|
||||
proc initToken*(L: var TToken) =
|
||||
L.tokType = tkInvalid
|
||||
@@ -223,7 +219,7 @@ proc fillToken(L: var TToken) =
|
||||
proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream;
|
||||
cache: IdentCache; config: ConfigRef) =
|
||||
openBaseLexer(lex, inputstream)
|
||||
lex.fileIdx = fileidx
|
||||
lex.fileIdx = fileIdx
|
||||
lex.indentAhead = -1
|
||||
lex.currLineIndent = 0
|
||||
inc(lex.lineNumber, inputstream.lineOffset)
|
||||
@@ -379,7 +375,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||
result.literal = ""
|
||||
result.base = base10
|
||||
startpos = L.bufpos
|
||||
tokenBegin(result, startPos)
|
||||
tokenBegin(result, startpos)
|
||||
|
||||
# First stage: find out base, make verifications, build token literal string
|
||||
# {'c', 'C'} is added for deprecation reasons to provide a clear error message
|
||||
@@ -534,13 +530,13 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||
|
||||
case result.tokType
|
||||
of tkIntLit, tkInt64Lit: result.iNumber = xi
|
||||
of tkInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
|
||||
of tkInt16Lit: result.iNumber = BiggestInt(int16(toU16(int(xi))))
|
||||
of tkInt32Lit: result.iNumber = BiggestInt(int32(toU32(int64(xi))))
|
||||
of tkInt8Lit: result.iNumber = ashr(xi shl 56, 56)
|
||||
of tkInt16Lit: result.iNumber = ashr(xi shl 48, 48)
|
||||
of tkInt32Lit: result.iNumber = ashr(xi shl 32, 32)
|
||||
of tkUIntLit, tkUInt64Lit: result.iNumber = xi
|
||||
of tkUInt8Lit: result.iNumber = BiggestInt(cast[uint8](toU8(int(xi))))
|
||||
of tkUInt16Lit: result.iNumber = BiggestInt(cast[uint16](toU16(int(xi))))
|
||||
of tkUInt32Lit: result.iNumber = BiggestInt(cast[uint32](toU32(int64(xi))))
|
||||
of tkUInt8Lit: result.iNumber = xi and 0xff
|
||||
of tkUInt16Lit: result.iNumber = xi and 0xffff
|
||||
of tkUInt32Lit: result.iNumber = xi and 0xffffffff
|
||||
of tkFloat32Lit:
|
||||
result.fNumber = (cast[PFloat32](addr(xi)))[]
|
||||
# note: this code is endian neutral!
|
||||
@@ -569,7 +565,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||
case result.tokType
|
||||
of floatTypes:
|
||||
result.fNumber = parseFloat(result.literal)
|
||||
of tkUint64Lit:
|
||||
of tkUInt64Lit, tkUIntLit:
|
||||
var iNumber: uint64
|
||||
var len: int
|
||||
try:
|
||||
@@ -868,7 +864,9 @@ proc getCharacter(L: var TLexer, tok: var TToken) =
|
||||
inc(L.bufpos) # skip '
|
||||
var c = L.buf[L.bufpos]
|
||||
case c
|
||||
of '\0'..pred(' '), '\'': lexMessage(L, errGenerated, "invalid character literal")
|
||||
of '\0'..pred(' '), '\'':
|
||||
lexMessage(L, errGenerated, "invalid character literal")
|
||||
tok.literal = $c
|
||||
of '\\': getEscapedChar(L, tok)
|
||||
else:
|
||||
tok.literal = $c
|
||||
@@ -882,6 +880,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
|
||||
var h: Hash = 0
|
||||
var pos = L.bufpos
|
||||
tokenBegin(tok, pos)
|
||||
var suspicious = false
|
||||
while true:
|
||||
var c = L.buf[pos]
|
||||
case c
|
||||
@@ -892,21 +891,26 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
|
||||
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
|
||||
h = h !& ord(c)
|
||||
inc(pos)
|
||||
suspicious = true
|
||||
of '_':
|
||||
if L.buf[pos+1] notin SymChars:
|
||||
lexMessage(L, errGenerated, "invalid token: trailing underscore")
|
||||
break
|
||||
inc(pos)
|
||||
suspicious = true
|
||||
else: break
|
||||
tokenEnd(tok, pos-1)
|
||||
h = !$h
|
||||
tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
|
||||
L.bufpos = pos
|
||||
if (tok.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
|
||||
(tok.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
|
||||
tok.tokType = tkSymbol
|
||||
else:
|
||||
tok.tokType = TTokType(tok.ident.id + ord(tkSymbol))
|
||||
if suspicious and {optStyleHint, optStyleError} * L.config.globalOptions != {}:
|
||||
lintReport(L.config, getLineInfo(L), tok.ident.s.normalize, tok.ident.s)
|
||||
L.bufpos = pos
|
||||
|
||||
|
||||
proc endOperator(L: var TLexer, tok: var TToken, pos: int,
|
||||
hash: Hash) {.inline.} =
|
||||
@@ -1119,7 +1123,7 @@ proc skip(L: var TLexer, tok: var TToken) =
|
||||
inc(pos)
|
||||
inc(tok.strongSpaceA)
|
||||
of '\t':
|
||||
if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabulators are not allowed")
|
||||
if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead")
|
||||
inc(pos)
|
||||
of CR, LF:
|
||||
tokenEndPrevious(tok, pos)
|
||||
@@ -1174,8 +1178,6 @@ proc skip(L: var TLexer, tok: var TToken) =
|
||||
tok.commentOffsetB = L.offsetBase + pos - 1
|
||||
tok.tokType = tkComment
|
||||
tok.indent = commentIndent
|
||||
if gIndentationWidth <= 0:
|
||||
gIndentationWidth = tok.indent
|
||||
|
||||
proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
||||
template atTokenEnd() {.dirty.} =
|
||||
@@ -1334,10 +1336,13 @@ proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
|
||||
var tok: TToken
|
||||
initToken(tok)
|
||||
openLexer(lex, fileIdx, inputstream, cache, config)
|
||||
while true:
|
||||
var prevToken = tkEof
|
||||
while tok.tokType != tkEof:
|
||||
rawGetTok(lex, tok)
|
||||
result = tok.indent
|
||||
if result > 0 or tok.tokType == tkEof: break
|
||||
if tok.indent > 0 and prevToken in {tkColon, tkEquals, tkType, tkConst, tkLet, tkVar, tkUsing}:
|
||||
result = tok.indent
|
||||
if result > 0: break
|
||||
prevToken = tok.tokType
|
||||
closeLexer(lex)
|
||||
|
||||
proc getPrecedence*(ident: PIdent): int =
|
||||
|
||||
@@ -10,28 +10,27 @@
|
||||
## This module implements lifting for type-bound operations
|
||||
## (``=sink``, ``=``, ``=destroy``, ``=deepCopy``).
|
||||
|
||||
# included from sempass2.nim
|
||||
|
||||
# Todo:
|
||||
# - use openArray instead of array to avoid over-specializations
|
||||
|
||||
import sighashes
|
||||
import modulegraphs, lineinfos, idents, ast, renderer, semdata,
|
||||
sighashes, lowerings, options, types, msgs, magicsys, tables
|
||||
|
||||
type
|
||||
TLiftCtx = object
|
||||
graph: ModuleGraph
|
||||
g: ModuleGraph
|
||||
info: TLineInfo # for construction
|
||||
kind: TTypeAttachedOp
|
||||
fn: PSym
|
||||
asgnForType: PType
|
||||
recurse: bool
|
||||
c: PContext
|
||||
c: PContext # c can be nil, then we are called from lambdalifting!
|
||||
|
||||
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode)
|
||||
proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
info: TLineInfo): PSym
|
||||
|
||||
proc createTypeBoundOps*(c: PContext; orig: PType; info: TLineInfo)
|
||||
proc createTypeBoundOps*(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo)
|
||||
|
||||
proc at(a, i: PNode, elemType: PType): PNode =
|
||||
result = newNodeI(nkBracketExpr, a.info, 2)
|
||||
@@ -41,7 +40,7 @@ proc at(a, i: PNode, elemType: PType): PNode =
|
||||
|
||||
proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
for i in 0 ..< t.len:
|
||||
let lit = lowerings.newIntLit(c.graph, x.info, i)
|
||||
let lit = lowerings.newIntLit(c.g, x.info, i)
|
||||
fillBody(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i]))
|
||||
|
||||
proc dotField(x: PNode, f: PSym): PNode =
|
||||
@@ -88,7 +87,12 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
|
||||
of nkRecList:
|
||||
for t in items(n): fillBodyObj(c, t, body, x, y)
|
||||
else:
|
||||
illFormedAstLocal(n, c.graph.config)
|
||||
illFormedAstLocal(n, c.g.config)
|
||||
|
||||
proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
|
||||
if t.len > 0 and t.sons[0] != nil:
|
||||
fillBodyObjT(c, skipTypes(t.sons[0], abstractPtrs), body, x, y)
|
||||
fillBodyObj(c, t.n, body, x, y)
|
||||
|
||||
proc genAddr(g: ModuleGraph; x: PNode): PNode =
|
||||
if x.kind == nkHiddenDeref:
|
||||
@@ -125,20 +129,28 @@ proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
|
||||
result = newAsgnStmt(x, newOpCall(op, y))
|
||||
|
||||
proc useNoGc(c: TLiftCtx; t: PType): bool {.inline.} =
|
||||
result = optNimV2 in c.graph.config.globalOptions and
|
||||
result = c.g.config.selectedGC == gcDestructors and
|
||||
({tfHasGCedMem, tfHasOwned} * t.flags != {} or t.isGCedMem)
|
||||
|
||||
proc instantiateGeneric(c: var TLiftCtx; op: PSym; t, typeInst: PType): PSym =
|
||||
if c.c != nil and typeInst != nil:
|
||||
result = c.c.instTypeBoundOp(c.c, op, typeInst, c.info, attachedAsgn, 1)
|
||||
else:
|
||||
localError(c.g.config, c.info,
|
||||
"cannot generate destructor for generic type: " & typeToString(t))
|
||||
result = nil
|
||||
|
||||
proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
field: var PSym): bool =
|
||||
if optNimV2 in c.graph.config.globalOptions:
|
||||
if c.g.config.selectedGC == gcDestructors:
|
||||
let op = field
|
||||
if field != nil and sfOverriden in field.flags:
|
||||
if sfError in op.flags:
|
||||
incl c.fn.flags, sfError
|
||||
else:
|
||||
markUsed(c.graph.config, c.info, op, c.graph.usageSym)
|
||||
#else:
|
||||
# markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op)
|
||||
body.add newAsgnCall(c.graph, op, x, y)
|
||||
body.add newAsgnCall(c.g, op, x, y)
|
||||
result = true
|
||||
elif tfHasAsgn in t.flags:
|
||||
var op: PSym
|
||||
@@ -152,38 +164,45 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
else:
|
||||
op = field
|
||||
if op == nil:
|
||||
op = produceSym(c.c, t, c.kind, c.info)
|
||||
op = produceSym(c.g, c.c, t, c.kind, c.info)
|
||||
if sfError in op.flags:
|
||||
incl c.fn.flags, sfError
|
||||
else:
|
||||
markUsed(c.graph.config, c.info, op, c.graph.usageSym)
|
||||
#else:
|
||||
# markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op)
|
||||
# We also now do generic instantiations in the destructor lifting pass:
|
||||
if op.ast[genericParamsPos].kind != nkEmpty:
|
||||
assert t.typeInst != nil
|
||||
op = c.c.instTypeBoundOp(c.c, op, t.typeInst, c.info, attachedAsgn, 1)
|
||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||
field = op
|
||||
#echo "trying to use ", op.ast
|
||||
#echo "for ", op.name.s, " "
|
||||
#debug(t)
|
||||
#return false
|
||||
assert op.ast[genericParamsPos].kind == nkEmpty
|
||||
body.add newAsgnCall(c.graph, op, x, y)
|
||||
body.add newAsgnCall(c.g, op, x, y)
|
||||
result = true
|
||||
|
||||
proc addDestructorCall(c: var TLiftCtx; t: PType; body, x: PNode) =
|
||||
proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
|
||||
let t = orig.skipTypes(abstractInst)
|
||||
var op = t.destructor
|
||||
|
||||
if op != nil and sfOverriden in op.flags:
|
||||
if op.ast[genericParamsPos].kind != nkEmpty:
|
||||
# patch generic destructor:
|
||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||
t.attachedOps[attachedDestructor] = op
|
||||
|
||||
if op == nil and useNoGc(c, t):
|
||||
op = produceSym(c.c, t, attachedDestructor, c.info)
|
||||
op = produceSym(c.g, c.c, t, attachedDestructor, c.info)
|
||||
doAssert op != nil
|
||||
doAssert op == t.destructor
|
||||
|
||||
if op != nil:
|
||||
markUsed(c.graph.config, c.info, op, c.graph.usageSym)
|
||||
#markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op)
|
||||
body.add destructorCall(c.graph, op, x)
|
||||
body.add destructorCall(c.g, op, x)
|
||||
elif useNoGc(c, t):
|
||||
internalError(c.graph.config, c.info,
|
||||
internalError(c.g.config, c.info,
|
||||
"type-bound operator could not be resolved")
|
||||
|
||||
proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
@@ -193,14 +212,13 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
if op != nil and sfOverriden in op.flags:
|
||||
|
||||
if op.ast[genericParamsPos].kind != nkEmpty:
|
||||
assert t.typeInst != nil
|
||||
# patch generic destructor:
|
||||
op = c.c.instTypeBoundOp(c.c, op, t.typeInst, c.info, attachedAsgn, 1)
|
||||
op = instantiateGeneric(c, op, t, t.typeInst)
|
||||
t.attachedOps[attachedDestructor] = op
|
||||
|
||||
markUsed(c.graph.config, c.info, op, c.graph.usageSym)
|
||||
#markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op)
|
||||
body.add destructorCall(c.graph, op, x)
|
||||
body.add destructorCall(c.g, op, x)
|
||||
result = true
|
||||
#result = addDestructorCall(c, t, body, x)
|
||||
of attachedAsgn:
|
||||
@@ -210,7 +228,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
of attachedDeepCopy:
|
||||
let op = t.attachedOps[attachedDeepCopy]
|
||||
if op != nil:
|
||||
markUsed(c.graph.config, c.info, op, c.graph.usageSym)
|
||||
#markUsed(c.g.config, c.info, op, c.g.usageSym)
|
||||
onUse(c.info, op)
|
||||
body.add newDeepCopyCall(op, x, y)
|
||||
result = true
|
||||
@@ -227,13 +245,13 @@ proc addVar(father, v, value: PNode) =
|
||||
addSon(father, vpart)
|
||||
|
||||
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
|
||||
var temp = newSym(skTemp, getIdent(c.graph.cache, lowerings.genPrefix), c.fn, c.info)
|
||||
temp.typ = getSysType(c.graph, body.info, tyInt)
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.fn, c.info)
|
||||
temp.typ = getSysType(c.g, body.info, tyInt)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
|
||||
var v = newNodeI(nkVarSection, c.info)
|
||||
result = newSymNode(temp)
|
||||
v.addVar(result, lowerings.newIntLit(c.graph, body.info, first))
|
||||
v.addVar(result, lowerings.newIntLit(c.g, body.info, first))
|
||||
body.add v
|
||||
|
||||
proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode =
|
||||
@@ -243,9 +261,9 @@ proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode =
|
||||
|
||||
proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
|
||||
result = newNodeI(nkWhileStmt, c.info, 2)
|
||||
let cmp = genBuiltin(c.graph, mLtI, "<", i)
|
||||
cmp.add genLen(c.graph, dest)
|
||||
cmp.typ = getSysType(c.graph, c.info, tyBool)
|
||||
let cmp = genBuiltin(c.g, mLtI, "<", i)
|
||||
cmp.add genLen(c.g, dest)
|
||||
cmp.typ = getSysType(c.g, c.info, tyBool)
|
||||
result.sons[0] = cmp
|
||||
result.sons[1] = newNodeI(nkStmtList, c.info)
|
||||
|
||||
@@ -253,8 +271,8 @@ proc genIf(c: var TLiftCtx; cond, action: PNode): PNode =
|
||||
result = newTree(nkIfStmt, newTree(nkElifBranch, cond, action))
|
||||
|
||||
proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
|
||||
let incCall = genBuiltin(c.graph, mInc, "inc", i)
|
||||
incCall.add lowerings.newIntLit(c.graph, c.info, 1)
|
||||
let incCall = genBuiltin(c.g, mInc, "inc", i)
|
||||
incCall.add lowerings.newIntLit(c.g, c.info, 1)
|
||||
body.add incCall
|
||||
|
||||
proc newSeqCall(g: ModuleGraph; x, y: PNode): PNode =
|
||||
@@ -271,18 +289,18 @@ proc setLenStrCall(g: ModuleGraph; x, y: PNode): PNode =
|
||||
result.add lenCall
|
||||
|
||||
proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode =
|
||||
let lenCall = genBuiltin(c.graph, mLengthSeq, "len", y)
|
||||
lenCall.typ = getSysType(c.graph, x.info, tyInt)
|
||||
var op = getSysMagic(c.graph, x.info, "setLen", mSetLengthSeq)
|
||||
op = c.c.instTypeBoundOp(c.c, op, t, c.info, attachedAsgn, 1)
|
||||
let lenCall = genBuiltin(c.g, mLengthSeq, "len", y)
|
||||
lenCall.typ = getSysType(c.g, x.info, tyInt)
|
||||
var op = getSysMagic(c.g, x.info, "setLen", mSetLengthSeq)
|
||||
op = instantiateGeneric(c, op, t, t)
|
||||
result = newTree(nkCall, newSymNode(op, x.info), x, lenCall)
|
||||
|
||||
proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let i = declareCounter(c, body, firstOrd(c.graph.config, t))
|
||||
let i = declareCounter(c, body, toInt64(firstOrd(c.g.config, t)))
|
||||
let whileLoop = genWhileLoop(c, i, x)
|
||||
let elemType = t.lastSon
|
||||
fillBody(c, elemType, whileLoop.sons[1], x.at(i, elemType),
|
||||
y.at(i, elemType))
|
||||
y.at(i, elemType))
|
||||
addIncStmt(c, whileLoop.sons[1], i)
|
||||
body.add whileLoop
|
||||
|
||||
@@ -297,63 +315,69 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.add setLenSeqCall(c, t, x, y)
|
||||
forallElements(c, t, body, x, y)
|
||||
of attachedSink:
|
||||
let moveCall = genBuiltin(c.graph, mMove, "move", x)
|
||||
let moveCall = genBuiltin(c.g, mMove, "move", x)
|
||||
moveCall.add y
|
||||
doAssert t.destructor != nil
|
||||
moveCall.add destructorCall(c.graph, t.destructor, x)
|
||||
moveCall.add destructorCall(c.g, t.destructor, x)
|
||||
body.add moveCall
|
||||
of attachedDestructor:
|
||||
# destroy all elements:
|
||||
forallElements(c, t, body, x, y)
|
||||
body.add genBuiltin(c.graph, mDestroy, "destroy", x)
|
||||
body.add genBuiltin(c.g, mDestroy, "destroy", x)
|
||||
|
||||
proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
createTypeBoundOps(c.c, t, body.info)
|
||||
createTypeBoundOps(c.g, c.c, t, body.info)
|
||||
case c.kind
|
||||
of attachedAsgn, attachedDeepCopy:
|
||||
doAssert t.assignment != nil
|
||||
body.add newAsgnCall(c.graph, t.assignment, x, y)
|
||||
body.add newAsgnCall(c.g, t.assignment, x, y)
|
||||
of attachedSink:
|
||||
# we always inline the move for better performance:
|
||||
let moveCall = genBuiltin(c.graph, mMove, "move", x)
|
||||
let moveCall = genBuiltin(c.g, mMove, "move", x)
|
||||
moveCall.add y
|
||||
doAssert t.destructor != nil
|
||||
moveCall.add destructorCall(c.graph, t.destructor, x)
|
||||
moveCall.add destructorCall(c.g, t.destructor, x)
|
||||
body.add moveCall
|
||||
# alternatively we could do this:
|
||||
when false:
|
||||
doAssert t.asink != nil
|
||||
body.add newAsgnCall(c.graph, t.asink, x, y)
|
||||
body.add newAsgnCall(c.g, t.asink, x, y)
|
||||
of attachedDestructor:
|
||||
doAssert t.destructor != nil
|
||||
body.add destructorCall(c.graph, t.destructor, x)
|
||||
body.add destructorCall(c.g, t.destructor, x)
|
||||
|
||||
proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case c.kind
|
||||
of attachedAsgn, attachedDeepCopy:
|
||||
body.add callCodegenProc(c.graph, "nimAsgnStrV2", c.info, genAddr(c.graph, x), y)
|
||||
body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c.g, x), y)
|
||||
of attachedSink:
|
||||
let moveCall = genBuiltin(c.graph, mMove, "move", x)
|
||||
let moveCall = genBuiltin(c.g, mMove, "move", x)
|
||||
moveCall.add y
|
||||
doAssert t.destructor != nil
|
||||
moveCall.add destructorCall(c.graph, t.destructor, x)
|
||||
moveCall.add destructorCall(c.g, t.destructor, x)
|
||||
body.add moveCall
|
||||
of attachedDestructor:
|
||||
body.add genBuiltin(c.graph, mDestroy, "destroy", x)
|
||||
body.add genBuiltin(c.g, mDestroy, "destroy", x)
|
||||
|
||||
proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case c.kind
|
||||
of attachedSink:
|
||||
# we 'nil' y out afterwards so we *need* to take over its reference
|
||||
# count value:
|
||||
body.add genIf(c, x, callCodegenProc(c.graph, "nimDecWeakRef", c.info, x))
|
||||
body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedAsgn:
|
||||
body.add genIf(c, y, callCodegenProc(c.graph, "nimIncWeakRef", c.info, y))
|
||||
body.add genIf(c, x, callCodegenProc(c.graph, "nimDecWeakRef", c.info, x))
|
||||
body.add genIf(c, y, callCodegenProc(c.g, "nimIncWeakRef", c.info, y))
|
||||
body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDestructor:
|
||||
body.add genIf(c, x, callCodegenProc(c.graph, "nimDecWeakRef", c.info, x))
|
||||
# it's better to prepend the destruction of weak refs in order to
|
||||
# prevent wrong "dangling refs exist" problems:
|
||||
let des = genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
|
||||
if body.len == 0:
|
||||
body.add des
|
||||
else:
|
||||
body.sons.insert(des, 0)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
|
||||
proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
@@ -361,14 +385,14 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
|
||||
let elemType = t.lastSon
|
||||
#fillBody(c, elemType, actions, genDeref(x), genDeref(y))
|
||||
#var disposeCall = genBuiltin(c.graph, mDispose, "dispose", x)
|
||||
#var disposeCall = genBuiltin(c.g, mDispose, "dispose", x)
|
||||
|
||||
if isFinal(elemType):
|
||||
addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr))
|
||||
actions.add callCodegenProc(c.graph, "nimRawDispose", c.info, x)
|
||||
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x)
|
||||
else:
|
||||
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr))
|
||||
actions.add callCodegenProc(c.graph, "nimDestroyAndDispose", c.info, x)
|
||||
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, x)
|
||||
|
||||
case c.kind
|
||||
of attachedSink, attachedAsgn:
|
||||
@@ -384,35 +408,40 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
# have to go through some indirection; we delegate this to the codegen:
|
||||
let call = newNodeI(nkCall, c.info, 2)
|
||||
call.typ = t
|
||||
call.sons[0] = newSymNode(createMagic(c.graph, "deepCopy", mDeepCopy))
|
||||
call.sons[0] = newSymNode(createMagic(c.g, "deepCopy", mDeepCopy))
|
||||
call.sons[1] = y
|
||||
body.add newAsgnStmt(x, call)
|
||||
elif optNimV2 in c.graph.config.globalOptions:
|
||||
let xx = genBuiltin(c.graph, mAccessEnv, "accessEnv", x)
|
||||
xx.typ = getSysType(c.graph, c.info, tyPointer)
|
||||
elif optNimV2 in c.g.config.globalOptions and
|
||||
optRefCheck in c.g.config.options:
|
||||
let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x)
|
||||
xx.typ = getSysType(c.g, c.info, tyPointer)
|
||||
case c.kind
|
||||
of attachedSink:
|
||||
# we 'nil' y out afterwards so we *need* to take over its reference
|
||||
# count value:
|
||||
body.add genIf(c, xx, callCodegenProc(c.graph, "nimDecWeakRef", c.info, xx))
|
||||
body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedAsgn:
|
||||
let yy = genBuiltin(c.graph, mAccessEnv, "accessEnv", y)
|
||||
yy.typ = getSysType(c.graph, c.info, tyPointer)
|
||||
body.add genIf(c, yy, callCodegenProc(c.graph, "nimIncWeakRef", c.info, yy))
|
||||
body.add genIf(c, xx, callCodegenProc(c.graph, "nimDecWeakRef", c.info, xx))
|
||||
let yy = genBuiltin(c.g, mAccessEnv, "accessEnv", y)
|
||||
yy.typ = getSysType(c.g, c.info, tyPointer)
|
||||
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncWeakRef", c.info, yy))
|
||||
body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDestructor:
|
||||
body.add genIf(c, xx, callCodegenProc(c.graph, "nimDecWeakRef", c.info, xx))
|
||||
let des = genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
|
||||
if body.len == 0:
|
||||
body.add des
|
||||
else:
|
||||
body.sons.insert(des, 0)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
|
||||
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let xx = genBuiltin(c.graph, mAccessEnv, "accessEnv", x)
|
||||
xx.typ = getSysType(c.graph, c.info, tyPointer)
|
||||
let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x)
|
||||
xx.typ = getSysType(c.g, c.info, tyPointer)
|
||||
var actions = newNodeI(nkStmtList, c.info)
|
||||
let elemType = t.lastSon
|
||||
#discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(xx))
|
||||
actions.add callCodegenProc(c.graph, "nimDestroyAndDispose", c.info, xx)
|
||||
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, xx)
|
||||
case c.kind
|
||||
of attachedSink, attachedAsgn:
|
||||
body.add genIf(c, xx, actions)
|
||||
@@ -428,7 +457,8 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
tyPtr, tyOpt, tyUncheckedArray:
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyRef:
|
||||
if optNimV2 in c.graph.config.globalOptions:
|
||||
if optNimV2 in c.g.config.globalOptions and
|
||||
optRefCheck in c.g.config.options:
|
||||
weakrefOp(c, t, body, x, y)
|
||||
else:
|
||||
defaultOp(c, t, body, x, y)
|
||||
@@ -439,7 +469,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyOwned:
|
||||
let base = t.skipTypes(abstractInstOwned)
|
||||
if optNimV2 in c.graph.config.globalOptions:
|
||||
if optNimV2 in c.g.config.globalOptions:
|
||||
case base.kind
|
||||
of tyRef:
|
||||
ownedRefOp(c, base, body, x, y)
|
||||
@@ -458,13 +488,13 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of tySequence:
|
||||
if useNoGc(c, t):
|
||||
useSeqOrStrOp(c, t, body, x, y)
|
||||
elif c.graph.config.selectedGC == gcDestructors:
|
||||
elif c.g.config.selectedGC == gcDestructors:
|
||||
# note that tfHasAsgn is propagated so we need the check on
|
||||
# 'selectedGC' here to determine if we have the new runtime.
|
||||
discard considerUserDefinedOp(c, t, body, x, y)
|
||||
elif tfHasAsgn in t.flags:
|
||||
if c.kind != attachedDestructor:
|
||||
body.add newSeqCall(c.graph, x, y)
|
||||
body.add newSeqCall(c.g, x, y)
|
||||
forallElements(c, t, body, x, y)
|
||||
else:
|
||||
defaultOp(c, t, body, x, y)
|
||||
@@ -477,19 +507,23 @@ 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):
|
||||
fillBodyObj(c, t.n, body, x, y)
|
||||
fillBodyObjT(c, t, body, x, y)
|
||||
of tyDistinct:
|
||||
if not considerUserDefinedOp(c, t, body, x, y):
|
||||
fillBody(c, t.sons[0].skipTypes(skipPtrs), body, x, y)
|
||||
of tyTuple:
|
||||
fillBodyTup(c, t, body, x, y)
|
||||
of tyVarargs, tyOpenArray:
|
||||
localError(c.graph.config, c.info, "cannot copy openArray")
|
||||
if c.kind == attachedDestructor:
|
||||
forallElements(c, t, body, x, y)
|
||||
else:
|
||||
discard "cannot copy openArray"
|
||||
|
||||
of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
|
||||
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
|
||||
tyGenericParam, tyGenericBody, tyNil, tyUntyped, tyTyped,
|
||||
tyTypeDesc, tyGenericInvocation, tyForward:
|
||||
#internalError(c.graph.config, c.info, "assignment requested for type: " & typeToString(t))
|
||||
#internalError(c.g.config, c.info, "assignment requested for type: " & typeToString(t))
|
||||
discard
|
||||
of tyVar, tyLent:
|
||||
if c.kind != attachedDestructor:
|
||||
@@ -498,25 +532,24 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
tyGenericInst, tyStatic, tyAlias, tySink:
|
||||
fillBody(c, lastSon(t), body, x, y)
|
||||
|
||||
proc produceSymDistinctType(c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym =
|
||||
proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym =
|
||||
assert typ.kind == tyDistinct
|
||||
let baseType = typ[0]
|
||||
if baseType.attachedOps[kind] == nil:
|
||||
discard produceSym(c, baseType, kind, info)
|
||||
discard produceSym(g, c, baseType, kind, info)
|
||||
typ.attachedOps[kind] = baseType.attachedOps[kind]
|
||||
result = typ.attachedOps[kind]
|
||||
|
||||
proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
info: TLineInfo): PSym =
|
||||
if typ.kind == tyDistinct:
|
||||
return produceSymDistinctType(c, typ, kind, info)
|
||||
return produceSymDistinctType(g, c, typ, kind, info)
|
||||
|
||||
var a: TLiftCtx
|
||||
a.info = info
|
||||
a.graph = c.graph
|
||||
a.g = g
|
||||
a.kind = kind
|
||||
a.c = c
|
||||
let g = c.graph
|
||||
let body = newNodeI(nkStmtList, info)
|
||||
let procname = getIdent(g.cache, AttachedOpToStr[kind])
|
||||
|
||||
@@ -538,7 +571,7 @@ proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
typ.attachedOps[kind] = result
|
||||
|
||||
var tk: TTypeKind
|
||||
if optNimV2 in c.graph.config.globalOptions:
|
||||
if g.config.selectedGC == gcDestructors:
|
||||
tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind
|
||||
else:
|
||||
tk = tyNone # no special casing for strings and seqs
|
||||
@@ -562,33 +595,39 @@ proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
template liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
|
||||
discard "now a nop"
|
||||
|
||||
proc patchBody(c: PContext; n: PNode; info: TLineInfo) =
|
||||
proc patchBody(g: ModuleGraph; c: PContext; n: PNode; info: TLineInfo) =
|
||||
if n.kind in nkCallKinds:
|
||||
if n[0].kind == nkSym and n[0].sym.magic == mDestroy:
|
||||
let t = n[1].typ.skipTypes(abstractVar)
|
||||
if t.destructor == nil:
|
||||
discard produceSym(c, t, attachedDestructor, info)
|
||||
discard produceSym(g, c, t, attachedDestructor, info)
|
||||
|
||||
if t.destructor != nil:
|
||||
if t.destructor.ast[genericParamsPos].kind != nkEmpty:
|
||||
internalError(c.graph.config, info, "resolved destructor is generic")
|
||||
internalError(g.config, info, "resolved destructor is generic")
|
||||
if t.destructor.magic == mDestroy:
|
||||
internalError(c.graph.config, info, "patching mDestroy with mDestroy?")
|
||||
internalError(g.config, info, "patching mDestroy with mDestroy?")
|
||||
n.sons[0] = newSymNode(t.destructor)
|
||||
for x in n: patchBody(c, x, info)
|
||||
for x in n: patchBody(g, c, x, info)
|
||||
|
||||
template inst(field, t) =
|
||||
if field.ast != nil and field.ast[genericParamsPos].kind != nkEmpty:
|
||||
if t.typeInst != nil:
|
||||
field = c.instTypeBoundOp(c, field, t.typeInst, info, attachedAsgn, 1)
|
||||
var a: TLiftCtx
|
||||
a.info = info
|
||||
a.g = g
|
||||
a.kind = k
|
||||
a.c = c
|
||||
|
||||
field = instantiateGeneric(a, field, t, t.typeInst)
|
||||
if field.ast != nil:
|
||||
patchBody(c, field.ast, info)
|
||||
patchBody(g, c, field.ast, info)
|
||||
else:
|
||||
localError(c.graph.config, info, "unresolved generic parameter")
|
||||
localError(g.config, info, "unresolved generic parameter")
|
||||
|
||||
proc isTrival(s: PSym): bool {.inline.} = s == nil or s.ast[bodyPos].len == 0
|
||||
|
||||
proc createTypeBoundOps(c: PContext; orig: PType; info: TLineInfo) =
|
||||
proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo) =
|
||||
## In the semantic pass this is called in strategic places
|
||||
## to ensure we lift assignment, destructors and moves properly.
|
||||
## The later 'injectdestructors' pass depends on it.
|
||||
@@ -596,13 +635,13 @@ proc createTypeBoundOps(c: PContext; orig: PType; info: TLineInfo) =
|
||||
incl orig.flags, tfCheckedForDestructor
|
||||
|
||||
let h = sighashes.hashType(orig, {CoType, CoConsiderOwned, CoDistinct})
|
||||
var canon = c.graph.canonTypes.getOrDefault(h)
|
||||
var canon = g.canonTypes.getOrDefault(h)
|
||||
var overwrite = false
|
||||
if canon == nil:
|
||||
let typ = orig.skipTypes({tyGenericInst, tyAlias})
|
||||
c.graph.canonTypes[h] = typ
|
||||
let typ = orig.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
g.canonTypes[h] = typ
|
||||
canon = typ
|
||||
elif canon != orig:
|
||||
if canon != orig:
|
||||
overwrite = true
|
||||
|
||||
# multiple cases are to distinguish here:
|
||||
@@ -615,7 +654,7 @@ proc createTypeBoundOps(c: PContext; orig: PType; info: TLineInfo) =
|
||||
# we generate the destructor first so that other operators can depend on it:
|
||||
for k in attachedDestructor..attachedSink:
|
||||
if canon.attachedOps[k] == nil:
|
||||
discard produceSym(c, canon, k, info)
|
||||
discard produceSym(g, c, canon, k, info)
|
||||
else:
|
||||
inst(canon.attachedOps[k], canon)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## This module implements the '.liftLocals' pragma.
|
||||
|
||||
import
|
||||
intsets, strutils, options, ast, astalgo, msgs,
|
||||
strutils, options, ast, msgs,
|
||||
idents, renderer, types, lowerings, lineinfos
|
||||
|
||||
from pragmas import getPragmaVal
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
import ropes, tables, pathutils
|
||||
|
||||
const
|
||||
explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
|
||||
explanationsBaseUrl* = "https://nim-lang.org/docs"
|
||||
|
||||
type
|
||||
TMsgKind* = enum
|
||||
@@ -33,12 +33,14 @@ type
|
||||
warnFieldXNotSupported, warnCommentXIgnored,
|
||||
warnTypelessParam,
|
||||
warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
|
||||
warnUnusedImportX,
|
||||
warnEachIdentIsTuple,
|
||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||
warnInconsistentSpacing, warnCaseTransition, warnUser,
|
||||
hintSuccess, hintSuccessX, hintCC,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed,
|
||||
hintConvToBaseNotNeeded,
|
||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||
hintConditionAlwaysTrue, hintConditionAlwaysFalse, hintName, hintPattern,
|
||||
@@ -78,6 +80,7 @@ const
|
||||
warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
|
||||
warnWriteToForeignHeap: "write to foreign heap",
|
||||
warnUnsafeCode: "unsafe code: '$1'",
|
||||
warnUnusedImportX: "imported and not used: '$1'",
|
||||
warnEachIdentIsTuple: "each identifier is a tuple",
|
||||
warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.",
|
||||
warnProveField: "cannot prove that field '$1' is accessible",
|
||||
@@ -108,7 +111,7 @@ const
|
||||
hintPath: "added path: '$1'",
|
||||
hintConditionAlwaysTrue: "condition is always true: '$1'",
|
||||
hintConditionAlwaysFalse: "condition is always false: '$1'",
|
||||
hintName: "name should be: '$1'",
|
||||
hintName: "$1",
|
||||
hintPattern: "$1",
|
||||
hintExecuting: "$1",
|
||||
hintLinking: "",
|
||||
@@ -133,14 +136,15 @@ const
|
||||
"LanguageXNotSupported", "FieldXNotSupported",
|
||||
"CommentXIgnored",
|
||||
"TypelessParam", "UseBase", "WriteToForeignHeap",
|
||||
"UnsafeCode", "EachIdentIsTuple",
|
||||
"UnsafeCode", "UnusedImport", "EachIdentIsTuple",
|
||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||
"GcMem", "Destructor", "LockLevel", "ResultShadowed",
|
||||
"Spacing", "CaseTransition", "User"]
|
||||
|
||||
HintsToStr* = [
|
||||
"Success", "SuccessX", "CC", "LineTooLong",
|
||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||
"XDeclaredButNotUsed",
|
||||
"ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
||||
"Path", "CondTrue", "CondFalse", "Name", "Pattern", "Exec", "Link", "Dependency",
|
||||
"Source", "Performance", "StackTrace", "GCStats", "GlobalVar", "ExpandMacro",
|
||||
@@ -193,7 +197,7 @@ type
|
||||
# used for better error messages and
|
||||
# embedding the original source in the
|
||||
# generated code
|
||||
dirtyfile*: AbsoluteFile # the file that is actually read into memory
|
||||
dirtyFile*: AbsoluteFile # the file that is actually read into memory
|
||||
# and parsed; usually "" but is used
|
||||
# for 'nimsuggest'
|
||||
hash*: string # the checksum of the file
|
||||
@@ -229,19 +233,21 @@ proc raiseRecoverableError*(msg: string) {.noinline.} =
|
||||
raise newException(ERecoverableError, msg)
|
||||
|
||||
const
|
||||
InvalidFileIDX* = FileIndex(-1)
|
||||
InvalidFileIdx* = FileIndex(-1)
|
||||
|
||||
proc unknownLineInfo*(): TLineInfo =
|
||||
result.line = uint16(0)
|
||||
result.col = int16(-1)
|
||||
result.fileIndex = InvalidFileIDX
|
||||
result.fileIndex = InvalidFileIdx
|
||||
|
||||
type
|
||||
Severity* {.pure.} = enum ## VS Code only supports these three
|
||||
Hint, Warning, Error
|
||||
|
||||
const trackPosInvalidFileIdx* = FileIndex(-2) # special marker so that no suggestions
|
||||
# are produced within comments and string literals
|
||||
const
|
||||
trackPosInvalidFileIdx* = FileIndex(-2) # special marker so that no suggestions
|
||||
# are produced within comments and string literals
|
||||
commandLineIdx* = FileIndex(-3)
|
||||
|
||||
type
|
||||
MsgConfig* = object ## does not need to be stored in the incremental cache
|
||||
|
||||
@@ -9,11 +9,9 @@
|
||||
|
||||
## This module implements the style checker.
|
||||
|
||||
import
|
||||
strutils, os, intsets, strtabs
|
||||
import strutils
|
||||
|
||||
import options, ast, astalgo, msgs, semdata, ropes, idents,
|
||||
lineinfos, pathutils
|
||||
import options, ast, msgs, idents, lineinfos, wordrecg
|
||||
|
||||
const
|
||||
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
|
||||
@@ -22,33 +20,6 @@ proc identLen*(line: string, start: int): int =
|
||||
while start+result < line.len and line[start+result] in Letters:
|
||||
inc result
|
||||
|
||||
type
|
||||
StyleCheck* {.pure.} = enum None, Warn, Auto
|
||||
|
||||
var
|
||||
gOverWrite* = true
|
||||
gStyleCheck*: StyleCheck
|
||||
gCheckExtern*, gOnlyMainfile*: bool
|
||||
|
||||
proc overwriteFiles*(conf: ConfigRef) =
|
||||
let doStrip = options.getConfigVar(conf, "pretty.strip").normalize == "on"
|
||||
for i in 0 .. high(conf.m.fileInfos):
|
||||
if conf.m.fileInfos[i].dirty and
|
||||
(not gOnlyMainfile or FileIndex(i) == conf.projectMainIdx):
|
||||
let newFile = if gOverWrite: conf.m.fileInfos[i].fullpath
|
||||
else: conf.m.fileInfos[i].fullpath.changeFileExt(".pretty.nim")
|
||||
try:
|
||||
var f = open(newFile.string, fmWrite)
|
||||
for line in conf.m.fileInfos[i].lines:
|
||||
if doStrip:
|
||||
f.write line.strip(leading = false, trailing = true)
|
||||
else:
|
||||
f.write line
|
||||
f.write(conf.m.fileInfos[i], "\L")
|
||||
f.close
|
||||
except IOError:
|
||||
rawMessage(conf, errGenerated, "cannot open file: " & newFile.string)
|
||||
|
||||
proc `=~`(s: string, a: openArray[string]): bool =
|
||||
for x in a:
|
||||
if s.startsWith(x): return true
|
||||
@@ -69,7 +40,7 @@ proc beautifyName(s: string, k: TSymKind): string =
|
||||
"pointer", "float", "csize", "cdouble", "cchar", "cschar",
|
||||
"cshort", "cu", "nil", "typedesc", "auto", "any",
|
||||
"range", "openarray", "varargs", "set", "cfloat", "ref", "ptr",
|
||||
"untyped", "typed", "static", "sink", "lent", "type"]:
|
||||
"untyped", "typed", "static", "sink", "lent", "type", "owned"]:
|
||||
result.add s[i]
|
||||
else:
|
||||
result.add toUpperAscii(s[i])
|
||||
@@ -98,47 +69,26 @@ proc beautifyName(s: string, k: TSymKind): string =
|
||||
result.add s[i]
|
||||
inc i
|
||||
|
||||
proc differ*(line: string, a, b: int, x: string): bool =
|
||||
let y = line[a..b]
|
||||
result = cmpIgnoreStyle(y, x) == 0 and y != x
|
||||
proc differ*(line: string, a, b: int, x: string): string =
|
||||
proc substrEq(s: string, pos, last: int, substr: string): bool =
|
||||
var i = 0
|
||||
var length = substr.len
|
||||
while i < length and pos+i <= last and s[pos+i] == substr[i]:
|
||||
inc i
|
||||
return i == length
|
||||
|
||||
proc replaceInFile(conf: ConfigRef; info: TLineInfo; newName: string) =
|
||||
let line = conf.m.fileInfos[info.fileIndex.int].lines[info.line.int-1]
|
||||
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 = min(b, line.len)
|
||||
|
||||
let last = first+identLen(line, first)-1
|
||||
if differ(line, first, last, newName):
|
||||
# last-first+1 != newName.len or
|
||||
var x = line.substr(0, first-1) & newName & line.substr(last+1)
|
||||
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int].lines[info.line.int-1], x)
|
||||
conf.m.fileInfos[info.fileIndex.int].dirty = true
|
||||
|
||||
proc lintReport(conf: ConfigRef; info: TLineInfo, beau: string) =
|
||||
if optStyleError in conf.globalOptions:
|
||||
localError(conf, info, "name should be: '$1'" % beau)
|
||||
else:
|
||||
message(conf, info, hintName, beau)
|
||||
result = ""
|
||||
if not substrEq(line, a, b, x):
|
||||
let y = line[a..b]
|
||||
if cmpIgnoreStyle(y, x) == 0:
|
||||
result = y
|
||||
|
||||
proc checkStyle(conf: ConfigRef; cache: IdentCache; info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
|
||||
let beau = beautifyName(s, k)
|
||||
if s != beau:
|
||||
if gStyleCheck == StyleCheck.Auto:
|
||||
sym.name = getIdent(cache, beau)
|
||||
replaceInFile(conf, info, beau)
|
||||
else:
|
||||
lintReport(conf, info, beau)
|
||||
|
||||
proc styleCheckDefImpl(conf: ConfigRef; cache: IdentCache; info: TLineInfo; s: PSym; k: TSymKind) =
|
||||
# operators stay as they are:
|
||||
if k in {skResult, skTemp} or s.name.s[0] notin Letters: return
|
||||
if k in {skType, skGenericParam} and sfAnon in s.flags: return
|
||||
if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern:
|
||||
checkStyle(conf, cache, info, s.name.s, k, s)
|
||||
lintReport(conf, info, beau, s)
|
||||
|
||||
proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
|
||||
# operators stay as they are:
|
||||
@@ -146,35 +96,47 @@ proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
|
||||
if k in {skType, skGenericParam} and sfAnon in s.flags: return
|
||||
if s.typ != nil and s.typ.kind == tyTypeDesc: return
|
||||
if {sfImportc, sfExportc} * s.flags != {}: return
|
||||
if optStyleCheck notin s.options: return
|
||||
let beau = beautifyName(s.name.s, k)
|
||||
if s.name.s != beau:
|
||||
lintReport(conf, info, beau)
|
||||
lintReport(conf, info, beau, s.name.s)
|
||||
|
||||
template styleCheckDef*(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
|
||||
if {optStyleHint, optStyleError} * conf.globalOptions != {}:
|
||||
nep1CheckDefImpl(conf, info, s, k)
|
||||
when defined(nimfix):
|
||||
if gStyleCheck != StyleCheck.None: styleCheckDefImpl(conf, cache, info, s, k)
|
||||
|
||||
template styleCheckDef*(conf: ConfigRef; info: TLineInfo; s: PSym) =
|
||||
styleCheckDef(conf, info, s, s.kind)
|
||||
template styleCheckDef*(conf: ConfigRef; s: PSym) =
|
||||
styleCheckDef(conf, s.info, s, s.kind)
|
||||
|
||||
proc styleCheckUseImpl(conf: ConfigRef; info: TLineInfo; s: PSym) =
|
||||
proc differs(conf: ConfigRef; info: TLineInfo; newName: string): string =
|
||||
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 first+1 < line.len and line[first] == '`': inc first
|
||||
|
||||
let last = first+identLen(line, first)-1
|
||||
result = differ(line, first, last, newName)
|
||||
|
||||
proc styleCheckUse*(conf: ConfigRef; info: TLineInfo; s: PSym) =
|
||||
if info.fileIndex.int < 0: return
|
||||
# we simply convert it to what it looks like in the definition
|
||||
# for consistency
|
||||
|
||||
# operators stay as they are:
|
||||
if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters:
|
||||
if s.kind == skTemp or s.name.s[0] notin Letters or sfAnon in s.flags:
|
||||
return
|
||||
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
|
||||
|
||||
let newName = s.name.s
|
||||
let oldName = differs(conf, info, newName)
|
||||
if oldName.len > 0:
|
||||
lintReport(conf, info, newName, oldName)
|
||||
|
||||
replaceInFile(conf, info, newName)
|
||||
#if newName == "File": writeStackTrace()
|
||||
|
||||
template styleCheckUse*(info: TLineInfo; s: PSym) =
|
||||
when defined(nimfix):
|
||||
if gStyleCheck != StyleCheck.None: styleCheckUseImpl(conf, info, s)
|
||||
proc checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) =
|
||||
let wanted = canonPragmaSpelling(w)
|
||||
if pragmaName != wanted:
|
||||
lintReport(conf, info, wanted, pragmaName)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Low-level streams for high performance.
|
||||
|
||||
import
|
||||
strutils, pathutils
|
||||
pathutils
|
||||
|
||||
# support '-d:useGnuReadline' for backwards compatibility:
|
||||
when not defined(windows) and (defined(useGnuReadline) or defined(useLinenoise)):
|
||||
@@ -97,7 +97,7 @@ proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
|
||||
|
||||
proc countTriples(s: string): int =
|
||||
var i = 0
|
||||
while i < s.len:
|
||||
while i+2 < s.len:
|
||||
if s[i] == '"' and s[i+1] == '"' and s[i+2] == '"':
|
||||
inc result
|
||||
inc i, 2
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, idents, semdata, types, msgs, options,
|
||||
renderer, wordrecg, idgen, nimfix/prettybase, lineinfos, strutils
|
||||
renderer, nimfix/prettybase, lineinfos, strutils
|
||||
|
||||
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
|
||||
|
||||
@@ -430,7 +430,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
of oimOtherModule:
|
||||
result = nextIdentIter(o.it, o.m.tab).skipAlias(n, c.config)
|
||||
of oimSymChoice:
|
||||
if o.symChoiceIndex < sonsLen(n):
|
||||
if o.symChoiceIndex < len(n):
|
||||
result = n.sons[o.symChoiceIndex].sym
|
||||
incl(o.inSymChoice, result.id)
|
||||
inc o.symChoiceIndex
|
||||
|
||||
@@ -14,7 +14,6 @@ const
|
||||
|
||||
import ast, astalgo, types, idents, magicsys, msgs, options, modulegraphs,
|
||||
lineinfos
|
||||
from trees import getMagic
|
||||
|
||||
proc newDeref*(n: PNode): PNode {.inline.} =
|
||||
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
|
||||
@@ -22,8 +21,8 @@ proc newDeref*(n: PNode): PNode {.inline.} =
|
||||
|
||||
proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode =
|
||||
if tup.kind == nkHiddenAddr:
|
||||
result = newNodeIT(nkHiddenAddr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar}))
|
||||
result.addSon(newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar}).sons[i]))
|
||||
result = newNodeIT(nkHiddenAddr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent}))
|
||||
result.addSon(newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent}).sons[i]))
|
||||
addSon(result[0], tup[0])
|
||||
var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt))
|
||||
lit.intVal = i
|
||||
@@ -43,12 +42,12 @@ proc addVar*(father, v: PNode) =
|
||||
vpart.sons[2] = vpart[1]
|
||||
addSon(father, vpart)
|
||||
|
||||
proc newAsgnStmt(le, ri: PNode): PNode =
|
||||
proc newAsgnStmt*(le, ri: PNode): PNode =
|
||||
result = newNodeI(nkAsgn, le.info, 2)
|
||||
result.sons[0] = le
|
||||
result.sons[1] = ri
|
||||
|
||||
proc newFastAsgnStmt(le, ri: PNode): PNode =
|
||||
proc newFastAsgnStmt*(le, ri: PNode): PNode =
|
||||
result = newNodeI(nkFastAsgn, le.info, 2)
|
||||
result.sons[0] = le
|
||||
result.sons[1] = ri
|
||||
@@ -153,8 +152,9 @@ proc createObj*(g: ModuleGraph; owner: PSym, info: TLineInfo; final=true): PType
|
||||
|
||||
proc rawAddField*(obj: PType; field: PSym) =
|
||||
assert field.kind == skField
|
||||
field.position = sonsLen(obj.n)
|
||||
field.position = len(obj.n)
|
||||
addSon(obj.n, newSymNode(field))
|
||||
propagateToOwner(obj, field.typ)
|
||||
|
||||
proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode =
|
||||
# returns a[].field as a node
|
||||
@@ -179,14 +179,14 @@ proc lookupInRecord(n: PNode, id: int): PSym =
|
||||
result = nil
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
result = lookupInRecord(n.sons[i], id)
|
||||
if result != nil: return
|
||||
of nkRecCase:
|
||||
if n.sons[0].kind != nkSym: return
|
||||
result = lookupInRecord(n.sons[0], id)
|
||||
if result != nil: return
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
case n.sons[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
result = lookupInRecord(lastSon(n.sons[i]), id)
|
||||
@@ -205,7 +205,8 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache) =
|
||||
let t = skipIntLit(s.typ)
|
||||
field.typ = t
|
||||
assert t.kind != tyTyped
|
||||
field.position = sonsLen(obj.n)
|
||||
propagateToOwner(obj, t)
|
||||
field.position = len(obj.n)
|
||||
addSon(obj.n, newSymNode(field))
|
||||
|
||||
proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache): PSym {.discardable.} =
|
||||
@@ -217,11 +218,12 @@ proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache): PSym {.discardable
|
||||
let t = skipIntLit(s.typ)
|
||||
field.typ = t
|
||||
assert t.kind != tyTyped
|
||||
field.position = sonsLen(obj.n)
|
||||
propagateToOwner(obj, t)
|
||||
field.position = len(obj.n)
|
||||
addSon(obj.n, newSymNode(field))
|
||||
result = field
|
||||
|
||||
proc newDotExpr(obj, b: PSym): PNode =
|
||||
proc newDotExpr*(obj, b: PSym): PNode =
|
||||
result = newNodeI(nkDotExpr, obj.info)
|
||||
let field = lookupInRecord(obj.typ.n, b.id)
|
||||
assert field != nil, b.name.s
|
||||
@@ -252,7 +254,7 @@ proc indirectAccess*(a: PNode, b: int, info: TLineInfo): PNode =
|
||||
addSon(result, newSymNode(field))
|
||||
result.typ = field.typ
|
||||
|
||||
proc indirectAccess(a: PNode, b: string, info: TLineInfo; cache: IdentCache): PNode =
|
||||
proc indirectAccess*(a: PNode, b: string, info: TLineInfo; cache: IdentCache): PNode =
|
||||
# returns a[].b as a node
|
||||
var deref = newNodeI(nkHiddenDeref, info)
|
||||
deref.typ = a.typ.skipTypes(abstractInst).sons[0]
|
||||
@@ -322,44 +324,27 @@ proc callCodegenProc*(g: ModuleGraph; name: string;
|
||||
result.add optionalArgs[i]
|
||||
result.typ = sym.typ.sons[0]
|
||||
|
||||
proc callProc(a: PNode): PNode =
|
||||
result = newNodeI(nkCall, a.info)
|
||||
result.add a
|
||||
result.typ = a.typ.sons[0]
|
||||
proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
|
||||
result = nkIntLit.newIntNode(value)
|
||||
result.typ = getSysType(g, info, tyInt)
|
||||
|
||||
# we have 4 cases to consider:
|
||||
# - a void proc --> nothing to do
|
||||
# - a proc returning GC'ed memory --> requires a flowVar
|
||||
# - a proc returning non GC'ed memory --> pass as hidden 'var' parameter
|
||||
# - not in a parallel environment --> requires a flowVar for memory safety
|
||||
type
|
||||
TSpawnResult* = enum
|
||||
srVoid, srFlowVar, srByVar
|
||||
TFlowVarKind = enum
|
||||
fvInvalid # invalid type T for 'FlowVar[T]'
|
||||
fvGC # FlowVar of a GC'ed type
|
||||
fvBlob # FlowVar of a blob type
|
||||
proc genHigh*(g: ModuleGraph; n: PNode): PNode =
|
||||
if skipTypes(n.typ, abstractVar).kind == tyArray:
|
||||
result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar))))
|
||||
else:
|
||||
result = newNodeI(nkCall, n.info, 2)
|
||||
result.typ = getSysType(g, n.info, tyInt)
|
||||
result.sons[0] = newSymNode(getSysMagic(g, n.info, "high", mHigh))
|
||||
result.sons[1] = n
|
||||
|
||||
proc spawnResult*(t: PType; inParallel: bool): TSpawnResult =
|
||||
if t.isEmptyType: srVoid
|
||||
elif inParallel and not containsGarbageCollectedRef(t): srByVar
|
||||
else: srFlowVar
|
||||
|
||||
proc flowVarKind(t: PType): TFlowVarKind =
|
||||
if t.skipTypes(abstractInst).kind in {tyRef, tyString, tySequence}: fvGC
|
||||
elif containsGarbageCollectedRef(t): fvInvalid
|
||||
else: fvBlob
|
||||
|
||||
proc typeNeedsNoDeepCopy(t: PType): bool =
|
||||
var t = t.skipTypes(abstractInst)
|
||||
# for the tconvexhull example (and others) we're a bit lax here and pretend
|
||||
# seqs and strings are *by value* only and 'shallow' doesn't exist!
|
||||
if t.kind == tyString: return true
|
||||
# note that seq[T] is fine, but 'var seq[T]' is not, so we need to skip 'var'
|
||||
# for the stricter check and likewise we can skip 'seq' for a less
|
||||
# strict check:
|
||||
if t.kind in {tyVar, tyLent, tySequence}: t = t.lastSon
|
||||
result = not containsGarbageCollectedRef(t)
|
||||
proc genLen*(g: ModuleGraph; n: PNode): PNode =
|
||||
if skipTypes(n.typ, abstractVar).kind == tyArray:
|
||||
result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar)) + 1))
|
||||
else:
|
||||
result = newNodeI(nkCall, n.info, 2)
|
||||
result.typ = getSysType(g, n.info, tyInt)
|
||||
result.sons[0] = newSymNode(getSysMagic(g, n.info, "len", mLengthSeq))
|
||||
result.sons[1] = n
|
||||
|
||||
proc hoistExpr*(varSection, expr: PNode, name: PIdent, owner: PSym): PSym =
|
||||
result = newSym(skLet, name, owner, varSection.info, owner.options)
|
||||
@@ -372,399 +357,3 @@ proc hoistExpr*(varSection, expr: PNode, name: PIdent, owner: PSym): PSym =
|
||||
varDef.sons[2] = expr
|
||||
|
||||
varSection.add varDef
|
||||
|
||||
proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: PType;
|
||||
v: PNode; useShallowCopy=false): PSym =
|
||||
result = newSym(skTemp, getIdent(g.cache, genPrefix), owner, varSection.info,
|
||||
owner.options)
|
||||
result.typ = typ
|
||||
incl(result.flags, sfFromGeneric)
|
||||
|
||||
var vpart = newNodeI(nkIdentDefs, varSection.info, 3)
|
||||
vpart.sons[0] = newSymNode(result)
|
||||
vpart.sons[1] = newNodeI(nkEmpty, varSection.info)
|
||||
vpart.sons[2] = if varInit.isNil: v else: vpart[1]
|
||||
varSection.add vpart
|
||||
if varInit != nil:
|
||||
if useShallowCopy and typeNeedsNoDeepCopy(typ):
|
||||
varInit.add newFastAsgnStmt(newSymNode(result), v)
|
||||
else:
|
||||
let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
|
||||
deepCopyCall.sons[0] = newSymNode(getSysMagic(g, varSection.info, "deepCopy", mDeepCopy))
|
||||
deepCopyCall.sons[1] = newSymNode(result)
|
||||
deepCopyCall.sons[2] = v
|
||||
varInit.add deepCopyCall
|
||||
|
||||
discard """
|
||||
We generate roughly this:
|
||||
|
||||
proc f_wrapper(thread, args) =
|
||||
barrierEnter(args.barrier) # for parallel statement
|
||||
var a = args.a # thread transfer; deepCopy or shallowCopy or no copy
|
||||
# depending on whether we're in a 'parallel' statement
|
||||
var b = args.b
|
||||
var fv = args.fv
|
||||
|
||||
fv.owner = thread # optional
|
||||
nimArgsPassingDone() # signal parent that the work is done
|
||||
#
|
||||
args.fv.blob = f(a, b, ...)
|
||||
nimFlowVarSignal(args.fv)
|
||||
|
||||
# - or -
|
||||
f(a, b, ...)
|
||||
barrierLeave(args.barrier) # for parallel statement
|
||||
|
||||
stmtList:
|
||||
var scratchObj
|
||||
scratchObj.a = a
|
||||
scratchObj.b = b
|
||||
|
||||
nimSpawn(f_wrapper, addr scratchObj)
|
||||
scratchObj.fv # optional
|
||||
|
||||
"""
|
||||
|
||||
proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
|
||||
varSection, varInit, call, barrier, fv: PNode;
|
||||
spawnKind: TSpawnResult): PSym =
|
||||
var body = newNodeI(nkStmtList, f.info)
|
||||
body.flags.incl nfTransf # do not transform further
|
||||
|
||||
var threadLocalBarrier: PSym
|
||||
if barrier != nil:
|
||||
var varSection2 = newNodeI(nkVarSection, barrier.info)
|
||||
threadLocalBarrier = addLocalVar(g, varSection2, nil, argsParam.owner,
|
||||
barrier.typ, barrier)
|
||||
body.add varSection2
|
||||
body.add callCodegenProc(g, "barrierEnter", threadLocalBarrier.info,
|
||||
threadLocalBarrier.newSymNode)
|
||||
var threadLocalProm: PSym
|
||||
if spawnKind == srByVar:
|
||||
threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv)
|
||||
elif fv != nil:
|
||||
internalAssert g.config, fv.typ.kind == tyGenericInst
|
||||
threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv)
|
||||
body.add varSection
|
||||
body.add varInit
|
||||
if fv != nil and spawnKind != srByVar:
|
||||
# generate:
|
||||
# fv.owner = threadParam
|
||||
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
|
||||
"owner", fv.info, g.cache), threadParam.newSymNode)
|
||||
|
||||
body.add callCodegenProc(g, "nimArgsPassingDone", threadParam.info,
|
||||
threadParam.newSymNode)
|
||||
if spawnKind == srByVar:
|
||||
body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call)
|
||||
elif fv != nil:
|
||||
let fk = fv.typ.sons[1].flowVarKind
|
||||
if fk == fvInvalid:
|
||||
localError(g.config, f.info, "cannot create a flowVar of type: " &
|
||||
typeToString(fv.typ.sons[1]))
|
||||
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
|
||||
if fk == fvGC: "data" else: "blob", fv.info, g.cache), call)
|
||||
if fk == fvGC:
|
||||
let incRefCall = newNodeI(nkCall, fv.info, 2)
|
||||
incRefCall.sons[0] = newSymNode(getSysMagic(g, fv.info, "GCref", mGCref))
|
||||
incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode,
|
||||
"data", fv.info, g.cache)
|
||||
body.add incRefCall
|
||||
if barrier == nil:
|
||||
# by now 'fv' is shared and thus might have beeen overwritten! we need
|
||||
# to use the thread-local view instead:
|
||||
body.add callCodegenProc(g, "nimFlowVarSignal", threadLocalProm.info,
|
||||
threadLocalProm.newSymNode)
|
||||
else:
|
||||
body.add call
|
||||
if barrier != nil:
|
||||
body.add callCodegenProc(g, "barrierLeave", threadLocalBarrier.info,
|
||||
threadLocalBarrier.newSymNode)
|
||||
|
||||
var params = newNodeI(nkFormalParams, f.info)
|
||||
params.add newNodeI(nkEmpty, f.info)
|
||||
params.add threadParam.newSymNode
|
||||
params.add argsParam.newSymNode
|
||||
|
||||
var t = newType(tyProc, threadParam.owner)
|
||||
t.rawAddSon nil
|
||||
t.rawAddSon threadParam.typ
|
||||
t.rawAddSon argsParam.typ
|
||||
t.n = newNodeI(nkFormalParams, f.info)
|
||||
t.n.add newNodeI(nkEffectList, f.info)
|
||||
t.n.add threadParam.newSymNode
|
||||
t.n.add argsParam.newSymNode
|
||||
|
||||
let name = (if f.kind == nkSym: f.sym.name.s else: genPrefix) & "Wrapper"
|
||||
result = newSym(skProc, getIdent(g.cache, name), argsParam.owner, f.info,
|
||||
argsParam.options)
|
||||
let emptyNode = newNodeI(nkEmpty, f.info)
|
||||
result.ast = newProcNode(nkProcDef, f.info, body = body,
|
||||
params = params, name = newSymNode(result), pattern = emptyNode,
|
||||
genericParams = emptyNode, pragmas = emptyNode,
|
||||
exceptions = emptyNode)
|
||||
result.typ = t
|
||||
|
||||
proc createCastExpr(argsParam: PSym; objType: PType): PNode =
|
||||
result = newNodeI(nkCast, argsParam.info)
|
||||
result.add newNodeI(nkEmpty, argsParam.info)
|
||||
result.add newSymNode(argsParam)
|
||||
result.typ = newType(tyPtr, objType.owner)
|
||||
result.typ.rawAddSon(objType)
|
||||
|
||||
proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym,
|
||||
castExpr, call,
|
||||
varSection, varInit, result: PNode) =
|
||||
let formals = n[0].typ.n
|
||||
let tmpName = getIdent(g.cache, genPrefix)
|
||||
for i in 1 ..< n.len:
|
||||
# we pick n's type here, which hopefully is 'tyArray' and not
|
||||
# 'tyOpenArray':
|
||||
var argType = n[i].typ.skipTypes(abstractInst)
|
||||
if i < formals.len and formals[i].typ.kind in {tyVar, tyLent}:
|
||||
localError(g.config, n[i].info, "'spawn'ed function cannot have a 'var' parameter")
|
||||
#elif containsTyRef(argType):
|
||||
# localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure")
|
||||
|
||||
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
|
||||
var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options)
|
||||
field.typ = argType
|
||||
objType.addField(field, g.cache)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
|
||||
|
||||
let temp = addLocalVar(g, varSection, varInit, objType.owner, argType,
|
||||
indirectAccess(castExpr, field, n.info))
|
||||
call.add(newSymNode(temp))
|
||||
|
||||
proc getRoot*(n: PNode): PSym =
|
||||
## ``getRoot`` takes a *path* ``n``. A path is an lvalue expression
|
||||
## like ``obj.x[i].y``. The *root* of a path is the symbol that can be
|
||||
## determined as the owner; ``obj`` in the example.
|
||||
case n.kind
|
||||
of nkSym:
|
||||
if n.sym.kind in {skVar, skResult, skTemp, skLet, skForVar}:
|
||||
result = n.sym
|
||||
of nkDotExpr, nkBracketExpr, nkHiddenDeref, nkDerefExpr,
|
||||
nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
||||
result = getRoot(n.sons[0])
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
result = getRoot(n.sons[1])
|
||||
of nkCallKinds:
|
||||
if getMagic(n) == mSlice: result = getRoot(n.sons[1])
|
||||
else: discard
|
||||
|
||||
proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
|
||||
result = nkIntLit.newIntNode(value)
|
||||
result.typ = getSysType(g, info, tyInt)
|
||||
|
||||
proc genHigh*(g: ModuleGraph; n: PNode): PNode =
|
||||
if skipTypes(n.typ, abstractVar).kind == tyArray:
|
||||
result = newIntLit(g, n.info, lastOrd(g.config, skipTypes(n.typ, abstractVar)))
|
||||
else:
|
||||
result = newNodeI(nkCall, n.info, 2)
|
||||
result.typ = getSysType(g, n.info, tyInt)
|
||||
result.sons[0] = newSymNode(getSysMagic(g, n.info, "high", mHigh))
|
||||
result.sons[1] = n
|
||||
|
||||
proc genLen*(g: ModuleGraph; n: PNode): PNode =
|
||||
if skipTypes(n.typ, abstractVar).kind == tyArray:
|
||||
result = newIntLit(g, n.info, lastOrd(g.config, skipTypes(n.typ, abstractVar)) + 1)
|
||||
else:
|
||||
result = newNodeI(nkCall, n.info, 2)
|
||||
result.typ = getSysType(g, n.info, tyInt)
|
||||
result.sons[0] = newSymNode(getSysMagic(g, n.info, "len", mLengthSeq))
|
||||
result.sons[1] = n
|
||||
|
||||
proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym;
|
||||
castExpr, call,
|
||||
varSection, varInit, result: PNode) =
|
||||
let formals = n[0].typ.n
|
||||
let tmpName = getIdent(g.cache, genPrefix)
|
||||
# we need to copy the foreign scratch object fields into local variables
|
||||
# for correctness: These are called 'threadLocal' here.
|
||||
for i in 1 ..< n.len:
|
||||
let n = n[i]
|
||||
let argType = skipTypes(if i < formals.len: formals[i].typ else: n.typ,
|
||||
abstractInst)
|
||||
#if containsTyRef(argType):
|
||||
# localError(n.info, "'spawn'ed function cannot refer to 'ref'/closure")
|
||||
|
||||
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
|
||||
var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options)
|
||||
|
||||
if argType.kind in {tyVarargs, tyOpenArray}:
|
||||
# important special case: we always create a zero-copy slice:
|
||||
let slice = newNodeI(nkCall, n.info, 4)
|
||||
slice.typ = n.typ
|
||||
slice.sons[0] = newSymNode(createMagic(g, "slice", mSlice))
|
||||
slice.sons[0].typ = getSysType(g, n.info, tyInt) # fake type
|
||||
var fieldB = newSym(skField, tmpName, objType.owner, n.info, g.config.options)
|
||||
fieldB.typ = getSysType(g, n.info, tyInt)
|
||||
objType.addField(fieldB, g.cache)
|
||||
|
||||
if getMagic(n) == mSlice:
|
||||
let a = genAddrOf(n[1])
|
||||
field.typ = a.typ
|
||||
objType.addField(field, g.cache)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
|
||||
|
||||
var fieldA = newSym(skField, tmpName, objType.owner, n.info, g.config.options)
|
||||
fieldA.typ = getSysType(g, n.info, tyInt)
|
||||
objType.addField(fieldA, g.cache)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2])
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3])
|
||||
|
||||
let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldA.typ,
|
||||
indirectAccess(castExpr, fieldA, n.info),
|
||||
useShallowCopy=true)
|
||||
slice.sons[2] = threadLocal.newSymNode
|
||||
else:
|
||||
let a = genAddrOf(n)
|
||||
field.typ = a.typ
|
||||
objType.addField(field, g.cache)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(g, n))
|
||||
|
||||
slice.sons[2] = newIntLit(g, n.info, 0)
|
||||
# the array itself does not need to go through a thread local variable:
|
||||
slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info))
|
||||
|
||||
let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldB.typ,
|
||||
indirectAccess(castExpr, fieldB, n.info),
|
||||
useShallowCopy=true)
|
||||
slice.sons[3] = threadLocal.newSymNode
|
||||
call.add slice
|
||||
elif (let size = computeSize(g.config, argType); size < 0 or size > 16) and
|
||||
n.getRoot != nil:
|
||||
# it is more efficient to pass a pointer instead:
|
||||
let a = genAddrOf(n)
|
||||
field.typ = a.typ
|
||||
objType.addField(field, g.cache)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
|
||||
let threadLocal = addLocalVar(g, varSection,nil, objType.owner, field.typ,
|
||||
indirectAccess(castExpr, field, n.info),
|
||||
useShallowCopy=true)
|
||||
call.add(genDeref(threadLocal.newSymNode))
|
||||
else:
|
||||
# boring case
|
||||
field.typ = argType
|
||||
objType.addField(field, g.cache)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
|
||||
let threadLocal = addLocalVar(g, varSection, varInit,
|
||||
objType.owner, field.typ,
|
||||
indirectAccess(castExpr, field, n.info),
|
||||
useShallowCopy=true)
|
||||
call.add(threadLocal.newSymNode)
|
||||
|
||||
proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: PType;
|
||||
barrier, dest: PNode = nil): PNode =
|
||||
# if 'barrier' != nil, then it is in a 'parallel' section and we
|
||||
# generate quite different code
|
||||
let n = spawnExpr[^2]
|
||||
let spawnKind = spawnResult(retType, barrier!=nil)
|
||||
case spawnKind
|
||||
of srVoid:
|
||||
internalAssert g.config, dest == nil
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
of srFlowVar:
|
||||
internalAssert g.config, dest == nil
|
||||
result = newNodeIT(nkStmtListExpr, n.info, retType)
|
||||
of srByVar:
|
||||
if dest == nil: localError(g.config, n.info, "'spawn' must not be discarded")
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
|
||||
if n.kind notin nkCallKinds:
|
||||
localError(g.config, n.info, "'spawn' takes a call expression")
|
||||
return
|
||||
if optThreadAnalysis in g.config.globalOptions:
|
||||
if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}:
|
||||
localError(g.config, n.info, "'spawn' takes a GC safe call expression")
|
||||
var
|
||||
threadParam = newSym(skParam, getIdent(g.cache, "thread"), owner, n.info, g.config.options)
|
||||
argsParam = newSym(skParam, getIdent(g.cache, "args"), owner, n.info, g.config.options)
|
||||
block:
|
||||
let ptrType = getSysType(g, n.info, tyPointer)
|
||||
threadParam.typ = ptrType
|
||||
argsParam.typ = ptrType
|
||||
argsParam.position = 1
|
||||
|
||||
var objType = createObj(g, owner, n.info)
|
||||
incl(objType.flags, tfFinal)
|
||||
let castExpr = createCastExpr(argsParam, objType)
|
||||
|
||||
var scratchObj = newSym(skVar, getIdent(g.cache, "scratch"), owner, n.info, g.config.options)
|
||||
block:
|
||||
scratchObj.typ = objType
|
||||
incl(scratchObj.flags, sfFromGeneric)
|
||||
var varSectionB = newNodeI(nkVarSection, n.info)
|
||||
varSectionB.addVar(scratchObj.newSymNode)
|
||||
result.add varSectionB
|
||||
|
||||
var call = newNodeIT(nkCall, n.info, n.typ)
|
||||
var fn = n.sons[0]
|
||||
# templates and macros are in fact valid here due to the nature of
|
||||
# the transformation:
|
||||
if fn.kind == nkClosure:
|
||||
localError(g.config, n.info, "closure in spawn environment is not allowed")
|
||||
if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
|
||||
skFunc, skMethod, skConverter}):
|
||||
# for indirect calls we pass the function pointer in the scratchObj
|
||||
var argType = n[0].typ.skipTypes(abstractInst)
|
||||
var field = newSym(skField, getIdent(g.cache, "fn"), owner, n.info, g.config.options)
|
||||
field.typ = argType
|
||||
objType.addField(field, g.cache)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0])
|
||||
fn = indirectAccess(castExpr, field, n.info)
|
||||
elif fn.kind == nkSym and fn.sym.kind == skIterator:
|
||||
localError(g.config, n.info, "iterator in spawn environment is not allowed")
|
||||
elif fn.typ.callConv == ccClosure:
|
||||
localError(g.config, n.info, "closure in spawn environment is not allowed")
|
||||
|
||||
call.add(fn)
|
||||
var varSection = newNodeI(nkVarSection, n.info)
|
||||
var varInit = newNodeI(nkStmtList, n.info)
|
||||
if barrier.isNil:
|
||||
setupArgsForConcurrency(g, n, objType, scratchObj, castExpr, call,
|
||||
varSection, varInit, result)
|
||||
else:
|
||||
setupArgsForParallelism(g, n, objType, scratchObj, castExpr, call,
|
||||
varSection, varInit, result)
|
||||
|
||||
var barrierAsExpr: PNode = nil
|
||||
if barrier != nil:
|
||||
let typ = newType(tyPtr, owner)
|
||||
typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ)
|
||||
var field = newSym(skField, getIdent(g.cache, "barrier"), owner, n.info, g.config.options)
|
||||
field.typ = typ
|
||||
objType.addField(field, g.cache)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier)
|
||||
barrierAsExpr = indirectAccess(castExpr, field, n.info)
|
||||
|
||||
var fvField, fvAsExpr: PNode = nil
|
||||
if spawnKind == srFlowVar:
|
||||
var field = newSym(skField, getIdent(g.cache, "fv"), owner, n.info, g.config.options)
|
||||
field.typ = retType
|
||||
objType.addField(field, g.cache)
|
||||
fvField = newDotExpr(scratchObj, field)
|
||||
fvAsExpr = indirectAccess(castExpr, field, n.info)
|
||||
# create flowVar:
|
||||
result.add newFastAsgnStmt(fvField, callProc(spawnExpr[^1]))
|
||||
if barrier == nil:
|
||||
result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField.info,
|
||||
fvField)
|
||||
|
||||
elif spawnKind == srByVar:
|
||||
var field = newSym(skField, getIdent(g.cache, "fv"), owner, n.info, g.config.options)
|
||||
field.typ = newType(tyPtr, objType.owner)
|
||||
field.typ.rawAddSon(retType)
|
||||
objType.addField(field, g.cache)
|
||||
fvAsExpr = indirectAccess(castExpr, field, n.info)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest))
|
||||
|
||||
let wrapper = createWrapperProc(g, fn, threadParam, argsParam,
|
||||
varSection, varInit, call,
|
||||
barrierAsExpr, fvAsExpr, spawnKind)
|
||||
result.add callCodegenProc(g, "nimSpawn" & $spawnExpr.len, wrapper.info,
|
||||
wrapper.newSymNode, genAddrOf(scratchObj.newSymNode), nil, spawnExpr)
|
||||
|
||||
if spawnKind == srFlowVar: result.add fvField
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## This module implements helpers for the macro cache.
|
||||
|
||||
import lineinfos, ast, modulegraphs, vmdef, magicsys
|
||||
import lineinfos, ast, modulegraphs, vmdef
|
||||
|
||||
proc recordInc*(c: PCtx; info: TLineInfo; key: string; by: BiggestInt) =
|
||||
var recorded = newNodeI(nkCommentStmt, info)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# Built-in types and compilerprocs are registered here.
|
||||
|
||||
import
|
||||
ast, astalgo, hashes, msgs, platform, nversion, times, idents,
|
||||
ast, astalgo, msgs, platform, idents,
|
||||
modulegraphs, lineinfos
|
||||
|
||||
export createMagic
|
||||
|
||||
@@ -13,22 +13,17 @@ when not defined(nimcore):
|
||||
{.error: "nimcore MUST be defined for Nim's core tooling".}
|
||||
|
||||
import
|
||||
llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
|
||||
os, condsyms, times,
|
||||
wordrecg, sem, semdata, idents, passes, extccomp,
|
||||
llstream, strutils, ast, lexer, syntaxes, options, msgs,
|
||||
condsyms, times,
|
||||
sem, idents, passes, extccomp,
|
||||
cgen, json, nversion,
|
||||
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
|
||||
parser, modules, ccgutils, sigmatch, ropes,
|
||||
platform, nimconf, passaux, depends, vm, idgen,
|
||||
modules,
|
||||
modulegraphs, tables, rod, lineinfos, pathutils
|
||||
|
||||
when not defined(leanCompiler):
|
||||
import jsgen, docgen, docgen2
|
||||
|
||||
from magicsys import resetSysTypes
|
||||
|
||||
proc codegenPass(g: ModuleGraph) =
|
||||
registerPass g, cgenPass
|
||||
|
||||
proc semanticPasses(g: ModuleGraph) =
|
||||
registerPass g, verbosePass
|
||||
registerPass g, semPass
|
||||
@@ -87,6 +82,13 @@ proc commandCompileToC(graph: ModuleGraph) =
|
||||
semanticPasses(graph)
|
||||
registerPass(graph, cgenPass)
|
||||
|
||||
if {optRun, optForceFullMake} * conf.globalOptions == {optRun} or isDefined(conf, "nimBetterRun"):
|
||||
let proj = changeFileExt(conf.projectFull, "")
|
||||
if not changeDetectedViaJsonBuildInstructions(conf, proj):
|
||||
# nothing changed
|
||||
graph.config.notes = graph.config.mainPackageNotes
|
||||
return
|
||||
|
||||
compileProject(graph)
|
||||
if graph.config.errorCounter > 0:
|
||||
return # issue #9933
|
||||
@@ -148,14 +150,6 @@ const evalPasses = [verbosePass, semPass, evalPass]
|
||||
proc evalNim(graph: ModuleGraph; nodes: PNode, module: PSym) =
|
||||
carryPasses(graph, nodes, module, evalPasses)
|
||||
|
||||
proc commandEval(graph: ModuleGraph; exp: string) =
|
||||
if graph.systemModule == nil:
|
||||
interactivePasses(graph)
|
||||
compileSystemModule(graph)
|
||||
let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
|
||||
evalNim(graph, echoExp.parseString(graph.cache, graph.config),
|
||||
makeStdinModule(graph))
|
||||
|
||||
proc commandScan(cache: IdentCache, config: ConfigRef) =
|
||||
var f = addFileExt(AbsoluteFile mainCommandArg(config), NimExt)
|
||||
var stream = llStreamOpen(f, fmRead)
|
||||
@@ -343,8 +337,11 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
conf.cmd = cmdInteractive
|
||||
commandInteractive(graph)
|
||||
of "e":
|
||||
incl conf.globalOptions, optWasNimscript
|
||||
commandEval(graph, mainCommandArg(conf))
|
||||
if not fileExists(conf.projectFull):
|
||||
rawMessage(conf, errGenerated, "NimScript file does not exist: " & conf.projectFull.string)
|
||||
elif not conf.projectFull.string.endsWith(".nims"):
|
||||
rawMessage(conf, errGenerated, "not a NimScript file: " & conf.projectFull.string)
|
||||
# main NimScript logic handled in cmdlinehelper.nim.
|
||||
of "nop", "help":
|
||||
# prevent the "success" message:
|
||||
conf.cmd = cmdDump
|
||||
|
||||
@@ -29,7 +29,7 @@ import ast, intsets, tables, options, lineinfos, hashes, idents,
|
||||
incremental, btrees, md5
|
||||
|
||||
type
|
||||
SigHash* = distinct Md5Digest
|
||||
SigHash* = distinct MD5Digest
|
||||
|
||||
ModuleGraph* = ref object
|
||||
modules*: seq[PSym] ## indexed by int32 fileIdx
|
||||
@@ -98,7 +98,7 @@ const
|
||||
proc toBase64a(s: cstring, len: int): string =
|
||||
## encodes `s` into base64 representation.
|
||||
result = newStringOfCap(((len + 2) div 3) * 4)
|
||||
result.add '_'
|
||||
result.add "__"
|
||||
var i = 0
|
||||
while i < len - 2:
|
||||
let a = ord(s[i])
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
|
||||
import ast, renderer, strutils, msgs, options, idents, os, lineinfos,
|
||||
pathutils, nimblecmd
|
||||
pathutils
|
||||
|
||||
when false:
|
||||
const
|
||||
@@ -162,6 +162,6 @@ proc checkModuleName*(conf: ConfigRef; n: PNode; doLocalError=true): FileIndex =
|
||||
if doLocalError:
|
||||
let m = if modulename.len > 0: modulename else: $n
|
||||
localError(conf, n.info, "cannot open file: " & m)
|
||||
result = InvalidFileIDX
|
||||
result = InvalidFileIdx
|
||||
else:
|
||||
result = fileInfoIdx(conf, fullPath)
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
## Implements the module handling, including the caching of modules.
|
||||
|
||||
import
|
||||
ast, astalgo, magicsys, std / sha1, msgs, cgendata, sigmatch, options,
|
||||
idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod,
|
||||
ast, astalgo, magicsys, msgs, options,
|
||||
idents, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod,
|
||||
lineinfos, pathutils, tables
|
||||
|
||||
proc resetSystemArtifacts*(g: ModuleGraph) =
|
||||
@@ -50,7 +50,6 @@ proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; fil
|
||||
setLen(graph.modules, int(fileIdx) + 1)
|
||||
graph.modules[result.position] = result
|
||||
|
||||
incl(result.flags, sfUsed)
|
||||
initStrTable(result.tab)
|
||||
strTableAdd(result.tab, result) # a module knows itself
|
||||
strTableAdd(packSym.tab, result)
|
||||
@@ -77,8 +76,6 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P
|
||||
if result == nil:
|
||||
result = newModule(graph, fileIdx)
|
||||
result.flags = result.flags + flags
|
||||
if sfMainModule in result.flags:
|
||||
graph.config.mainPackageId = result.owner.id
|
||||
result.id = id
|
||||
registerModule(graph, result)
|
||||
else:
|
||||
@@ -133,12 +130,12 @@ proc wantMainModule*(conf: ConfigRef) =
|
||||
"command expects a filename")
|
||||
conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt))
|
||||
|
||||
proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIDX) =
|
||||
proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) =
|
||||
connectCallbacks(graph)
|
||||
let conf = graph.config
|
||||
wantMainModule(conf)
|
||||
let systemFileIdx = fileInfoIdx(conf, conf.libpath / RelativeFile"system.nim")
|
||||
let projectFile = if projectFileIdx == InvalidFileIDX: conf.projectMainIdx else: projectFileIdx
|
||||
let projectFile = if projectFileIdx == InvalidFileIdx: conf.projectMainIdx else: projectFileIdx
|
||||
graph.importStack.add projectFile
|
||||
if projectFile == systemFileIdx:
|
||||
discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule})
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
|
||||
import
|
||||
options, strutils, os, tables, ropes, platform, terminal, macros,
|
||||
options, strutils, os, tables, ropes, terminal, macros,
|
||||
lineinfos, pathutils
|
||||
|
||||
proc toCChar*(c: char; result: var string) =
|
||||
@@ -40,9 +40,8 @@ proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo =
|
||||
#shallow(result.fullPath)
|
||||
result.projPath = projPath
|
||||
#shallow(result.projPath)
|
||||
let fileName = fullPath.extractFilename
|
||||
result.shortName = fileName.changeFileExt("")
|
||||
result.quotedName = fileName.makeCString
|
||||
result.shortName = fullPath.extractFilename
|
||||
result.quotedName = result.shortName.makeCString
|
||||
result.quotedFullName = fullPath.string.makeCString
|
||||
result.lines = @[]
|
||||
when defined(nimpretty):
|
||||
@@ -96,14 +95,20 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
|
||||
|
||||
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
|
||||
result.fileIndex = fileInfoIdx
|
||||
result.line = uint16(line)
|
||||
result.col = int16(col)
|
||||
if line < int high(uint16):
|
||||
result.line = uint16(line)
|
||||
else:
|
||||
result.line = high(uint16)
|
||||
if col < int high(int16):
|
||||
result.col = int16(col)
|
||||
else:
|
||||
result.col = -1
|
||||
|
||||
proc newLineInfo*(conf: ConfigRef; filename: AbsoluteFile, line, col: int): TLineInfo {.inline.} =
|
||||
result = newLineInfo(fileInfoIdx(conf, filename), line, col)
|
||||
|
||||
|
||||
proc concat(strings: openarray[string]): string =
|
||||
proc concat(strings: openArray[string]): string =
|
||||
var totalLen = 0
|
||||
for s in strings: totalLen += s.len
|
||||
result = newStringOfCap totalLen
|
||||
@@ -155,18 +160,25 @@ proc getInfoContext*(conf: ConfigRef; index: int): TLineInfo =
|
||||
if i >=% L: result = unknownLineInfo()
|
||||
else: result = conf.m.msgContext[i].info
|
||||
|
||||
const
|
||||
commandLineDesc = "command line"
|
||||
|
||||
template toFilename*(conf: ConfigRef; fileIdx: FileIndex): string =
|
||||
if fileIdx.int32 < 0 or conf == nil:
|
||||
"???"
|
||||
(if fileIdx == commandLineIdx: commandLineDesc else: "???")
|
||||
else:
|
||||
if optListFullPaths in conf.globalOptions:
|
||||
conf.m.fileInfos[fileIdx.int32].fullPath.string
|
||||
else:
|
||||
conf.m.fileInfos[fileIdx.int32].projPath.string
|
||||
conf.m.fileInfos[fileIdx.int32].shortName
|
||||
|
||||
proc toProjPath*(conf: ConfigRef; fileIdx: FileIndex): string =
|
||||
if fileIdx.int32 < 0 or conf == nil:
|
||||
(if fileIdx == commandLineIdx: commandLineDesc else: "???")
|
||||
else: conf.m.fileInfos[fileIdx.int32].projPath.string
|
||||
|
||||
proc toFullPath*(conf: ConfigRef; fileIdx: FileIndex): string =
|
||||
if fileIdx.int32 < 0 or conf == nil: result = "???"
|
||||
else: result = conf.m.fileInfos[fileIdx.int32].fullPath.string
|
||||
if fileIdx.int32 < 0 or conf == nil:
|
||||
result = (if fileIdx == commandLineIdx: commandLineDesc else: "???")
|
||||
else:
|
||||
result = conf.m.fileInfos[fileIdx.int32].fullPath.string
|
||||
|
||||
proc setDirtyFile*(conf: ConfigRef; fileIdx: FileIndex; filename: AbsoluteFile) =
|
||||
assert fileIdx.int32 >= 0
|
||||
@@ -183,7 +195,7 @@ proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string =
|
||||
|
||||
proc toFullPathConsiderDirty*(conf: ConfigRef; fileIdx: FileIndex): AbsoluteFile =
|
||||
if fileIdx.int32 < 0:
|
||||
result = AbsoluteFile"???"
|
||||
result = AbsoluteFile(if fileIdx == commandLineIdx: commandLineDesc else: "???")
|
||||
elif not conf.m.fileInfos[fileIdx.int32].dirtyFile.isEmpty:
|
||||
result = conf.m.fileInfos[fileIdx.int32].dirtyFile
|
||||
else:
|
||||
@@ -192,22 +204,28 @@ proc toFullPathConsiderDirty*(conf: ConfigRef; fileIdx: FileIndex): AbsoluteFile
|
||||
template toFilename*(conf: ConfigRef; info: TLineInfo): string =
|
||||
toFilename(conf, info.fileIndex)
|
||||
|
||||
template toProjPath*(conf: ConfigRef; info: TLineInfo): string =
|
||||
toProjPath(conf, info.fileIndex)
|
||||
|
||||
template toFullPath*(conf: ConfigRef; info: TLineInfo): string =
|
||||
toFullPath(conf, info.fileIndex)
|
||||
|
||||
template toFullPathConsiderDirty*(conf: ConfigRef; info: TLineInfo): string =
|
||||
string toFullPathConsiderDirty(conf, info.fileIndex)
|
||||
|
||||
proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
|
||||
if info.fileIndex.int32 < 0:
|
||||
result = "???"
|
||||
return
|
||||
let absPath = conf.m.fileInfos[info.fileIndex.int32].fullPath.string
|
||||
if optListFullPaths in conf.globalOptions:
|
||||
result = absPath
|
||||
else:
|
||||
let relPath = conf.m.fileInfos[info.fileIndex.int32].projPath.string
|
||||
result = if relPath.count("..") > 2: absPath else: relPath
|
||||
proc toMsgFilename*(conf: ConfigRef; info: FileIndex): string =
|
||||
let
|
||||
absPath = toFullPath(conf, info)
|
||||
relPath = toProjPath(conf, info)
|
||||
result = if (optListFullPaths in conf.globalOptions) or
|
||||
(relPath.len > absPath.len) or
|
||||
(relPath.count("..") > 2):
|
||||
absPath
|
||||
else:
|
||||
relPath
|
||||
|
||||
template toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
|
||||
toMsgFilename(conf, info.fileIndex)
|
||||
|
||||
proc toLinenumber*(info: TLineInfo): int {.inline.} =
|
||||
result = int info.line
|
||||
@@ -215,12 +233,9 @@ proc toLinenumber*(info: TLineInfo): int {.inline.} =
|
||||
proc toColumn*(info: TLineInfo): int {.inline.} =
|
||||
result = info.col
|
||||
|
||||
proc toFileLine*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
|
||||
result = toFilename(conf, info) & ":" & $info.line
|
||||
|
||||
proc toFileLineCol*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
|
||||
# consider calling `helpers.lineInfoToString` instead
|
||||
result = toFilename(conf, info) & "(" & $info.line & ", " &
|
||||
result = toMsgFilename(conf, info) & "(" & $info.line & ", " &
|
||||
$(info.col + ColOffset) & ")"
|
||||
|
||||
proc `$`*(conf: ConfigRef; info: TLineInfo): string = toFileLineCol(conf, info)
|
||||
@@ -452,7 +467,8 @@ proc sourceLine*(conf: ConfigRef; i: TLineInfo): string =
|
||||
proc writeSurroundingSrc(conf: ConfigRef; info: TLineInfo) =
|
||||
const indent = " "
|
||||
msgWriteln(conf, indent & $sourceLine(conf, info))
|
||||
msgWriteln(conf, indent & spaces(info.col) & '^')
|
||||
if info.col >= 0:
|
||||
msgWriteln(conf, indent & spaces(info.col) & '^')
|
||||
|
||||
proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||
let title = case msg
|
||||
@@ -532,7 +548,7 @@ proc localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
proc localError*(conf: ConfigRef; info: TLineInfo, arg: string) =
|
||||
liMessage(conf, info, errGenerated, arg, doNothing)
|
||||
|
||||
proc localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openarray[string]) =
|
||||
proc localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openArray[string]) =
|
||||
localError(conf, info, format % params)
|
||||
|
||||
proc message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
@@ -556,8 +572,9 @@ template internalAssert*(conf: ConfigRef, e: bool) =
|
||||
if not e: internalError(conf, $instantiationInfo())
|
||||
|
||||
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
|
||||
assert i.fileIndex.int32 >= 0
|
||||
if optExcessiveStackTrace in conf.globalOptions:
|
||||
if i.fileIndex.int32 < 0:
|
||||
result = makeCString "???"
|
||||
elif optExcessiveStackTrace in conf.globalOptions:
|
||||
result = conf.m.fileInfos[i.fileIndex.int32].quotedFullName
|
||||
else:
|
||||
result = conf.m.fileInfos[i.fileIndex.int32].quotedName
|
||||
@@ -577,3 +594,10 @@ proc listHints*(conf: ConfigRef) =
|
||||
if hint in conf.notes: "x" else: " ",
|
||||
lineinfos.HintsToStr[ord(hint) - ord(hintMin)]
|
||||
])
|
||||
|
||||
proc lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string) =
|
||||
let m = "'$2' should be: '$1'" % [beau, got]
|
||||
if optStyleError in conf.globalOptions:
|
||||
localError(conf, info, m)
|
||||
else:
|
||||
message(conf, info, hintName, m)
|
||||
|
||||
@@ -7,6 +7,8 @@ define:nimcore
|
||||
#define:nimIncremental
|
||||
#import:"$projectpath/testability"
|
||||
|
||||
#define:staticSqlite
|
||||
|
||||
@if windows:
|
||||
cincludes: "$lib/wrappers/libffi/common"
|
||||
@end
|
||||
@@ -14,6 +16,10 @@ define:nimcore
|
||||
define:useStdoutAsStdmsg
|
||||
define:nimOldCaseObjects
|
||||
|
||||
@if nimHasStyleChecks:
|
||||
styleCheck:error
|
||||
@end
|
||||
|
||||
#define:useNodeIds
|
||||
#gc:markAndSweep
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@ when defined(i386) and defined(windows) and defined(vcc):
|
||||
{.link: "../icons/nim-i386-windows-vcc.res".}
|
||||
|
||||
import
|
||||
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
|
||||
extccomp, strutils, os, osproc, platform, main, parseopt,
|
||||
scriptconfig, idents, modulegraphs, lineinfos, cmdlinehelper,
|
||||
commands, options, msgs,
|
||||
extccomp, strutils, os, main, parseopt,
|
||||
idents, lineinfos, cmdlinehelper,
|
||||
pathutils
|
||||
|
||||
include nodejs
|
||||
@@ -47,13 +47,21 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
|
||||
parseopt.next(p)
|
||||
case p.kind
|
||||
of cmdEnd: break
|
||||
of cmdLongoption, cmdShortOption:
|
||||
of cmdLongOption, cmdShortOption:
|
||||
config.commandLine.add " "
|
||||
config.commandLine.add p.key
|
||||
if p.val.len > 0:
|
||||
config.commandLine.add ':'
|
||||
config.commandLine.add p.val
|
||||
|
||||
if p.key == " ":
|
||||
p.key = "-"
|
||||
if processArgument(pass, p, argsCount, config): break
|
||||
else:
|
||||
processSwitch(pass, p, config)
|
||||
of cmdArgument:
|
||||
config.commandLine.add " "
|
||||
config.commandLine.add p.key
|
||||
if processArgument(pass, p, argsCount, config): break
|
||||
if pass == passCmd2:
|
||||
if {optRun, optWasNimscript} * config.globalOptions == {} and
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# This module handles the reading of the config file.
|
||||
|
||||
import
|
||||
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
|
||||
llstream, commands, os, strutils, msgs, lexer,
|
||||
options, idents, wordrecg, strtabs, lineinfos, pathutils
|
||||
|
||||
# ---------------- configuration file parser -----------------------------
|
||||
@@ -123,31 +123,31 @@ proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack
|
||||
of wEnd: doEnd(L, tok, condStack)
|
||||
of wWrite:
|
||||
ppGetTok(L, tok)
|
||||
msgs.msgWriteln(config, strtabs.`%`(tokToStr(tok), config.configVars,
|
||||
msgs.msgWriteln(config, strtabs.`%`($tok, config.configVars,
|
||||
{useEnvironment, useKey}))
|
||||
ppGetTok(L, tok)
|
||||
else:
|
||||
case tok.ident.s.normalize
|
||||
of "putenv":
|
||||
ppGetTok(L, tok)
|
||||
var key = tokToStr(tok)
|
||||
var key = $tok
|
||||
ppGetTok(L, tok)
|
||||
os.putEnv(key, tokToStr(tok))
|
||||
os.putEnv(key, $tok)
|
||||
ppGetTok(L, tok)
|
||||
of "prependenv":
|
||||
ppGetTok(L, tok)
|
||||
var key = tokToStr(tok)
|
||||
var key = $tok
|
||||
ppGetTok(L, tok)
|
||||
os.putEnv(key, tokToStr(tok) & os.getEnv(key))
|
||||
os.putEnv(key, $tok & os.getEnv(key))
|
||||
ppGetTok(L, tok)
|
||||
of "appendenv":
|
||||
ppGetTok(L, tok)
|
||||
var key = tokToStr(tok)
|
||||
var key = $tok
|
||||
ppGetTok(L, tok)
|
||||
os.putEnv(key, os.getEnv(key) & tokToStr(tok))
|
||||
os.putEnv(key, os.getEnv(key) & $tok)
|
||||
ppGetTok(L, tok)
|
||||
else:
|
||||
lexMessage(L, errGenerated, "invalid directive: '$1'" % tokToStr(tok))
|
||||
lexMessage(L, errGenerated, "invalid directive: '$1'" % $tok)
|
||||
|
||||
proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
|
||||
ppGetTok(L, tok)
|
||||
@@ -156,7 +156,7 @@ proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var s
|
||||
|
||||
proc checkSymbol(L: TLexer, tok: TToken) =
|
||||
if tok.tokType notin {tkSymbol..tkInt64Lit, tkStrLit..tkTripleStrLit}:
|
||||
lexMessage(L, errGenerated, "expected identifier, but got: " & tokToStr(tok))
|
||||
lexMessage(L, errGenerated, "expected identifier, but got: " & $tok)
|
||||
|
||||
proc parseAssignment(L: var TLexer, tok: var TToken;
|
||||
config: ConfigRef; condStack: var seq[bool]) =
|
||||
@@ -164,21 +164,21 @@ proc parseAssignment(L: var TLexer, tok: var TToken;
|
||||
confTok(L, tok, config, condStack) # skip unnecessary prefix
|
||||
var info = getLineInfo(L, tok) # save for later in case of an error
|
||||
checkSymbol(L, tok)
|
||||
var s = tokToStr(tok)
|
||||
var s = $tok
|
||||
confTok(L, tok, config, condStack) # skip symbol
|
||||
var val = ""
|
||||
while tok.tokType == tkDot:
|
||||
add(s, '.')
|
||||
confTok(L, tok, config, condStack)
|
||||
checkSymbol(L, tok)
|
||||
add(s, tokToStr(tok))
|
||||
add(s, $tok)
|
||||
confTok(L, tok, config, condStack)
|
||||
if tok.tokType == tkBracketLe:
|
||||
# BUGFIX: val, not s!
|
||||
confTok(L, tok, config, condStack)
|
||||
checkSymbol(L, tok)
|
||||
add(val, '[')
|
||||
add(val, tokToStr(tok))
|
||||
add(val, $tok)
|
||||
confTok(L, tok, config, condStack)
|
||||
if tok.tokType == tkBracketRi: confTok(L, tok, config, condStack)
|
||||
else: lexMessage(L, errGenerated, "expected closing ']'")
|
||||
@@ -188,12 +188,12 @@ proc parseAssignment(L: var TLexer, tok: var TToken;
|
||||
if len(val) > 0: add(val, ':')
|
||||
confTok(L, tok, config, condStack) # skip ':' or '=' or '%'
|
||||
checkSymbol(L, tok)
|
||||
add(val, tokToStr(tok))
|
||||
add(val, $tok)
|
||||
confTok(L, tok, config, condStack) # skip symbol
|
||||
while tok.ident != nil and tok.ident.s == "&":
|
||||
confTok(L, tok, config, condStack)
|
||||
checkSymbol(L, tok)
|
||||
add(val, tokToStr(tok))
|
||||
add(val, $tok)
|
||||
confTok(L, tok, config, condStack)
|
||||
if percent:
|
||||
processSwitch(s, strtabs.`%`(val, config.configVars,
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
#
|
||||
|
||||
import strutils except Letters
|
||||
import lexbase, streams
|
||||
import ".." / [ast, msgs, lineinfos, idents, options, linter]
|
||||
from os import splitFile
|
||||
|
||||
proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PIdent) =
|
||||
let line = sourceLine(conf, info)
|
||||
|
||||
@@ -10,15 +10,14 @@
|
||||
# this unit handles Nim sets; it implements symbolic sets
|
||||
|
||||
import
|
||||
ast, astalgo, trees, nversion, lineinfos, platform, bitsets, types, renderer,
|
||||
options
|
||||
ast, astalgo, lineinfos, bitsets, types, options
|
||||
|
||||
proc inSet*(s: PNode, elem: PNode): bool =
|
||||
assert s.kind == nkCurly
|
||||
if s.kind != nkCurly:
|
||||
#internalError(s.info, "inSet")
|
||||
return false
|
||||
for i in 0 ..< sonsLen(s):
|
||||
for i in 0 ..< len(s):
|
||||
if s.sons[i].kind == nkRange:
|
||||
if leValue(s.sons[i].sons[0], elem) and
|
||||
leValue(elem, s.sons[i].sons[1]):
|
||||
@@ -48,7 +47,7 @@ proc someInSet*(s: PNode, a, b: PNode): bool =
|
||||
if s.kind != nkCurly:
|
||||
#internalError(s.info, "SomeInSet")
|
||||
return false
|
||||
for i in 0 ..< sonsLen(s):
|
||||
for i in 0 ..< len(s):
|
||||
if s.sons[i].kind == nkRange:
|
||||
if leValue(s.sons[i].sons[0], b) and leValue(b, s.sons[i].sons[1]) or
|
||||
leValue(s.sons[i].sons[0], a) and leValue(a, s.sons[i].sons[1]):
|
||||
@@ -60,17 +59,17 @@ proc someInSet*(s: PNode, a, b: PNode): bool =
|
||||
result = false
|
||||
|
||||
proc toBitSet*(conf: ConfigRef; s: PNode, b: var TBitSet) =
|
||||
var first, j: BiggestInt
|
||||
var first, j: Int128
|
||||
first = firstOrd(conf, s.typ.sons[0])
|
||||
bitSetInit(b, int(getSize(conf, s.typ)))
|
||||
for i in 0 ..< sonsLen(s):
|
||||
for i in 0 ..< len(s):
|
||||
if s.sons[i].kind == nkRange:
|
||||
j = getOrdValue(s.sons[i].sons[0])
|
||||
while j <= getOrdValue(s.sons[i].sons[1]):
|
||||
bitSetIncl(b, j - first)
|
||||
j = getOrdValue(s.sons[i].sons[0], first)
|
||||
while j <= getOrdValue(s.sons[i].sons[1], first):
|
||||
bitSetIncl(b, toInt64(j - first))
|
||||
inc(j)
|
||||
else:
|
||||
bitSetIncl(b, getOrdValue(s.sons[i]) - first)
|
||||
bitSetIncl(b, toInt64(getOrdValue(s.sons[i]) - first))
|
||||
|
||||
proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): PNode =
|
||||
var
|
||||
@@ -78,7 +77,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
|
||||
elemType: PType
|
||||
n: PNode
|
||||
elemType = settype.sons[0]
|
||||
first = firstOrd(conf, elemType)
|
||||
first = firstOrd(conf, elemType).toInt64
|
||||
result = newNodeI(nkCurly, info)
|
||||
result.typ = settype
|
||||
result.info = info
|
||||
@@ -91,7 +90,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
|
||||
inc(b)
|
||||
if (b >= len(s) * ElemSize) or not bitSetIn(s, b): break
|
||||
dec(b)
|
||||
let aa = newIntTypeNode(nkIntLit, a + first, elemType)
|
||||
let aa = newIntTypeNode(a + first, elemType)
|
||||
aa.info = info
|
||||
if a == b:
|
||||
addSon(result, aa)
|
||||
@@ -99,7 +98,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
|
||||
n = newNodeI(nkRange, info)
|
||||
n.typ = elemType
|
||||
addSon(n, aa)
|
||||
let bb = newIntTypeNode(nkIntLit, b + first, elemType)
|
||||
let bb = newIntTypeNode(b + first, elemType)
|
||||
bb.info = info
|
||||
addSon(n, bb)
|
||||
addSon(result, n)
|
||||
@@ -150,7 +149,7 @@ proc setHasRange*(s: PNode): bool =
|
||||
assert s.kind == nkCurly
|
||||
if s.kind != nkCurly:
|
||||
return false
|
||||
for i in 0 ..< sonsLen(s):
|
||||
for i in 0 ..< len(s):
|
||||
if s.sons[i].kind == nkRange:
|
||||
return true
|
||||
result = false
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import os
|
||||
|
||||
proc findNodeJs*(): string =
|
||||
proc findNodeJs*(): string {.inline.} =
|
||||
## Find NodeJS executable and return it as a string.
|
||||
result = findExe("nodejs")
|
||||
if result == "":
|
||||
result = findExe("node")
|
||||
if result == "":
|
||||
result = findExe("iojs")
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
|
||||
import
|
||||
os, strutils, strtabs, osproc, sets, lineinfos, platform,
|
||||
os, strutils, strtabs, sets, lineinfos, platform,
|
||||
prefixmatches, pathutils
|
||||
|
||||
from terminal import isatty
|
||||
@@ -25,12 +25,11 @@ type # please make sure we have under 32 options
|
||||
# (improves code efficiency a lot!)
|
||||
TOption* = enum # **keep binary compatible**
|
||||
optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck,
|
||||
optOverflowCheck, optNilCheck,
|
||||
optNaNCheck, optInfCheck, optMoveCheck,
|
||||
optOverflowCheck, optNilCheck, optRefCheck,
|
||||
optNaNCheck, optInfCheck, optStyleCheck,
|
||||
optAssert, optLineDir, optWarns, optHints,
|
||||
optOptimizeSpeed, optOptimizeSize, optStackTrace, # stack tracing support
|
||||
optLineTrace, # line tracing support (includes stack tracing)
|
||||
optEndb, # embedded debugger
|
||||
optByRef, # use pass by ref for objects
|
||||
# (for interfacing with C)
|
||||
optProfiler, # profiler turned on
|
||||
@@ -78,12 +77,13 @@ type # please make sure we have under 32 options
|
||||
optWholeProject # for 'doc2': output any dependency
|
||||
optDocInternal # generate documentation for non-exported symbols
|
||||
optMixedMode # true if some module triggered C++ codegen
|
||||
optListFullPaths # use full paths in toMsgFilename, toFilename
|
||||
optListFullPaths # use full paths in toMsgFilename
|
||||
optNoNimblePath
|
||||
optHotCodeReloading
|
||||
optDynlibOverrideAll
|
||||
optNimV2
|
||||
optMultiMethods
|
||||
optNimV019
|
||||
|
||||
TGlobalOptions* = set[TGlobalOption]
|
||||
|
||||
@@ -110,7 +110,7 @@ type
|
||||
cmdJsonScript # compile a .json build file
|
||||
TStringSeq* = seq[string]
|
||||
TGCMode* = enum # the selected GC
|
||||
gcNone, gcBoehm, gcRegions, gcMarkAndSweep, gcDestructors,
|
||||
gcUnselected, gcNone, gcBoehm, gcRegions, gcMarkAndSweep, gcDestructors,
|
||||
gcRefc, gcV2, gcGo
|
||||
# gcRefc and the GCs that follow it use a write barrier,
|
||||
# as far as usesWriteBarrier() is concerned
|
||||
@@ -135,6 +135,12 @@ type
|
||||
## which itself requires `nimble install libffi`, see #10150
|
||||
## Note: this feature can't be localized with {.push.}
|
||||
|
||||
LegacyFeature* = enum
|
||||
allowSemcheckedAstModification,
|
||||
## Allows to modify a NimNode where the type has already been
|
||||
## flaged with nfSem. If you actually do this, it will cause
|
||||
## bugs.
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, writeOnlySf, readOnlySf, v2Sf
|
||||
|
||||
@@ -149,7 +155,7 @@ type
|
||||
Cfile* = object
|
||||
nimname*: string
|
||||
cname*, obj*: AbsoluteFile
|
||||
flags*: set[CFileFlag]
|
||||
flags*: set[CfileFlag]
|
||||
CfileList* = seq[Cfile]
|
||||
|
||||
Suggest* = ref object
|
||||
@@ -196,6 +202,7 @@ type
|
||||
cppDefines*: HashSet[string] # (*)
|
||||
headerFile*: string
|
||||
features*: set[Feature]
|
||||
legacyFeatures*: set[LegacyFeature]
|
||||
arguments*: string ## the arguments to be passed to the program that
|
||||
## should be run
|
||||
ideCmd*: IdeCmd
|
||||
@@ -229,6 +236,7 @@ type
|
||||
projectMainIdx*: FileIndex # the canonical path id of the main module
|
||||
command*: string # the main command (e.g. cc, check, scan, etc)
|
||||
commandArgs*: seq[string] # any arguments after the main command
|
||||
commandLine*: string
|
||||
keepComments*: bool # whether the parser needs to keep comments
|
||||
implicitImports*: seq[string] # modules that are to be implicitly imported
|
||||
implicitIncludes*: seq[string] # modules that are to be implicitly included
|
||||
@@ -246,7 +254,7 @@ type
|
||||
compileOptionsCmd*: seq[string]
|
||||
linkOptions*: string # (*)
|
||||
compileOptions*: string # (*)
|
||||
ccompilerpath*: string
|
||||
cCompilerPath*: string
|
||||
toCompile*: CfileList # (*)
|
||||
suggestionResultHook*: proc (result: Suggest) {.closure.}
|
||||
suggestVersion*: int
|
||||
@@ -270,12 +278,12 @@ const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, par
|
||||
const
|
||||
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
|
||||
optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck,
|
||||
optMoveCheck}
|
||||
optStyleCheck, optRefCheck}
|
||||
|
||||
DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck,
|
||||
optBoundsCheck, optOverflowCheck, optAssert, optWarns,
|
||||
optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck,
|
||||
optHints, optStackTrace, optLineTrace,
|
||||
optTrMacros, optNilCheck, optMoveCheck}
|
||||
optTrMacros, optNilCheck, optStyleCheck}
|
||||
DefaultGlobalOptions* = {optThreadAnalysis,
|
||||
optExcessiveStackTrace, optListFullPaths}
|
||||
|
||||
@@ -314,7 +322,7 @@ proc newConfigRef*(): ConfigRef =
|
||||
m: initMsgConfig(),
|
||||
evalExpr: "",
|
||||
cppDefines: initHashSet[string](),
|
||||
headerFile: "", features: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic,
|
||||
headerFile: "", features: {}, legacyFeatures: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic,
|
||||
hintQuitCalled, hintExecuting},
|
||||
notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1],
|
||||
configVars: newStringTable(modeStyleInsensitive),
|
||||
@@ -335,6 +343,7 @@ proc newConfigRef*(): ConfigRef =
|
||||
projectMainIdx: FileIndex(0'i32), # the canonical path id of the main module
|
||||
command: "", # the main command (e.g. cc, check, scan, etc)
|
||||
commandArgs: @[], # any arguments after the main command
|
||||
commandLine: "",
|
||||
keepComments: true, # whether the parser needs to keep comments
|
||||
implicitImports: @[], # modules that are to be implicitly imported
|
||||
implicitIncludes: @[], # modules that are to be implicitly included
|
||||
@@ -388,7 +397,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||
result = conf.target.targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
|
||||
osQnx, osAtari, osAix,
|
||||
osHaiku, osVxWorks, osSolaris, osNetbsd,
|
||||
osFreebsd, osOpenbsd, osDragonfly, osMacosx,
|
||||
osFreebsd, osOpenbsd, osDragonfly, osMacosx, osIos,
|
||||
osAndroid, osNintendoSwitch}
|
||||
of "linux":
|
||||
result = conf.target.targetOS in {osLinux, osAndroid}
|
||||
@@ -398,8 +407,10 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||
result = platform.OS[conf.target.targetOS].props.contains(ospLacksThreadVars)
|
||||
of "msdos": result = conf.target.targetOS == osDos
|
||||
of "mswindows", "win32": result = conf.target.targetOS == osWindows
|
||||
of "macintosh": result = conf.target.targetOS in {osMacos, osMacosx}
|
||||
of "osx": result = conf.target.targetOS == osMacosx
|
||||
of "macintosh":
|
||||
result = conf.target.targetOS in {osMacos, osMacosx, osIos}
|
||||
of "osx":
|
||||
result = conf.target.targetOS in {osMacosx, osIos}
|
||||
of "sunos": result = conf.target.targetOS == osSolaris
|
||||
of "nintendoswitch":
|
||||
result = conf.target.targetOS == osNintendoSwitch
|
||||
@@ -462,12 +473,16 @@ proc getOutFile*(conf: ConfigRef; filename: RelativeFile, ext: string): Absolute
|
||||
conf.outDir / changeFileExt(filename, ext)
|
||||
|
||||
proc absOutFile*(conf: ConfigRef): AbsoluteFile =
|
||||
conf.outDir / conf.outFile
|
||||
result = conf.outDir / conf.outFile
|
||||
if dirExists(result.string):
|
||||
result.string.add ".out"
|
||||
|
||||
proc prepareToWriteOutput*(conf: ConfigRef): AbsoluteFile =
|
||||
## Create the output directory and returns a full path to the output file
|
||||
createDir conf.outDir
|
||||
return conf.outDir / conf.outFile
|
||||
result = conf.outDir / conf.outFile
|
||||
if dirExists(result.string):
|
||||
result.string.add ".out"
|
||||
|
||||
proc getPrefixDir*(conf: ConfigRef): AbsoluteDir =
|
||||
## Gets the prefix dir, usually the parent directory where the binary resides.
|
||||
@@ -498,7 +513,7 @@ proc setDefaultLibpath*(conf: ConfigRef) =
|
||||
# Find out if $nim/../../lib/system.nim exists.
|
||||
let parentNimLibPath = realNimPath.parentDir.parentDir / "lib"
|
||||
if not fileExists(conf.libpath.string / "system.nim") and
|
||||
fileExists(parentNimlibPath / "system.nim"):
|
||||
fileExists(parentNimLibPath / "system.nim"):
|
||||
conf.libpath = AbsoluteDir parentNimLibPath
|
||||
|
||||
proc canonicalizePath*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile =
|
||||
@@ -590,7 +605,7 @@ proc rawFindFile2(conf: ConfigRef; f: RelativeFile): AbsoluteFile =
|
||||
result = it / f
|
||||
if fileExists(result):
|
||||
# bring to front
|
||||
for j in countDown(i,1):
|
||||
for j in countdown(i, 1):
|
||||
swap(conf.lazyPaths[j], conf.lazyPaths[j-1])
|
||||
|
||||
return canonicalizePath(conf, result)
|
||||
@@ -709,3 +724,13 @@ proc `$`*(c: IdeCmd): string =
|
||||
of ideOutline: "outline"
|
||||
of ideKnown: "known"
|
||||
of ideMsg: "msg"
|
||||
|
||||
proc floatInt64Align*(conf: ConfigRef): int16 =
|
||||
## Returns either 4 or 8 depending on reasons.
|
||||
if conf.target.targetCPU == cpuI386:
|
||||
#on Linux/BSD i386, double are aligned to 4bytes (except with -malign-double)
|
||||
if conf.target.targetOS != osWindows:
|
||||
# on i386 for all known POSIX systems, 64bits ints are aligned
|
||||
# to 4bytes (except with -malign-double)
|
||||
return 4
|
||||
return 8
|
||||
|
||||
@@ -39,13 +39,11 @@ proc getPackageName*(conf: ConfigRef; path: string): string =
|
||||
if parents <= 0: break
|
||||
|
||||
proc fakePackageName*(conf: ConfigRef; path: AbsoluteFile): string =
|
||||
# foo/../bar becomes foo7_7bar
|
||||
result = relativeTo(path, conf.projectPath, '/').string.multiReplace(
|
||||
{"/": "7", "..": "_", "7": "77", "_": "__", ":": "8", "8": "88"})
|
||||
# foo-#head/../bar becomes @foo-@hhead@s..@sbar
|
||||
result = "@m" & relativeTo(path, conf.projectPath, '/').string.multiReplace({"/": "@s", "#": "@h", "@": "@@"})
|
||||
|
||||
proc demanglePackageName*(path: string): string =
|
||||
result = path.multiReplace(
|
||||
{"88": "8", "8": ":", "77": "7", "__": "_", "_7": "../", "7": "/"})
|
||||
result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": ""})
|
||||
|
||||
proc withPackageName*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile =
|
||||
let x = getPackageName(conf, path.string)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## This module implements the pattern matching features for term rewriting
|
||||
## macro support.
|
||||
|
||||
import strutils, ast, astalgo, types, msgs, idents, renderer, wordrecg, trees,
|
||||
import strutils, ast, types, msgs, idents, renderer, wordrecg, trees,
|
||||
options
|
||||
|
||||
# we precompile the pattern here for efficiency into some internal
|
||||
@@ -218,20 +218,22 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
||||
of nkSym:
|
||||
let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet, skForVar}
|
||||
else: {skVar, skResult, skTemp}
|
||||
if n.sym.kind in kinds:
|
||||
if n.sym.kind == skParam and n.sym.typ.kind in {tyVar, tySink}:
|
||||
result = arLValue
|
||||
elif isUnsafeAddr and n.sym.kind == skParam:
|
||||
result = arLValue
|
||||
elif n.sym.kind in kinds:
|
||||
if owner != nil and owner == n.sym.owner and
|
||||
sfGlobal notin n.sym.flags:
|
||||
result = arLocalLValue
|
||||
else:
|
||||
result = arLValue
|
||||
elif n.sym.kind == skParam and n.sym.typ.kind == tyVar:
|
||||
result = arLValue
|
||||
elif n.sym.kind == skType:
|
||||
let t = n.sym.typ.skipTypes({tyTypeDesc})
|
||||
if t.kind == tyVar: result = arStrange
|
||||
of nkDotExpr:
|
||||
let t = skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc})
|
||||
if t.kind in {tyVar, tyPtr, tyRef}:
|
||||
if t.kind in {tyVar, tySink, tyPtr, tyRef}:
|
||||
result = arLValue
|
||||
elif isUnsafeAddr and t.kind == tyLent:
|
||||
result = arLValue
|
||||
@@ -242,7 +244,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
||||
result = arDiscriminant
|
||||
of nkBracketExpr:
|
||||
let t = skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc})
|
||||
if t.kind in {tyVar, tyPtr, tyRef}:
|
||||
if t.kind in {tyVar, tySink, tyPtr, tyRef}:
|
||||
result = arLValue
|
||||
elif isUnsafeAddr and t.kind == tyLent:
|
||||
result = arLValue
|
||||
|
||||
@@ -27,7 +27,7 @@ when isMainModule:
|
||||
outp.close
|
||||
|
||||
import
|
||||
llstream, lexer, idents, strutils, ast, astalgo, msgs, options, lineinfos,
|
||||
llstream, lexer, idents, strutils, ast, msgs, options, lineinfos,
|
||||
pathutils
|
||||
|
||||
when defined(nimpretty):
|
||||
@@ -147,10 +147,17 @@ template withInd(p, body: untyped) =
|
||||
body
|
||||
p.currInd = oldInd
|
||||
|
||||
template newlineWasSplitting(p: var TParser) =
|
||||
when defined(nimpretty):
|
||||
layouter.newlineWasSplitting(p.em)
|
||||
|
||||
template realInd(p): bool = p.tok.indent > p.currInd
|
||||
template sameInd(p): bool = p.tok.indent == p.currInd
|
||||
template sameOrNoInd(p): bool = p.tok.indent == p.currInd or p.tok.indent < 0
|
||||
|
||||
proc validInd(p: var TParser): bool {.inline.} =
|
||||
result = p.tok.indent < 0 or p.tok.indent > p.currInd
|
||||
|
||||
proc rawSkipComment(p: var TParser, node: PNode) =
|
||||
if p.tok.tokType == tkComment:
|
||||
if node != nil:
|
||||
@@ -339,17 +346,17 @@ proc parseSymbol(p: var TParser, mode = smNormal): PNode =
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
break
|
||||
of tkOpr, tkDot, tkDotDot, tkEquals, tkParLe..tkParDotRi:
|
||||
let lineinfo = parLineinfo(p)
|
||||
let lineinfo = parLineInfo(p)
|
||||
var accm = ""
|
||||
while p.tok.tokType in {tkOpr, tkDot, tkDotDot, tkEquals,
|
||||
tkParLe..tkParDotRi}:
|
||||
accm.add(tokToStr(p.tok))
|
||||
accm.add($p.tok)
|
||||
getTok(p)
|
||||
let node = newNodeI(nkIdent, lineinfo)
|
||||
node.ident = p.lex.cache.getIdent(accm)
|
||||
result.add(node)
|
||||
of tokKeywordLow..tokKeywordHigh, tkSymbol, tkIntLit..tkCharLit:
|
||||
result.add(newIdentNodeP(p.lex.cache.getIdent(tokToStr(p.tok)), p))
|
||||
result.add(newIdentNodeP(p.lex.cache.getIdent($p.tok), p))
|
||||
getTok(p)
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
@@ -367,6 +374,7 @@ proc colonOrEquals(p: var TParser, a: PNode): PNode =
|
||||
if p.tok.tokType == tkColon:
|
||||
result = newNodeP(nkExprColonExpr, p)
|
||||
getTok(p)
|
||||
newlineWasSplitting(p)
|
||||
#optInd(p, result)
|
||||
addSon(result, a)
|
||||
addSon(result, parseExpr(p))
|
||||
@@ -903,6 +911,9 @@ proc parsePragma(p: var TParser): PNode =
|
||||
#| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
|
||||
result = newNodeP(nkPragma, p)
|
||||
inc p.inPragma
|
||||
when defined(nimpretty):
|
||||
inc p.em.doIndentMore
|
||||
inc p.em.keepIndents
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
|
||||
@@ -921,6 +932,9 @@ proc parsePragma(p: var TParser): PNode =
|
||||
else:
|
||||
parMessage(p, "expected '.}'")
|
||||
dec p.inPragma
|
||||
when defined(nimpretty):
|
||||
dec p.em.doIndentMore
|
||||
dec p.em.keepIndents
|
||||
|
||||
proc identVis(p: var TParser; allowDot=false): PNode =
|
||||
#| identVis = symbol opr? # postfix position
|
||||
@@ -967,7 +981,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
|
||||
while true:
|
||||
case p.tok.tokType
|
||||
of tkSymbol, tkAccent:
|
||||
if withPragma in flags: a = identWithPragma(p, allowDot=withdot in flags)
|
||||
if withPragma in flags: a = identWithPragma(p, allowDot=withDot in flags)
|
||||
else: a = parseSymbol(p)
|
||||
if a.kind == nkEmpty: return
|
||||
else: break
|
||||
@@ -1076,7 +1090,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.sons[0] = parseTypeDesc(p)
|
||||
elif not retColon and not hasParle:
|
||||
elif not retColon and not hasParLe:
|
||||
# Mark as "not there" in order to mark for deprecation in the semantic pass:
|
||||
result = p.emptyNode
|
||||
when defined(nimpretty):
|
||||
@@ -1189,6 +1203,13 @@ proc parseFor(p: var TParser): PNode =
|
||||
colcom(p, result)
|
||||
addSon(result, parseStmt(p))
|
||||
|
||||
template nimprettyDontTouch(body) =
|
||||
when defined(nimpretty):
|
||||
inc p.em.keepIndents
|
||||
body
|
||||
when defined(nimpretty):
|
||||
dec p.em.keepIndents
|
||||
|
||||
proc parseExpr(p: var TParser): PNode =
|
||||
#| expr = (blockExpr
|
||||
#| | ifExpr
|
||||
@@ -1198,12 +1219,26 @@ proc parseExpr(p: var TParser): PNode =
|
||||
#| | tryExpr)
|
||||
#| / simpleExpr
|
||||
case p.tok.tokType:
|
||||
of tkBlock: result = parseBlock(p)
|
||||
of tkIf: result = parseIfExpr(p, nkIfExpr)
|
||||
of tkFor: result = parseFor(p)
|
||||
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
|
||||
of tkCase: result = parseCase(p)
|
||||
of tkTry: result = parseTry(p, isExpr=true)
|
||||
of tkBlock:
|
||||
nimprettyDontTouch:
|
||||
result = parseBlock(p)
|
||||
of tkIf:
|
||||
nimprettyDontTouch:
|
||||
result = parseIfExpr(p, nkIfExpr)
|
||||
of tkFor:
|
||||
nimprettyDontTouch:
|
||||
result = parseFor(p)
|
||||
of tkWhen:
|
||||
nimprettyDontTouch:
|
||||
result = parseIfExpr(p, nkWhenExpr)
|
||||
of tkCase:
|
||||
# Currently we think nimpretty is good enough with case expressions,
|
||||
# so it is allowed to touch them:
|
||||
#nimprettyDontTouch:
|
||||
result = parseCase(p)
|
||||
of tkTry:
|
||||
nimprettyDontTouch:
|
||||
result = parseTry(p, isExpr=true)
|
||||
else: result = simpleExpr(p)
|
||||
|
||||
proc parseEnum(p: var TParser): PNode
|
||||
@@ -1289,6 +1324,7 @@ proc binaryNot(p: var TParser; a: PNode): PNode =
|
||||
|
||||
proc parseTypeDesc(p: var TParser): PNode =
|
||||
#| typeDesc = simpleExpr ('not' expr)?
|
||||
newlineWasSplitting(p)
|
||||
result = simpleExpr(p, pmTypeDesc)
|
||||
result = binaryNot(p, result)
|
||||
|
||||
@@ -1504,6 +1540,7 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
|
||||
elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or not isExprStart(p):
|
||||
# NL terminates:
|
||||
addSon(result, p.emptyNode)
|
||||
# nimpretty here!
|
||||
else:
|
||||
var e = parseExpr(p)
|
||||
e = postExprBlocks(p, e)
|
||||
@@ -1716,9 +1753,6 @@ proc parsePattern(p: var TParser): PNode =
|
||||
result = parseStmt(p)
|
||||
eat(p, tkCurlyRi)
|
||||
|
||||
proc validInd(p: var TParser): bool =
|
||||
result = p.tok.indent < 0 or p.tok.indent > p.currInd
|
||||
|
||||
proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
|
||||
#| indAndComment = (IND{>} COMMENT)? | COMMENT?
|
||||
#| routine = optInd identVis pattern? genericParamList?
|
||||
@@ -1803,7 +1837,7 @@ proc parseEnum(p: var TParser): PNode =
|
||||
symPragma = newNodeP(nkPragmaExpr, p)
|
||||
addSon(symPragma, a)
|
||||
addSon(symPragma, pragma)
|
||||
|
||||
# nimpretty support here
|
||||
if p.tok.indent >= 0 and p.tok.indent <= p.currInd:
|
||||
add(result, symPragma)
|
||||
break
|
||||
@@ -2213,6 +2247,7 @@ proc parseStmt(p: var TParser): PNode =
|
||||
#| stmt = (IND{>} complexOrSimpleStmt^+(IND{=} / ';') DED)
|
||||
#| / simpleStmt ^+ ';'
|
||||
if p.tok.indent > p.currInd:
|
||||
# nimpretty support here
|
||||
result = newNodeP(nkStmtList, p)
|
||||
withInd(p):
|
||||
while true:
|
||||
@@ -2289,6 +2324,7 @@ proc parseTopLevelStmt(p: var TParser): PNode =
|
||||
result = p.emptyNode
|
||||
# progress guaranteed
|
||||
while true:
|
||||
# nimpretty support here
|
||||
if p.tok.indent != 0:
|
||||
if p.firstTok and p.tok.indent < 0: discard
|
||||
elif p.tok.tokType != tkSemiColon:
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## implements some little helper passes
|
||||
|
||||
import
|
||||
strutils, ast, astalgo, passes, idents, msgs, options, idgen, lineinfos
|
||||
ast, passes, idents, msgs, options, idgen, lineinfos
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
|
||||
@@ -30,6 +30,6 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode =
|
||||
# system.nim deactivates all hints, for verbosity:3 we want the processing
|
||||
# messages nonetheless, so we activate them again unconditionally:
|
||||
incl(v.config.notes, hintProcessing)
|
||||
message(v.config, n.info, hintProcessing, $idgen.gFrontendId)
|
||||
message(v.config, n.info, hintProcessing, $idgen.gFrontEndId)
|
||||
|
||||
const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
## `TPass` interface.
|
||||
|
||||
import
|
||||
strutils, options, ast, astalgo, llstream, msgs, platform, os,
|
||||
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
|
||||
nimsets, syntaxes, times, idgen, modulegraphs, reorder, rod,
|
||||
options, ast, llstream, msgs,
|
||||
idents,
|
||||
syntaxes, idgen, modulegraphs, reorder, rod,
|
||||
lineinfos, pathutils
|
||||
|
||||
type
|
||||
@@ -90,14 +90,13 @@ proc processTopLevelStmt(graph: ModuleGraph, n: PNode, a: var TPassContextArray)
|
||||
proc resolveMod(conf: ConfigRef; module, relativeTo: string): FileIndex =
|
||||
let fullPath = findModule(conf, module, relativeTo)
|
||||
if fullPath.isEmpty:
|
||||
result = InvalidFileIDX
|
||||
result = InvalidFileIdx
|
||||
else:
|
||||
result = fileInfoIdx(conf, fullPath)
|
||||
|
||||
proc processImplicits(graph: ModuleGraph; implicits: seq[string], nodeKind: TNodeKind,
|
||||
a: var TPassContextArray; m: PSym) =
|
||||
# XXX fixme this should actually be relative to the config file!
|
||||
let gCmdLineInfo = newLineInfo(FileIndex(0), 1, 1)
|
||||
let relativeTo = toFullPath(graph.config, m.info)
|
||||
for module in items(implicits):
|
||||
# implicit imports should not lead to a module importing itself
|
||||
@@ -113,6 +112,19 @@ const
|
||||
nkMacroDef, nkConverterDef, nkIteratorDef, nkFuncDef, nkPragma,
|
||||
nkExportStmt, nkExportExceptStmt, nkFromStmt, nkImportStmt, nkImportExceptStmt}
|
||||
|
||||
proc prepareConfigNotes(graph: ModuleGraph; module: PSym) =
|
||||
if sfMainModule in module.flags:
|
||||
graph.config.mainPackageId = module.owner.id
|
||||
# don't be verbose unless the module belongs to the main package:
|
||||
if module.owner.id == graph.config.mainPackageId:
|
||||
graph.config.notes = graph.config.mainPackageNotes
|
||||
else:
|
||||
if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes
|
||||
graph.config.notes = graph.config.foreignPackageNotes
|
||||
|
||||
proc moduleHasChanged*(graph: ModuleGraph; module: PSym): bool {.inline.} =
|
||||
result = module.id >= 0 or isDefined(graph.config, "nimBackendAssumesChange")
|
||||
|
||||
proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {.discardable.} =
|
||||
if graph.stopCompile(): return true
|
||||
var
|
||||
@@ -120,6 +132,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {
|
||||
a: TPassContextArray
|
||||
s: PLLStream
|
||||
fileIdx = module.fileIdx
|
||||
prepareConfigNotes(graph, module)
|
||||
if module.id < 0:
|
||||
# new module caching mechanism:
|
||||
for i in 0 ..< graph.passes.len:
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Path handling utilities for Nim. Strictly typed code in order
|
||||
## to avoid the never ending time sink in getting path handling right.
|
||||
|
||||
import os, strutils, pathnorm
|
||||
import os, pathnorm
|
||||
|
||||
type
|
||||
AbsoluteFile* = distinct string
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
## macro support.
|
||||
|
||||
import
|
||||
ast, astalgo, types, semdata, sigmatch, msgs, idents, aliases, parampatterns,
|
||||
trees
|
||||
ast, types, semdata, sigmatch, idents, aliases, parampatterns, trees
|
||||
|
||||
type
|
||||
TPatternContext = object
|
||||
@@ -59,8 +58,8 @@ proc sameTrees*(a, b: PNode): bool =
|
||||
of nkEmpty, nkNilLit: result = true
|
||||
of nkType: result = sameTypeOrNil(a.typ, b.typ)
|
||||
else:
|
||||
if sonsLen(a) == sonsLen(b):
|
||||
for i in 0 ..< sonsLen(a):
|
||||
if len(a) == len(b):
|
||||
for i in 0 ..< len(a):
|
||||
if not sameTrees(a.sons[i], b.sons[i]): return
|
||||
result = true
|
||||
|
||||
@@ -113,7 +112,7 @@ proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
|
||||
rpn: bool): bool =
|
||||
result = true
|
||||
if n.kind in nkCallKinds and matches(c, op.sons[1], n.sons[0]):
|
||||
for i in 1..sonsLen(n)-1:
|
||||
for i in 1..len(n)-1:
|
||||
if not matchStarAux(c, op, n[i], arglist, rpn): return false
|
||||
if rpn: arglist.add(n.sons[0])
|
||||
elif n.kind == nkHiddenStdConv and n.sons[1].kind == nkBracket:
|
||||
@@ -175,35 +174,35 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
|
||||
of nkEmpty, nkNilLit, nkType:
|
||||
result = true
|
||||
else:
|
||||
var plen = sonsLen(p)
|
||||
var plen = len(p)
|
||||
# special rule for p(X) ~ f(...); this also works for stuff like
|
||||
# partial case statements, etc! - Not really ... :-/
|
||||
let v = lastSon(p)
|
||||
if isPatternParam(c, v) and v.sym.typ.kind == tyVarargs:
|
||||
var arglist: PNode
|
||||
if plen <= sonsLen(n):
|
||||
if plen <= len(n):
|
||||
for i in 0 .. plen - 2:
|
||||
if not matches(c, p.sons[i], n.sons[i]): return
|
||||
if plen == sonsLen(n) and lastSon(n).kind == nkHiddenStdConv and
|
||||
if plen == len(n) and lastSon(n).kind == nkHiddenStdConv and
|
||||
lastSon(n).sons[1].kind == nkBracket:
|
||||
# unpack varargs:
|
||||
let n = lastSon(n).sons[1]
|
||||
arglist = newNodeI(nkArgList, n.info, n.len)
|
||||
for i in 0..<n.len: arglist.sons[i] = n.sons[i]
|
||||
else:
|
||||
arglist = newNodeI(nkArgList, n.info, sonsLen(n) - plen + 1)
|
||||
arglist = newNodeI(nkArgList, n.info, len(n) - plen + 1)
|
||||
# f(1, 2, 3)
|
||||
# p(X)
|
||||
for i in 0 .. sonsLen(n) - plen:
|
||||
for i in 0 .. len(n) - plen:
|
||||
arglist.sons[i] = n.sons[i + plen - 1]
|
||||
return bindOrCheck(c, v.sym, arglist)
|
||||
elif plen-1 == sonsLen(n):
|
||||
elif plen-1 == len(n):
|
||||
for i in 0 .. plen - 2:
|
||||
if not matches(c, p.sons[i], n.sons[i]): return
|
||||
arglist = newNodeI(nkArgList, n.info)
|
||||
return bindOrCheck(c, v.sym, arglist)
|
||||
if plen == sonsLen(n):
|
||||
for i in 0 ..< sonsLen(p):
|
||||
if plen == len(n):
|
||||
for i in 0 ..< len(p):
|
||||
if not matches(c, p.sons[i], n.sons[i]): return
|
||||
result = true
|
||||
|
||||
@@ -251,7 +250,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
||||
var ctx: TPatternContext
|
||||
ctx.owner = s
|
||||
ctx.c = c
|
||||
ctx.formals = sonsLen(s.typ)-1
|
||||
ctx.formals = len(s.typ)-1
|
||||
var m = matchStmtList(ctx, s.ast.sons[patternPos], n)
|
||||
if isNil(m): return nil
|
||||
# each parameter should have been bound; we simply setup a call and
|
||||
@@ -296,7 +295,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
||||
# constraint not fulfilled:
|
||||
if not ok: return nil
|
||||
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
markUsed(c, n.info, s)
|
||||
if ctx.subMatch:
|
||||
assert m.len == 3
|
||||
m.sons[1] = result
|
||||
|
||||
@@ -21,7 +21,7 @@ type
|
||||
# conditionals to condsyms (end of module).
|
||||
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
|
||||
osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx,
|
||||
osAmiga, osAtari, osNetware, osMacos, osMacosx, osHaiku, osAndroid, osVxworks
|
||||
osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks
|
||||
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch
|
||||
|
||||
type
|
||||
@@ -139,6 +139,10 @@ const
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
|
||||
(name: "iOS", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
props: {ospNeedsPIC, ospPosix}),
|
||||
(name: "Haiku", parDir: "..", dllFrmt: "lib$1.so", altDirSep: ":",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
|
||||
## Plugin to transform an inline iterator into a data structure.
|
||||
|
||||
import ".." / [ast, astalgo,
|
||||
magicsys, lookups, semdata,
|
||||
lambdalifting, msgs]
|
||||
import ".." / [ast, lookups, semdata, lambdalifting, msgs]
|
||||
|
||||
proc iterToProcImpl*(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## The builtin 'system.locals' implemented as a plugin.
|
||||
|
||||
import ".." / [pluginsupport, ast, astalgo,
|
||||
import ".." / [ast, astalgo,
|
||||
magicsys, lookups, semdata, lowerings]
|
||||
|
||||
proc semLocals*(c: PContext, n: PNode): PNode =
|
||||
@@ -17,25 +17,24 @@ proc semLocals*(c: PContext, n: PNode): PNode =
|
||||
var tupleType = newTypeS(tyTuple, c)
|
||||
result = newNodeIT(nkPar, n.info, tupleType)
|
||||
tupleType.n = newNodeI(nkRecList, n.info)
|
||||
let owner = getCurrOwner(c)
|
||||
# for now we skip openarrays ...
|
||||
for scope in walkScopes(c.currentScope):
|
||||
if scope == c.topLevelScope: break
|
||||
for it in items(scope.symbols):
|
||||
# XXX parameters' owners are wrong for generics; this caused some pain
|
||||
# for closures too; we should finally fix it.
|
||||
#if it.owner != c.p.owner: return result
|
||||
if it.kind in skLocalVars and
|
||||
it.typ.skipTypes({tyGenericInst, tyVar}).kind notin
|
||||
{tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyUntyped, tyTyped, tyEmpty}:
|
||||
|
||||
var field = newSym(skField, it.name, getCurrOwner(c), n.info)
|
||||
field.typ = it.typ.skipTypes({tyVar})
|
||||
field.position = counter
|
||||
inc(counter)
|
||||
if it.owner == owner:
|
||||
var field = newSym(skField, it.name, owner, n.info)
|
||||
field.typ = it.typ.skipTypes({tyVar})
|
||||
field.position = counter
|
||||
inc(counter)
|
||||
|
||||
addSon(tupleType.n, newSymNode(field))
|
||||
addSonSkipIntLit(tupleType, field.typ)
|
||||
addSon(tupleType.n, newSymNode(field))
|
||||
addSonSkipIntLit(tupleType, field.typ)
|
||||
|
||||
var a = newSymNode(it, result.info)
|
||||
if it.typ.skipTypes({tyGenericInst}).kind == tyVar: a = newDeref(a)
|
||||
result.add(a)
|
||||
var a = newSymNode(it, result.info)
|
||||
if it.typ.skipTypes({tyGenericInst}).kind == tyVar: a = newDeref(a)
|
||||
result.add(a)
|
||||
|
||||
@@ -12,64 +12,66 @@
|
||||
import
|
||||
os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
|
||||
wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees,
|
||||
types, lookups, lineinfos, pathutils
|
||||
types, lookups, lineinfos, pathutils, linter
|
||||
|
||||
const
|
||||
FirstCallConv* = wNimcall
|
||||
LastCallConv* = wNoconv
|
||||
|
||||
const
|
||||
procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||
wMagic, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
||||
wCompilerProc, wNonReloadable, wCore, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
||||
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
||||
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wCodegenDecl,
|
||||
declPragmas = {wImportc, wImportObjC, wImportCpp, wImportJs, wExportc, wExportCpp,
|
||||
wExportNims, wExtern, wDeprecated, wNodecl, wError, wUsed}
|
||||
## common pragmas for declarations, to a good approximation
|
||||
procPragmas* = declPragmas + {FirstCallConv..LastCallConv,
|
||||
wMagic, wNoSideEffect, wSideEffect, wNoreturn, wDynlib, wHeader,
|
||||
wCompilerProc, wNonReloadable, wCore, wProcVar, wVarargs, wCompileTime, wMerge,
|
||||
wBorrow, wImportCompilerProc, wThread,
|
||||
wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl,
|
||||
wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
|
||||
wConstructor, wExportNims, wUsed, wLiftLocals, wStacktrace, wLinetrace}
|
||||
converterPragmas* = procPragmas
|
||||
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
|
||||
wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy}
|
||||
converterPragmas* = procPragmas - {wNoDestroy}
|
||||
methodPragmas* = procPragmas+{wBase}-{wImportCpp, wNoDestroy}
|
||||
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
|
||||
wDelegator, wExportNims, wUsed, wPragma}
|
||||
macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc,
|
||||
wNodecl, wMagic, wNosideeffect, wCompilerProc, wNonReloadable, wCore, wDeprecated, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator,
|
||||
wExportNims, wUsed}
|
||||
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
|
||||
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
|
||||
wTags, wLocks, wGcSafe, wExportNims, wUsed}
|
||||
exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe, wNosideeffect}
|
||||
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
||||
wBoundchecks, wOverflowchecks, wNilchecks, wMovechecks, wAssertions,
|
||||
macroPragmas* = declPragmas + {FirstCallConv..LastCallConv,
|
||||
wMagic, wNoSideEffect, wCompilerProc, wNonReloadable, wCore,
|
||||
wDiscardable, wGensym, wInject, wDelegator}
|
||||
iteratorPragmas* = declPragmas + {FirstCallConv..LastCallConv, wNoSideEffect, wSideEffect,
|
||||
wMagic, wBorrow,
|
||||
wDiscardable, wGensym, wInject, wRaises,
|
||||
wTags, wLocks, wGcSafe}
|
||||
exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe, wNoSideEffect}
|
||||
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangeChecks,
|
||||
wBoundChecks, wOverflowChecks, wNilChecks, wStyleChecks, wAssertions,
|
||||
wWarnings, wHints,
|
||||
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
|
||||
wLineDir, wStackTrace, wLineTrace, wOptimization, wHint, wWarning, wError,
|
||||
wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop,
|
||||
wBreakpoint, wWatchPoint, wPassl, wPassc,
|
||||
wPassl, wPassc,
|
||||
wDeadCodeElimUnused, # deprecated, always on
|
||||
wDeprecated,
|
||||
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||
wLinearScanEnd, wPatterns, wTrMacros, wEffects, wNoForward, wReorder, wComputedGoto,
|
||||
wInjectStmt, wDeprecated, wExperimental, wThis}
|
||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
||||
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
||||
wRaises, wLocks, wTags, wGcSafe, wCodegenDecl}
|
||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wExtern, wShallow,
|
||||
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
|
||||
wInjectStmt, wExperimental, wThis, wUsed}
|
||||
lambdaPragmas* = declPragmas + {FirstCallConv..LastCallConv,
|
||||
wNoSideEffect, wSideEffect, wNoreturn, wDynlib, wHeader,
|
||||
wThread, wAsmNoStackFrame,
|
||||
wRaises, wLocks, wTags, wGcSafe, wCodegenDecl} - {wExportNims, wError, wUsed} # why exclude these?
|
||||
typePragmas* = declPragmas + {wMagic, wAcyclic,
|
||||
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow,
|
||||
wIncompleteStruct, wByCopy, wByRef,
|
||||
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
||||
wBorrow, wGcSafe, wExportNims, wPartial, wUsed, wExplain, wPackage}
|
||||
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wGuard, wBitsize, wUsed}
|
||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||
wMagic, wHeader, wDeprecated, wCompilerProc, wCore, wDynlib, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
|
||||
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims, wUsed, wCursor}
|
||||
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
||||
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims,
|
||||
wIntDefine, wStrDefine, wBoolDefine, wUsed, wCompilerProc, wCore}
|
||||
wBorrow, wGcSafe, wPartial, wExplain, wPackage}
|
||||
fieldPragmas* = declPragmas + {
|
||||
wGuard, wBitsize} - {wExportNims, wNodecl} # why exclude these?
|
||||
varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar,
|
||||
wMagic, wHeader, wCompilerProc, wCore, wDynlib,
|
||||
wNoInit, wCompileTime, wGlobal,
|
||||
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor}
|
||||
constPragmas* = declPragmas + {wHeader, wMagic,
|
||||
wGensym, wInject,
|
||||
wIntDefine, wStrDefine, wBoolDefine, wCompilerProc, wCore}
|
||||
letPragmas* = varPragmas
|
||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
|
||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect,
|
||||
wThread, wRaises, wLocks, wTags, wGcSafe}
|
||||
forVarPragmas* = {wInject, wGensym}
|
||||
allRoutinePragmas* = methodPragmas + iteratorPragmas + lambdaPragmas
|
||||
@@ -83,7 +85,8 @@ proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode =
|
||||
it[0].ident.id == ord(name):
|
||||
return it[1]
|
||||
|
||||
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
|
||||
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords;
|
||||
isStatement: bool = false)
|
||||
|
||||
proc recordPragma(c: PContext; n: PNode; key, val: string; val2 = "") =
|
||||
var recorded = newNodeI(nkCommentStmt, n.info)
|
||||
@@ -104,7 +107,7 @@ proc illegalCustomPragma*(c: PContext, n: PNode, s: PSym) =
|
||||
proc pragmaAsm*(c: PContext, n: PNode): char =
|
||||
result = '\0'
|
||||
if n != nil:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
let it = n.sons[i]
|
||||
if it.kind in nkPragmaCallKinds and it.len == 2 and it.sons[0].kind == nkIdent:
|
||||
case whichKeyword(it.sons[0].ident)
|
||||
@@ -161,7 +164,7 @@ proc processImportObjC(c: PContext; s: PSym, extname: string, info: TLineInfo) =
|
||||
incl(s.flags, sfNamedParamCall)
|
||||
excl(s.flags, sfForward)
|
||||
let m = s.getModule()
|
||||
incl(m.flags, sfCompileToObjC)
|
||||
incl(m.flags, sfCompileToObjc)
|
||||
|
||||
proc newEmptyStrNode(c: PContext; n: PNode): PNode {.noinline.} =
|
||||
result = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString))
|
||||
@@ -331,21 +334,21 @@ proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} =
|
||||
of wChecks: ChecksOptions
|
||||
of wObjChecks: {optObjCheck}
|
||||
of wFieldChecks: {optFieldCheck}
|
||||
of wRangechecks: {optRangeCheck}
|
||||
of wBoundchecks: {optBoundsCheck}
|
||||
of wOverflowchecks: {optOverflowCheck}
|
||||
of wNilchecks: {optNilCheck}
|
||||
of wFloatchecks: {optNaNCheck, optInfCheck}
|
||||
of wRangeChecks: {optRangeCheck}
|
||||
of wBoundChecks: {optBoundsCheck}
|
||||
of wOverflowChecks: {optOverflowCheck}
|
||||
of wNilChecks: {optNilCheck}
|
||||
of wFloatChecks: {optNaNCheck, optInfCheck}
|
||||
of wNanChecks: {optNaNCheck}
|
||||
of wInfChecks: {optInfCheck}
|
||||
of wMovechecks: {optMoveCheck}
|
||||
of wStyleChecks: {optStyleCheck}
|
||||
of wAssertions: {optAssert}
|
||||
of wWarnings: {optWarns}
|
||||
of wHints: {optHints}
|
||||
of wLinedir: {optLineDir}
|
||||
of wStacktrace: {optStackTrace}
|
||||
of wLinetrace: {optLineTrace}
|
||||
of wDebugger: {optEndb}
|
||||
of wLineDir: {optLineDir}
|
||||
of wStackTrace: {optStackTrace}
|
||||
of wLineTrace: {optLineTrace}
|
||||
of wDebugger: {optNone}
|
||||
of wProfiler: {optProfiler, optMemTracker}
|
||||
of wMemTracker: {optMemTracker}
|
||||
of wByRef: {optByRef}
|
||||
@@ -423,7 +426,7 @@ proc processPush(c: PContext, n: PNode, start: int) =
|
||||
x.notes = c.config.notes
|
||||
x.features = c.features
|
||||
c.optionStack.add(x)
|
||||
for i in start ..< sonsLen(n):
|
||||
for i in start ..< len(n):
|
||||
if not tryProcessOption(c, n.sons[i], c.config.options):
|
||||
# simply store it somewhere:
|
||||
if x.otherPragmas.isNil:
|
||||
@@ -434,6 +437,8 @@ proc processPush(c: PContext, n: PNode, start: int) =
|
||||
# If stacktrace is disabled globally we should not enable it
|
||||
if optStackTrace notin c.optionStack[0].options:
|
||||
c.config.options.excl(optStackTrace)
|
||||
when defined(debugOptions):
|
||||
echo c.config $ n.info, " PUSH config is now ", c.config.options
|
||||
|
||||
proc processPop(c: PContext, n: PNode) =
|
||||
if c.optionStack.len <= 1:
|
||||
@@ -443,6 +448,8 @@ proc processPop(c: PContext, n: PNode) =
|
||||
c.config.notes = c.optionStack[^1].notes
|
||||
c.features = c.optionStack[^1].features
|
||||
c.optionStack.setLen(c.optionStack.len - 1)
|
||||
when defined(debugOptions):
|
||||
echo c.config $ n.info, " POP config is now ", c.config.options
|
||||
|
||||
proc processDefine(c: PContext, n: PNode) =
|
||||
if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent):
|
||||
@@ -491,7 +498,7 @@ proc processCompile(c: PContext, n: PNode) =
|
||||
let dest = getStrLit(c, it, 1)
|
||||
var found = parentDir(toFullPath(c.config, n.info)) / s
|
||||
for f in os.walkFiles(found):
|
||||
let obj = completeCFilePath(c.config, AbsoluteFile(dest % extractFilename(f)))
|
||||
let obj = completeCfilePath(c.config, AbsoluteFile(dest % extractFilename(f)))
|
||||
docompile(c, it, AbsoluteFile f, obj)
|
||||
else:
|
||||
let s = expectStrLit(c, n)
|
||||
@@ -501,7 +508,7 @@ proc processCompile(c: PContext, n: PNode) =
|
||||
else:
|
||||
found = findFile(c.config, s)
|
||||
if found.isEmpty: found = AbsoluteFile s
|
||||
let obj = toObjFile(c.config, completeCFilePath(c.config, found, false))
|
||||
let obj = toObjFile(c.config, completeCfilePath(c.config, found, false))
|
||||
docompile(c, it, found, obj)
|
||||
|
||||
proc processLink(c: PContext, n: PNode) =
|
||||
@@ -509,15 +516,6 @@ proc processLink(c: PContext, n: PNode) =
|
||||
extccomp.addExternalFileToLink(c.config, found)
|
||||
recordPragma(c, n, "link", found.string)
|
||||
|
||||
proc pragmaBreakpoint(c: PContext, n: PNode) =
|
||||
discard getOptionalStr(c, n, "")
|
||||
|
||||
proc pragmaWatchpoint(c: PContext, n: PNode) =
|
||||
if n.kind in nkPragmaCallKinds and n.len == 2:
|
||||
n.sons[1] = c.semExpr(c, n.sons[1])
|
||||
else:
|
||||
invalidPragma(c, n)
|
||||
|
||||
proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
|
||||
case n.sons[1].kind
|
||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||
@@ -610,9 +608,9 @@ proc pragmaLine(c: PContext, n: PNode) =
|
||||
|
||||
proc processPragma(c: PContext, n: PNode, i: int) =
|
||||
let it = n[i]
|
||||
if it.kind notin nkPragmaCallKinds and it.len == 2: invalidPragma(c, n)
|
||||
elif it[0].kind != nkIdent: invalidPragma(c, n)
|
||||
elif it[1].kind != nkIdent: invalidPragma(c, n)
|
||||
if it.kind notin nkPragmaCallKinds and it.safeLen == 2: invalidPragma(c, n)
|
||||
elif it.safeLen != 2 or it[0].kind != nkIdent or it[1].kind != nkIdent:
|
||||
invalidPragma(c, n)
|
||||
|
||||
var userPragma = newSym(skTemplate, it[1].ident, nil, it.info, c.config.options)
|
||||
userPragma.ast = newNode(nkPragma, n.info, n.sons[i+1..^1])
|
||||
@@ -750,7 +748,8 @@ proc semCustomPragma(c: PContext, n: PNode): PNode =
|
||||
result.kind = n.kind
|
||||
|
||||
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
validPragmas: TSpecialWords, comesFromPush: bool) : bool =
|
||||
validPragmas: TSpecialWords,
|
||||
comesFromPush, isStatement: bool) : bool =
|
||||
var it = n.sons[i]
|
||||
var key = if it.kind in nkPragmaCallKinds and it.len > 1: it.sons[0] else: it
|
||||
if key.kind == nkBracketExpr:
|
||||
@@ -762,21 +761,31 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
let ident = considerQuotedIdent(c, key)
|
||||
var userPragma = strTableGet(c.userPragmas, ident)
|
||||
if userPragma != nil:
|
||||
if {optStyleHint, optStyleError} * c.config.globalOptions != {}:
|
||||
styleCheckUse(c.config, key.info, userPragma)
|
||||
|
||||
# number of pragmas increase/decrease with user pragma expansion
|
||||
inc c.instCounter
|
||||
if c.instCounter > 100:
|
||||
globalError(c.config, it.info, "recursive dependency: " & userPragma.name.s)
|
||||
|
||||
pragma(c, sym, userPragma.ast, validPragmas)
|
||||
pragma(c, sym, userPragma.ast, validPragmas, isStatement)
|
||||
n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content
|
||||
i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty
|
||||
dec c.instCounter
|
||||
else:
|
||||
let k = whichKeyword(ident)
|
||||
if k in validPragmas:
|
||||
if {optStyleHint, optStyleError} * c.config.globalOptions != {}:
|
||||
checkPragmaUse(c.config, key.info, k, ident.s)
|
||||
case k
|
||||
of wExportc:
|
||||
of wExportc, wExportCpp:
|
||||
makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
if k == wExportCpp:
|
||||
if c.config.cmd != cmdCompileToCpp:
|
||||
localError(c.config, it.info, "exportcpp requires `nim cpp`, got " & $c.config.cmd)
|
||||
else:
|
||||
incl(sym.flags, sfMangleCpp)
|
||||
incl(sym.flags, sfUsed) # avoid wrong hints
|
||||
of wImportc:
|
||||
let name = getOptionalStr(c, it, "$1")
|
||||
@@ -794,6 +803,15 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
else: invalidPragma(c, it)
|
||||
of wImportCpp:
|
||||
processImportCpp(c, sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
of wImportJs:
|
||||
if c.config.cmd != cmdCompileToJS:
|
||||
localError(c.config, it.info, "`importjs` pragma requires the JavaScript target")
|
||||
let name = getOptionalStr(c, it, "$1")
|
||||
incl(sym.flags, sfImportc)
|
||||
incl(sym.flags, sfInfixCall)
|
||||
if sym.kind in skProcKinds and {'(', '#', '@'} notin name:
|
||||
localError(c.config, n.info, "`importjs` for routines requires a pattern")
|
||||
setExternName(c, sym, name, it.info)
|
||||
of wImportObjC:
|
||||
processImportObjC(c, sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
of wAlign:
|
||||
@@ -807,12 +825,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
if sym.typ == nil: invalidPragma(c, it)
|
||||
var size = expectIntLit(c, it)
|
||||
case size
|
||||
of 1, 2, 4, 8:
|
||||
of 1, 2, 4:
|
||||
sym.typ.size = size
|
||||
if size == 8 and c.config.target.targetCPU == cpuI386:
|
||||
sym.typ.align = 4
|
||||
else:
|
||||
sym.typ.align = int16(size)
|
||||
sym.typ.align = int16 size
|
||||
of 8:
|
||||
sym.typ.size = 8
|
||||
sym.typ.align = floatInt64Align(c.config)
|
||||
else:
|
||||
localError(c.config, it.info, "size may only be 1, 2, 4 or 8")
|
||||
of wNodecl:
|
||||
@@ -839,7 +857,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
of wCompileTime:
|
||||
noVal(c, it)
|
||||
incl(sym.flags, sfCompileTime)
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
#incl(sym.loc.flags, lfNoDecl)
|
||||
of wGlobal:
|
||||
noVal(c, it)
|
||||
incl(sym.flags, sfGlobal)
|
||||
@@ -858,12 +876,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
# implies nodecl, because otherwise header would not make sense
|
||||
if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
|
||||
of wNosideeffect:
|
||||
of wNoSideEffect:
|
||||
noVal(c, it)
|
||||
if sym != nil:
|
||||
incl(sym.flags, sfNoSideEffect)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
|
||||
of wSideeffect:
|
||||
of wSideEffect:
|
||||
noVal(c, it)
|
||||
incl(sym.flags, sfSideEffect)
|
||||
of wNoreturn:
|
||||
@@ -874,6 +892,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
if sym.typ[0] != nil:
|
||||
localError(c.config, sym.ast[paramsPos][0].info,
|
||||
".noreturn with return type not allowed")
|
||||
of wNoDestroy:
|
||||
noVal(c, it)
|
||||
incl(sym.flags, sfGeneratedOp)
|
||||
of wDynlib:
|
||||
processDynLib(c, it, sym)
|
||||
of wCompilerProc, wCore:
|
||||
@@ -959,7 +980,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
recordPragma(c, it, "warning", s)
|
||||
message(c.config, it.info, warnUser, s)
|
||||
of wError:
|
||||
if sym != nil and (sym.isRoutine or sym.kind == skType) and wUsed in validPragmas:
|
||||
if sym != nil and (sym.isRoutine or sym.kind == skType) and not isStatement:
|
||||
# This is subtle but correct: the error *statement* is only
|
||||
# allowed when 'wUsed' is not in validPragmas. Here this is the easiest way to
|
||||
# distinguish properly between
|
||||
@@ -984,8 +1005,6 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
let s = expectStrLit(c, it)
|
||||
extccomp.addCompileOption(c.config, s)
|
||||
recordPragma(c, it, "passc", s)
|
||||
of wBreakpoint: pragmaBreakpoint(c, it)
|
||||
of wWatchPoint: pragmaWatchpoint(c, it)
|
||||
of wPush:
|
||||
processPush(c, n, i + 1)
|
||||
result = true
|
||||
@@ -1003,12 +1022,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
noVal(c, it)
|
||||
if sym != nil: incl(sym.flags, sfNoInit)
|
||||
of wCodegenDecl: processCodegenDecl(c, it, sym)
|
||||
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
|
||||
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||
wLinedir, wOptimization, wMovechecks, wCallconv, wDebugger, wProfiler,
|
||||
wFloatchecks, wNanChecks, wInfChecks, wPatterns, wTrMacros:
|
||||
of wChecks, wObjChecks, wFieldChecks, wRangeChecks, wBoundChecks,
|
||||
wOverflowChecks, wNilChecks, wAssertions, wWarnings, wHints,
|
||||
wLineDir, wOptimization, wStyleChecks, wCallconv, wDebugger, wProfiler,
|
||||
wFloatChecks, wNanChecks, wInfChecks, wPatterns, wTrMacros:
|
||||
processOption(c, it, c.config.options)
|
||||
of wStacktrace, wLinetrace:
|
||||
of wStackTrace, wLineTrace:
|
||||
if sym.kind in {skProc, skMethod, skConverter}:
|
||||
processOption(c, it, sym.options)
|
||||
else:
|
||||
@@ -1130,7 +1149,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
elif comesFromPush and whichKeyword(ident) in {wTags, wRaises}:
|
||||
discard "ignore the .push pragma; it doesn't apply"
|
||||
else:
|
||||
if sym == nil or (sym != nil and sym.kind in {skVar, skLet, skParam,
|
||||
if sym == nil or (sym.kind in {skVar, skLet, skParam,
|
||||
skField, skProc, skFunc, skConverter, skMethod, skType}):
|
||||
n.sons[i] = semCustomPragma(c, it)
|
||||
elif sym != nil:
|
||||
@@ -1160,7 +1179,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
|
||||
pushInfoContext(c.config, n.info)
|
||||
var i = 0
|
||||
while i < o.len:
|
||||
if singlePragma(c, sym, o, i, validPragmas, true):
|
||||
if singlePragma(c, sym, o, i, validPragmas, true, false):
|
||||
internalError(c.config, n.info, "implicitPragmas")
|
||||
inc i
|
||||
popInfoContext(c.config)
|
||||
@@ -1185,14 +1204,16 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
|
||||
|
||||
return false
|
||||
|
||||
proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||
proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords;
|
||||
isStatement: bool) =
|
||||
if n == nil: return
|
||||
var i = 0
|
||||
while i < n.len:
|
||||
if singlePragma(c, sym, n, i, validPragmas, false): break
|
||||
if singlePragma(c, sym, n, i, validPragmas, false, isStatement): break
|
||||
inc i
|
||||
|
||||
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords;
|
||||
isStatement: bool) =
|
||||
if n == nil: return
|
||||
pragmaRec(c, sym, n, validPragmas)
|
||||
pragmaRec(c, sym, n, validPragmas, isStatement)
|
||||
implicitPragmas(c, sym, n, validPragmas)
|
||||
|
||||
@@ -14,8 +14,8 @@ import
|
||||
ast, astalgo, msgs, semdata, types, trees, strutils
|
||||
|
||||
proc equalGenericParams(procA, procB: PNode): bool =
|
||||
if sonsLen(procA) != sonsLen(procB): return false
|
||||
for i in 0 ..< sonsLen(procA):
|
||||
if len(procA) != len(procB): return false
|
||||
for i in 0 ..< len(procA):
|
||||
if procA.sons[i].kind != nkSym:
|
||||
return false
|
||||
if procB.sons[i].kind != nkSym:
|
||||
@@ -72,8 +72,8 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||
of paramsEqual:
|
||||
if (sfExported notin result.flags) and (sfExported in fn.flags):
|
||||
let message = ("public implementation '$1' has non-public " &
|
||||
"forward declaration in $2") %
|
||||
[getProcHeader(c.config, result), c.config$result.info]
|
||||
"forward declaration at $2") %
|
||||
[getProcHeader(c.config, result, getDeclarationPath = false), c.config$result.info]
|
||||
localError(c.config, fn.info, message)
|
||||
return
|
||||
of paramsIncompatible:
|
||||
@@ -95,9 +95,9 @@ proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||
|
||||
when false:
|
||||
proc paramsFitBorrow(child, parent: PNode): bool =
|
||||
var length = sonsLen(child)
|
||||
var length = len(child)
|
||||
result = false
|
||||
if length == sonsLen(parent):
|
||||
if length == len(parent):
|
||||
for i in 1 ..< length:
|
||||
var m = child.sons[i].sym
|
||||
var n = parent.sons[i].sym
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
|
||||
# This module implements the renderer of the standard Nim representation.
|
||||
|
||||
when defined(nimHasUsed):
|
||||
# 'import renderer' is so useful for debugging
|
||||
# that Nim shouldn't produce a warning for that:
|
||||
{.used.}
|
||||
|
||||
import
|
||||
lexer, options, idents, strutils, ast, msgs, lineinfos
|
||||
|
||||
@@ -64,14 +69,11 @@ proc renderDefinitionName*(s: PSym, noQuotes = false): string =
|
||||
else:
|
||||
result = '`' & x & '`'
|
||||
|
||||
when not defined(nimpretty):
|
||||
const
|
||||
IndentWidth = 2
|
||||
longIndentWid = IndentWidth * 2
|
||||
else:
|
||||
template IndentWidth: untyped = lexer.gIndentationWidth
|
||||
template longIndentWid: untyped = IndentWidth() * 2
|
||||
const
|
||||
IndentWidth = 2
|
||||
longIndentWid = IndentWidth * 2
|
||||
|
||||
when defined(nimpretty):
|
||||
proc minmaxLine(n: PNode): (int, int) =
|
||||
case n.kind
|
||||
of nkTripleStrLit:
|
||||
@@ -333,8 +335,7 @@ proc ulitAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
|
||||
if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
|
||||
elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
|
||||
elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
|
||||
else: result = $x
|
||||
# XXX proper unsigned output!
|
||||
else: result = $cast[BiggestUInt](x)
|
||||
|
||||
proc atom(g: TSrcGen; n: PNode): string =
|
||||
when defined(nimpretty):
|
||||
@@ -394,7 +395,7 @@ proc atom(g: TSrcGen; n: PNode): string =
|
||||
proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
|
||||
assert(theEnd < 0)
|
||||
result = 0
|
||||
for i in start .. sonsLen(n) + theEnd:
|
||||
for i in start .. len(n) + theEnd:
|
||||
let param = n.sons[i]
|
||||
if nfDefaultParam notin param.flags:
|
||||
inc(result, lsub(g, param))
|
||||
@@ -405,7 +406,7 @@ proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
|
||||
proc lsons(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
|
||||
assert(theEnd < 0)
|
||||
result = 0
|
||||
for i in start .. sonsLen(n) + theEnd: inc(result, lsub(g, n.sons[i]))
|
||||
for i in start .. len(n) + theEnd: inc(result, lsub(g, n.sons[i]))
|
||||
|
||||
proc lsub(g: TSrcGen; n: PNode): int =
|
||||
# computes the length of a tree
|
||||
@@ -435,7 +436,7 @@ proc lsub(g: TSrcGen; n: PNode): int =
|
||||
of nkTableConstr:
|
||||
result = if n.len > 0: lcomma(g, n) + 2 else: len("{:}")
|
||||
of nkClosedSymChoice, nkOpenSymChoice:
|
||||
result = lsons(g, n) + len("()") + sonsLen(n) - 1
|
||||
result = lsons(g, n) + len("()") + len(n) - 1
|
||||
of nkTupleTy: result = lcomma(g, n) + len("tuple[]")
|
||||
of nkTupleClassTy: result = len("tuple")
|
||||
of nkDotExpr: result = lsons(g, n) + 1
|
||||
@@ -447,7 +448,7 @@ proc lsub(g: TSrcGen; n: PNode): int =
|
||||
of nkDo: result = lsons(g, n) + len("do__:_")
|
||||
of nkConstDef, nkIdentDefs:
|
||||
result = lcomma(g, n, 0, - 3)
|
||||
var L = sonsLen(n)
|
||||
var L = len(n)
|
||||
if n.sons[L - 2].kind != nkEmpty: result = result + lsub(g, n.sons[L - 2]) + 2
|
||||
if n.sons[L - 1].kind != nkEmpty: result = result + lsub(g, n.sons[L - 1]) + 3
|
||||
of nkVarTuple: result = lcomma(g, n, 0, - 3) + len("() = ") + lsub(g, lastSon(n))
|
||||
@@ -456,7 +457,7 @@ proc lsub(g: TSrcGen; n: PNode): int =
|
||||
of nkChckRange: result = len("chckRange") + 2 + lcomma(g, n)
|
||||
of nkObjDownConv, nkObjUpConv:
|
||||
result = 2
|
||||
if sonsLen(n) >= 1: result = result + lsub(g, n.sons[0])
|
||||
if len(n) >= 1: result = result + lsub(g, n.sons[0])
|
||||
result = result + lcomma(g, n, 1)
|
||||
of nkExprColonExpr: result = lsons(g, n) + 2
|
||||
of nkInfix: result = lsons(g, n) + 2
|
||||
@@ -490,16 +491,16 @@ proc lsub(g: TSrcGen; n: PNode): int =
|
||||
of nkIteratorTy: result = lsons(g, n) + len("iterator_")
|
||||
of nkSharedTy: result = lsons(g, n) + len("shared_")
|
||||
of nkEnumTy:
|
||||
if sonsLen(n) > 0:
|
||||
if len(n) > 0:
|
||||
result = lsub(g, n.sons[0]) + lcomma(g, n, 1) + len("enum_")
|
||||
else:
|
||||
result = len("enum")
|
||||
of nkEnumFieldDef: result = lsons(g, n) + 3
|
||||
of nkVarSection, nkLetSection:
|
||||
if sonsLen(n) > 1: result = MaxLineLen + 1
|
||||
if len(n) > 1: result = MaxLineLen + 1
|
||||
else: result = lsons(g, n) + len("var_")
|
||||
of nkUsingStmt:
|
||||
if sonsLen(n) > 1: result = MaxLineLen + 1
|
||||
if len(n) > 1: result = MaxLineLen + 1
|
||||
else: result = lsons(g, n) + len("using_")
|
||||
of nkReturnStmt:
|
||||
if n.len > 0 and n[0].kind == nkAsgn:
|
||||
@@ -555,7 +556,7 @@ proc hasCom(n: PNode): bool =
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit: discard
|
||||
else:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if hasCom(n.sons[i]): return true
|
||||
|
||||
proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) =
|
||||
@@ -564,8 +565,8 @@ proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) =
|
||||
|
||||
proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
|
||||
theEnd: int = - 1, separator = tkComma) =
|
||||
for i in start .. sonsLen(n) + theEnd:
|
||||
var c = i < sonsLen(n) + theEnd
|
||||
for i in start .. len(n) + theEnd:
|
||||
var c = i < len(n) + theEnd
|
||||
var sublen = lsub(g, n.sons[i]) + ord(c)
|
||||
if not fits(g, sublen) and (ind + sublen < MaxLineLen): optNL(g, ind)
|
||||
let oldLen = g.tokens.len
|
||||
@@ -599,15 +600,15 @@ proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
|
||||
|
||||
proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
|
||||
theEnd: int = - 1) =
|
||||
for i in start .. sonsLen(n) + theEnd: gsub(g, n.sons[i], c)
|
||||
for i in start .. len(n) + theEnd: gsub(g, n.sons[i], c)
|
||||
|
||||
proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType,
|
||||
k: string) =
|
||||
if sonsLen(n) == 0: return # empty var sections are possible
|
||||
if len(n) == 0: return # empty var sections are possible
|
||||
putWithSpace(g, kind, k)
|
||||
gcoms(g)
|
||||
indentNL(g)
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
optNL(g)
|
||||
gsub(g, n.sons[i], c)
|
||||
gcoms(g)
|
||||
@@ -617,7 +618,7 @@ proc longMode(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): bool =
|
||||
result = n.comment.len > 0
|
||||
if not result:
|
||||
# check further
|
||||
for i in start .. sonsLen(n) + theEnd:
|
||||
for i in start .. len(n) + theEnd:
|
||||
if (lsub(g, n.sons[i]) > MaxLineLen):
|
||||
result = true
|
||||
break
|
||||
@@ -662,7 +663,7 @@ proc gif(g: var TSrcGen, n: PNode) =
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g) # a good place for comments
|
||||
gstmts(g, n.sons[0].sons[1], c)
|
||||
var length = sonsLen(n)
|
||||
var length = len(n)
|
||||
for i in 1 ..< length:
|
||||
optNL(g)
|
||||
gsub(g, n.sons[i], c)
|
||||
@@ -711,7 +712,7 @@ proc gtry(g: var TSrcGen, n: PNode) =
|
||||
|
||||
proc gfor(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
var length = sonsLen(n)
|
||||
var length = len(n)
|
||||
putWithSpace(g, tkFor, "for")
|
||||
initContext(c)
|
||||
if longMode(g, n) or
|
||||
@@ -729,7 +730,7 @@ proc gfor(g: var TSrcGen, n: PNode) =
|
||||
proc gcase(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
initContext(c)
|
||||
var length = sonsLen(n)
|
||||
var length = len(n)
|
||||
if length == 0: return
|
||||
var last = if n.sons[length-1].kind == nkElse: -2 else: -1
|
||||
if longMode(g, n, 0, last): incl(c.flags, rfLongMode)
|
||||
@@ -743,13 +744,18 @@ proc gcase(g: var TSrcGen, n: PNode) =
|
||||
if longMode(g, n.sons[length - 1]): incl(c.flags, rfLongMode)
|
||||
gsub(g, n.sons[length - 1], c)
|
||||
|
||||
proc genSymSuffix(result: var string, s: PSym) {.inline.} =
|
||||
if sfGenSym in s.flags:
|
||||
result.add '_'
|
||||
result.addInt s.id
|
||||
|
||||
proc gproc(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
if n.sons[namePos].kind == nkSym:
|
||||
let s = n.sons[namePos].sym
|
||||
put(g, tkSymbol, renderDefinitionName(s))
|
||||
if sfGenSym in s.flags:
|
||||
put(g, tkIntLit, $s.id)
|
||||
var ret = renderDefinitionName(s)
|
||||
ret.genSymSuffix(s)
|
||||
put(g, tkSymbol, ret)
|
||||
else:
|
||||
gsub(g, n.sons[namePos])
|
||||
|
||||
@@ -843,12 +849,12 @@ proc gident(g: var TSrcGen, n: PNode) =
|
||||
t = tkSymbol
|
||||
else:
|
||||
t = tkOpr
|
||||
put(g, t, s, if n.kind == nkSym and renderSyms in g.flags: n.sym else: nil)
|
||||
if n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags or n.sym.kind == skTemp):
|
||||
s.genSymSuffix(n.sym)
|
||||
when defined(debugMagics):
|
||||
put(g, tkIntLit, $n.sym.id & $n.sym.magic)
|
||||
else:
|
||||
put(g, tkIntLit, $n.sym.id)
|
||||
s.add '_'
|
||||
s.add $n.sym.magic
|
||||
put(g, t, s, if n.kind == nkSym and renderSyms in g.flags: n.sym else: nil)
|
||||
|
||||
proc doParamsAux(g: var TSrcGen, params: PNode) =
|
||||
if params.len > 1:
|
||||
@@ -898,16 +904,19 @@ proc accentedName(g: var TSrcGen, n: PNode) =
|
||||
gsub(g, n)
|
||||
|
||||
proc infixArgument(g: var TSrcGen, n: PNode, i: int) =
|
||||
if i >= n.len: return
|
||||
|
||||
if i < 1 and i > 2: return
|
||||
var needsParenthesis = false
|
||||
let n_next = n[i].skipHiddenNodes
|
||||
if n_next.kind == nkInfix:
|
||||
if n_next[0].kind in {nkSym, nkIdent} and n[0].kind in {nkSym, nkIdent}:
|
||||
let nextId = if n_next[0].kind == nkSym: n_next[0].sym.name else: n_next[0].ident
|
||||
let nNext = n[i].skipHiddenNodes
|
||||
if nNext.kind == nkInfix:
|
||||
if nNext[0].kind in {nkSym, nkIdent} and n[0].kind in {nkSym, nkIdent}:
|
||||
let nextId = if nNext[0].kind == nkSym: nNext[0].sym.name else: nNext[0].ident
|
||||
let nnId = if n[0].kind == nkSym: n[0].sym.name else: n[0].ident
|
||||
if getPrecedence(nextId) < getPrecedence(nnId):
|
||||
needsParenthesis = true
|
||||
if i == 1:
|
||||
if getPrecedence(nextId) < getPrecedence(nnId):
|
||||
needsParenthesis = true
|
||||
elif i == 2:
|
||||
if getPrecedence(nextId) <= getPrecedence(nnId):
|
||||
needsParenthesis = true
|
||||
if needsParenthesis:
|
||||
put(g, tkParLe, "(")
|
||||
gsub(g, n, i)
|
||||
@@ -957,7 +966,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
put(g, tkColon, ":")
|
||||
gsub(g, n, n.len-1)
|
||||
else:
|
||||
if sonsLen(n) >= 1: accentedName(g, n[0])
|
||||
if len(n) >= 1: accentedName(g, n[0])
|
||||
put(g, tkParLe, "(")
|
||||
gcomma(g, n, 1)
|
||||
put(g, tkParRi, ")")
|
||||
@@ -1037,14 +1046,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
gcomma(g, n)
|
||||
put(g, tkParRi, ")")
|
||||
of nkObjDownConv, nkObjUpConv:
|
||||
if sonsLen(n) >= 1: gsub(g, n.sons[0])
|
||||
if len(n) >= 1: gsub(g, n.sons[0])
|
||||
put(g, tkParLe, "(")
|
||||
gcomma(g, n, 1)
|
||||
put(g, tkParRi, ")")
|
||||
of nkClosedSymChoice, nkOpenSymChoice:
|
||||
if renderIds in g.flags:
|
||||
put(g, tkParLe, "(")
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if i > 0: put(g, tkOpr, "|")
|
||||
if n.sons[i].kind == nkSym:
|
||||
let s = n[i].sym
|
||||
@@ -1106,7 +1115,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
gsub(g, n, bodyPos)
|
||||
of nkConstDef, nkIdentDefs:
|
||||
gcomma(g, n, 0, -3)
|
||||
var L = sonsLen(n)
|
||||
var L = len(n)
|
||||
if L >= 2 and n.sons[L - 2].kind != nkEmpty:
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gsub(g, n, L - 2)
|
||||
@@ -1144,10 +1153,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
elif n[0].kind == nkSym: n[0].sym.name
|
||||
elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name
|
||||
else: nil
|
||||
let n_next = skipHiddenNodes(n[1])
|
||||
if n_next.kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
|
||||
let nNext = skipHiddenNodes(n[1])
|
||||
if nNext.kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
|
||||
put(g, tkSpaces, Space)
|
||||
if n_next.kind == nkInfix:
|
||||
if nNext.kind == nkInfix:
|
||||
put(g, tkParLe, "(")
|
||||
gsub(g, n.sons[1])
|
||||
put(g, tkParRi, ")")
|
||||
@@ -1191,19 +1200,19 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
if n.len > 0: gsub(g, n.sons[0])
|
||||
put(g, tkParRi, ")")
|
||||
of nkRefTy:
|
||||
if sonsLen(n) > 0:
|
||||
if len(n) > 0:
|
||||
putWithSpace(g, tkRef, "ref")
|
||||
gsub(g, n.sons[0])
|
||||
else:
|
||||
put(g, tkRef, "ref")
|
||||
of nkPtrTy:
|
||||
if sonsLen(n) > 0:
|
||||
if len(n) > 0:
|
||||
putWithSpace(g, tkPtr, "ptr")
|
||||
gsub(g, n.sons[0])
|
||||
else:
|
||||
put(g, tkPtr, "ptr")
|
||||
of nkVarTy:
|
||||
if sonsLen(n) > 0:
|
||||
if len(n) > 0:
|
||||
putWithSpace(g, tkVar, "var")
|
||||
gsub(g, n.sons[0])
|
||||
else:
|
||||
@@ -1234,7 +1243,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
putWithSpace(g, tkEquals, "=")
|
||||
gsub(g, n.sons[2])
|
||||
of nkObjectTy:
|
||||
if sonsLen(n) > 0:
|
||||
if len(n) > 0:
|
||||
putWithSpace(g, tkObject, "object")
|
||||
gsub(g, n.sons[0])
|
||||
gsub(g, n.sons[1])
|
||||
@@ -1244,7 +1253,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
put(g, tkObject, "object")
|
||||
of nkRecList:
|
||||
indentNL(g)
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
optNL(g)
|
||||
gsub(g, n.sons[i], c)
|
||||
gcoms(g)
|
||||
@@ -1254,14 +1263,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
putWithSpace(g, tkOf, "of")
|
||||
gsub(g, n, 0)
|
||||
of nkProcTy:
|
||||
if sonsLen(n) > 0:
|
||||
if len(n) > 0:
|
||||
putWithSpace(g, tkProc, "proc")
|
||||
gsub(g, n, 0)
|
||||
gsub(g, n, 1)
|
||||
else:
|
||||
put(g, tkProc, "proc")
|
||||
of nkIteratorTy:
|
||||
if sonsLen(n) > 0:
|
||||
if len(n) > 0:
|
||||
putWithSpace(g, tkIterator, "iterator")
|
||||
gsub(g, n, 0)
|
||||
gsub(g, n, 1)
|
||||
@@ -1274,7 +1283,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
gsub(g, n.sons[0])
|
||||
put(g, tkBracketRi, "]")
|
||||
of nkEnumTy:
|
||||
if sonsLen(n) > 0:
|
||||
if len(n) > 0:
|
||||
putWithSpace(g, tkEnum, "enum")
|
||||
gsub(g, n.sons[0])
|
||||
gcoms(g)
|
||||
@@ -1332,7 +1341,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
incl(a.flags, rfInConstExpr)
|
||||
gsection(g, n, a, tkConst, "const")
|
||||
of nkVarSection, nkLetSection, nkUsingStmt:
|
||||
var L = sonsLen(n)
|
||||
var L = len(n)
|
||||
if L == 0: return
|
||||
if n.kind == nkVarSection: putWithSpace(g, tkVar, "var")
|
||||
elif n.kind == nkLetSection: putWithSpace(g, tkLet, "let")
|
||||
@@ -1543,7 +1552,7 @@ proc renderModule*(n: PNode, infile, outfile: string,
|
||||
g: TSrcGen
|
||||
initSrcGen(g, renderFlags, conf)
|
||||
g.fid = fid
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
gsub(g, n.sons[i])
|
||||
optNL(g)
|
||||
case n.sons[i].kind
|
||||
@@ -1576,3 +1585,15 @@ proc getTokSym*(r: TSrcGen): PSym =
|
||||
result = r.tokens[r.idx-1].sym
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc quoteExpr*(a: string): string {.inline.} =
|
||||
## can be used for quoting expressions in error msgs.
|
||||
"'" & a & "'"
|
||||
|
||||
proc genFieldError*(field: PSym, disc: PSym): string =
|
||||
## this needs to be in a module accessible by jsgen, ccgexprs, and vm to
|
||||
## provide this error msg FieldError; msgs would be better but it does not
|
||||
## import ast
|
||||
result = field.name.s.quoteExpr & " is not accessible using discriminant " &
|
||||
disc.name.s.quoteExpr & " of type " &
|
||||
disc.owner.name.s.quoteExpr
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
import
|
||||
intsets, ast, idents, algorithm, renderer, parser, os, strutils,
|
||||
sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables,
|
||||
intsets, ast, idents, algorithm, renderer, os, strutils,
|
||||
msgs, modulegraphs, syntaxes, options, modulepaths,
|
||||
lineinfos
|
||||
|
||||
type
|
||||
@@ -151,10 +151,10 @@ proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
|
||||
if a.kind == nkIncludeStmt:
|
||||
for i in 0..<a.len:
|
||||
var f = checkModuleName(graph.config, a.sons[i])
|
||||
if f != InvalidFileIDX:
|
||||
if f != InvalidFileIdx:
|
||||
if containsOrIncl(includedFiles, f.int):
|
||||
localError(graph.config, a.info, "recursive dependency: '$1'" %
|
||||
toFilename(graph.config, f))
|
||||
toMsgFilename(graph.config, f))
|
||||
else:
|
||||
let nn = includeModule(graph, module, f)
|
||||
let nnn = expandIncludes(graph, module, nn, modulePath,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## This module implements the canonalization for the various caching mechanisms.
|
||||
|
||||
import ast, idgen, lineinfos, msgs, incremental, modulegraphs, pathutils
|
||||
import ast, idgen, lineinfos, incremental, modulegraphs, pathutils
|
||||
|
||||
when not nimIncremental:
|
||||
template setupModuleCache*(g: ModuleGraph) = discard
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## This module implements the new compilation cache.
|
||||
|
||||
import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types,
|
||||
import strutils, intsets, tables, ropes, db_sqlite, msgs, options,
|
||||
renderer, rodutils, idents, astalgo, btrees, magicsys, cgmeth, extccomp,
|
||||
btrees, trees, condsyms, nversion, pathutils
|
||||
|
||||
@@ -17,7 +17,6 @@ import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types,
|
||||
## - Dependency computation should use *signature* hashes in order to
|
||||
## avoid recompiling dependent modules.
|
||||
## - Patch the rest of the compiler to do lazy loading of proc bodies.
|
||||
## - Patch the C codegen to cache proc bodies and maybe types.
|
||||
|
||||
template db(): DbConn = g.incr.db
|
||||
|
||||
@@ -72,9 +71,12 @@ proc getModuleId(g: ModuleGraph; fileIdx: FileIndex; fullpath: AbsoluteFile): in
|
||||
# not changed, so use the cached AST:
|
||||
doAssert(result != 0)
|
||||
var cycleCheck = initIntSet()
|
||||
if not needsRecompile(g, fileIdx, fullpath, cycleCheck) and not g.incr.configChanged:
|
||||
echo "cached successfully! ", string fullpath
|
||||
return -result
|
||||
if not needsRecompile(g, fileIdx, fullpath, cycleCheck):
|
||||
if not g.incr.configChanged or g.config.symbolFiles == readOnlySf:
|
||||
#echo "cached successfully! ", string fullpath
|
||||
return -result
|
||||
elif g.config.symbolFiles == readOnlySf:
|
||||
internalError(g.config, "file needs to be recompiled: " & (string fullpath))
|
||||
db.exec(sql"update modules set fullHash = ? where id = ?", currentFullhash, module[0])
|
||||
db.exec(sql"delete from deps where module = ?", module[0])
|
||||
db.exec(sql"delete from types where module = ?", module[0])
|
||||
@@ -154,7 +156,7 @@ proc encodeNode(g: ModuleGraph; fInfo: TLineInfo, n: PNode,
|
||||
encodeVInt(n.sym.id, result)
|
||||
pushSym(w, n.sym)
|
||||
else:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
encodeNode(g, n.info, n.sons[i], result)
|
||||
add(result, ')')
|
||||
|
||||
@@ -221,22 +223,16 @@ proc encodeType(g: ModuleGraph, t: PType, result: var string) =
|
||||
if t.lockLevel.ord != UnspecifiedLockLevel.ord:
|
||||
add(result, '\14')
|
||||
encodeVInt(t.lockLevel.int16, result)
|
||||
if t.destructor != nil and t.destructor.id != 0:
|
||||
if t.paddingAtEnd != 0:
|
||||
add(result, '\15')
|
||||
encodeVInt(t.destructor.id, result)
|
||||
pushSym(w, t.destructor)
|
||||
if t.deepCopy != nil:
|
||||
encodeVInt(t.paddingAtEnd, result)
|
||||
for a in t.attachedOps:
|
||||
add(result, '\16')
|
||||
encodeVInt(t.deepcopy.id, result)
|
||||
pushSym(w, t.deepcopy)
|
||||
if t.assignment != nil:
|
||||
add(result, '\17')
|
||||
encodeVInt(t.assignment.id, result)
|
||||
pushSym(w, t.assignment)
|
||||
if t.sink != nil:
|
||||
add(result, '\18')
|
||||
encodeVInt(t.sink.id, result)
|
||||
pushSym(w, t.sink)
|
||||
if a == nil:
|
||||
encodeVInt(-1, result)
|
||||
else:
|
||||
encodeVInt(a.id, result)
|
||||
pushSym(w, a)
|
||||
for i, s in items(t.methods):
|
||||
add(result, '\19')
|
||||
encodeVInt(i, result)
|
||||
@@ -248,7 +244,7 @@ proc encodeType(g: ModuleGraph, t: PType, result: var string) =
|
||||
add(result, '\21')
|
||||
encodeVInt(t.typeInst.uniqueId, result)
|
||||
pushType(w, t.typeInst)
|
||||
for i in 0 ..< sonsLen(t):
|
||||
for i in 0 ..< len(t):
|
||||
if t.sons[i] == nil:
|
||||
add(result, "^()")
|
||||
else:
|
||||
@@ -305,7 +301,7 @@ proc encodeSym(g: ModuleGraph, s: PSym, result: var string) =
|
||||
pushSym(w, s.owner)
|
||||
if s.flags != {}:
|
||||
result.add('$')
|
||||
encodeVInt(cast[int32](s.flags), result)
|
||||
encodeVBiggestInt(cast[int64](s.flags), result)
|
||||
if s.magic != mNone:
|
||||
result.add('@')
|
||||
encodeVInt(ord(s.magic), result)
|
||||
@@ -429,9 +425,7 @@ proc storeRemaining*(g: ModuleGraph; module: PSym) =
|
||||
transitiveClosure(g)
|
||||
var nimid = 0
|
||||
for x in items(g.config.m.fileInfos):
|
||||
# don't store the "command line" entry:
|
||||
if nimid != 0:
|
||||
storeFilename(g, x.fullPath, FileIndex(nimid))
|
||||
storeFilename(g, x.fullPath, FileIndex(nimid))
|
||||
inc nimid
|
||||
|
||||
# ---------------- decoder -----------------------------------
|
||||
@@ -642,16 +636,15 @@ proc loadType(g; id: int; info: TLineInfo): PType =
|
||||
|
||||
if b.s[b.pos] == '\15':
|
||||
inc(b.pos)
|
||||
result.destructor = loadSym(g, decodeVInt(b.s, b.pos), info)
|
||||
if b.s[b.pos] == '\16':
|
||||
inc(b.pos)
|
||||
result.deepCopy = loadSym(g, decodeVInt(b.s, b.pos), info)
|
||||
if b.s[b.pos] == '\17':
|
||||
inc(b.pos)
|
||||
result.assignment = loadSym(g, decodeVInt(b.s, b.pos), info)
|
||||
if b.s[b.pos] == '\18':
|
||||
inc(b.pos)
|
||||
result.sink = loadSym(g, decodeVInt(b.s, b.pos), info)
|
||||
result.paddingAtEnd = decodeVInt(b.s, b.pos).int16
|
||||
|
||||
for a in low(result.attachedOps)..high(result.attachedOps):
|
||||
if b.s[b.pos] == '\16':
|
||||
inc(b.pos)
|
||||
let id = decodeVInt(b.s, b.pos)
|
||||
if id >= 0:
|
||||
result.attachedOps[a] = loadSym(g, id, info)
|
||||
|
||||
while b.s[b.pos] == '\19':
|
||||
inc(b.pos)
|
||||
let x = decodeVInt(b.s, b.pos)
|
||||
@@ -739,7 +732,7 @@ proc loadSymFromBlob(g; b; info: TLineInfo): PSym =
|
||||
result.owner = loadSym(g, decodeVInt(b.s, b.pos), result.info)
|
||||
if b.s[b.pos] == '$':
|
||||
inc(b.pos)
|
||||
result.flags = cast[TSymFlags](int32(decodeVInt(b.s, b.pos)))
|
||||
result.flags = cast[TSymFlags](decodeVBiggestInt(b.s, b.pos))
|
||||
if b.s[b.pos] == '@':
|
||||
inc(b.pos)
|
||||
result.magic = TMagic(decodeVInt(b.s, b.pos))
|
||||
@@ -772,6 +765,7 @@ proc loadSymFromBlob(g; b; info: TLineInfo): PSym =
|
||||
if b.s[b.pos] == '\24':
|
||||
inc b.pos
|
||||
result.transformedBody = decodeNode(g, b, result.info)
|
||||
#result.transformedBody = nil
|
||||
of skModule, skPackage:
|
||||
decodeInstantiations(g, b, result.info, result.usedGenerics)
|
||||
of skLet, skVar, skField, skForVar:
|
||||
@@ -785,7 +779,7 @@ proc loadSymFromBlob(g; b; info: TLineInfo): PSym =
|
||||
|
||||
if b.s[b.pos] == '(':
|
||||
#if result.kind in routineKinds:
|
||||
# result.ast = decodeNodeLazyBody(b, result.info, result)
|
||||
# result.ast = nil
|
||||
#else:
|
||||
result.ast = decodeNode(g, b, result.info)
|
||||
if sfCompilerProc in result.flags:
|
||||
@@ -846,7 +840,7 @@ proc replay(g: ModuleGraph; module: PSym; n: PNode) =
|
||||
of "error": localError(g.config, n.info, errUser, n[1].strVal)
|
||||
of "compile":
|
||||
internalAssert g.config, n.len == 3 and n[2].kind == nkStrLit
|
||||
let cname = AbsoluteFile n[1].strVal,
|
||||
let cname = AbsoluteFile n[1].strVal
|
||||
var cf = Cfile(nimname: splitFile(cname).name, cname: cname,
|
||||
obj: AbsoluteFile n[2].strVal,
|
||||
flags: {CfileFlag.External})
|
||||
@@ -902,6 +896,10 @@ proc replay(g: ModuleGraph; module: PSym; n: PNode) =
|
||||
internalAssert g.config, imported.id < 0
|
||||
of nkStmtList, nkStmtListExpr:
|
||||
for x in n: replay(g, module, x)
|
||||
of nkExportStmt:
|
||||
for x in n:
|
||||
doAssert x.kind == nkSym
|
||||
strTableAdd(module.tab, x.sym)
|
||||
else: discard "nothing to do for this node"
|
||||
|
||||
proc loadNode*(g: ModuleGraph; module: PSym): PNode =
|
||||
|
||||
@@ -35,7 +35,7 @@ proc c_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf",
|
||||
|
||||
proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
|
||||
case classify(f)
|
||||
of fcNaN:
|
||||
of fcNan:
|
||||
result = "NAN"
|
||||
of fcNegZero:
|
||||
result = "-0.0" & literalPostfix
|
||||
@@ -46,14 +46,9 @@ proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
|
||||
of fcNegInf:
|
||||
result = "-INF"
|
||||
else:
|
||||
when defined(nimNoArrayToCstringConversion):
|
||||
result = newString(81)
|
||||
let n = c_snprintf(result.cstring, result.len.uint, "%#.16e%s", f, literalPostfix.cstring)
|
||||
setLen(result, n)
|
||||
else:
|
||||
var buf: array[0..80, char]
|
||||
discard c_snprintf(buf.cstring, buf.len.uint, "%#.16e%s", f, literalPostfix.cstring)
|
||||
result = $buf.cstring
|
||||
result = newString(81)
|
||||
let n = c_snprintf(result.cstring, result.len.uint, "%#.16e%s", f, literalPostfix.cstring)
|
||||
setLen(result, n)
|
||||
|
||||
proc encodeStr*(s: string, result: var string) =
|
||||
for i in 0 ..< len(s):
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
## language.
|
||||
|
||||
import
|
||||
ast, modules, idents, passes, passaux, condsyms,
|
||||
options, nimconf, sem, semdata, llstream, vm, vmdef, commands, msgs,
|
||||
os, times, osproc, wordrecg, strtabs, modulegraphs, lineinfos, pathutils
|
||||
ast, modules, idents, passes, condsyms,
|
||||
options, sem, llstream, vm, vmdef, commands, msgs,
|
||||
os, times, osproc, wordrecg, strtabs, modulegraphs,
|
||||
lineinfos, pathutils
|
||||
|
||||
# we support 'cmpIgnoreStyle' natively for efficiency:
|
||||
from strutils import cmpIgnoreStyle, contains
|
||||
@@ -61,9 +62,15 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
|
||||
cbos listDirs:
|
||||
listDirs(a, {pcDir})
|
||||
cbos removeDir:
|
||||
os.removeDir getString(a, 0)
|
||||
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
|
||||
discard
|
||||
else:
|
||||
os.removeDir getString(a, 0)
|
||||
cbos removeFile:
|
||||
os.removeFile getString(a, 0)
|
||||
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
|
||||
discard
|
||||
else:
|
||||
os.removeFile getString(a, 0)
|
||||
cbos createDir:
|
||||
os.createDir getString(a, 0)
|
||||
|
||||
@@ -75,20 +82,35 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
|
||||
cbos getCurrentDir:
|
||||
setResult(a, os.getCurrentDir())
|
||||
cbos moveFile:
|
||||
os.moveFile(getString(a, 0), getString(a, 1))
|
||||
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
|
||||
discard
|
||||
else:
|
||||
os.moveFile(getString(a, 0), getString(a, 1))
|
||||
cbos moveDir:
|
||||
os.moveDir(getString(a, 0), getString(a, 1))
|
||||
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
|
||||
discard
|
||||
else:
|
||||
os.moveDir(getString(a, 0), getString(a, 1))
|
||||
cbos copyFile:
|
||||
os.copyFile(getString(a, 0), getString(a, 1))
|
||||
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
|
||||
discard
|
||||
else:
|
||||
os.copyFile(getString(a, 0), getString(a, 1))
|
||||
cbos copyDir:
|
||||
os.copyDir(getString(a, 0), getString(a, 1))
|
||||
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
|
||||
discard
|
||||
else:
|
||||
os.copyDir(getString(a, 0), getString(a, 1))
|
||||
cbos getLastModificationTime:
|
||||
setResult(a, getLastModificationTime(getString(a, 0)).toUnix)
|
||||
cbos findExe:
|
||||
setResult(a, os.findExe(getString(a, 0)))
|
||||
|
||||
cbos rawExec:
|
||||
setResult(a, osproc.execCmd getString(a, 0))
|
||||
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
|
||||
discard
|
||||
else:
|
||||
setResult(a, osproc.execCmd getString(a, 0))
|
||||
|
||||
cbconf getEnv:
|
||||
setResult(a, os.getEnv(a.getString 0, a.getString 1))
|
||||
@@ -96,6 +118,8 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
|
||||
setResult(a, os.existsEnv(a.getString 0))
|
||||
cbconf putEnv:
|
||||
os.putEnv(a.getString 0, a.getString 1)
|
||||
cbconf delEnv:
|
||||
os.delEnv(a.getString 0)
|
||||
cbconf dirExists:
|
||||
setResult(a, os.dirExists(a.getString 0))
|
||||
cbconf fileExists:
|
||||
@@ -161,11 +185,17 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
|
||||
cbconf cppDefine:
|
||||
options.cppDefine(conf, a.getString(0))
|
||||
cbexc stdinReadLine, EOFError:
|
||||
setResult(a, "")
|
||||
setResult(a, stdin.readLine())
|
||||
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
|
||||
discard
|
||||
else:
|
||||
setResult(a, "")
|
||||
setResult(a, stdin.readLine())
|
||||
cbexc stdinReadAll, EOFError:
|
||||
setResult(a, "")
|
||||
setResult(a, stdin.readAll())
|
||||
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
|
||||
discard
|
||||
else:
|
||||
setResult(a, "")
|
||||
setResult(a, stdin.readAll())
|
||||
|
||||
proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
|
||||
freshDefines=true; conf: ConfigRef) =
|
||||
@@ -184,6 +214,12 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
|
||||
|
||||
conf.searchPaths.add(conf.libpath)
|
||||
|
||||
let oldGlobalOptions = conf.globalOptions
|
||||
let oldSelectedGC = conf.selectedGC
|
||||
undefSymbol(conf.symbols, "nimv2")
|
||||
conf.globalOptions.excl optNimV2
|
||||
conf.selectedGC = gcUnselected
|
||||
|
||||
var m = graph.makeModule(scriptName)
|
||||
incl(m.flags, sfMainModule)
|
||||
graph.vm = setupVM(m, cache, scriptName.string, graph)
|
||||
@@ -191,6 +227,14 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
|
||||
graph.compileSystemModule() # TODO: see why this unsets hintConf in conf.notes
|
||||
discard graph.processModule(m, llStreamOpen(scriptName, fmRead))
|
||||
|
||||
# watch out, "newruntime" can be set within NimScript itself and then we need
|
||||
# to remember this:
|
||||
if optNimV2 in oldGlobalOptions:
|
||||
conf.globalOptions.incl optNimV2
|
||||
defineSymbol(conf.symbols, "nimv2")
|
||||
if conf.selectedGC == gcUnselected:
|
||||
conf.selectedGC = oldSelectedGC
|
||||
|
||||
# ensure we load 'system.nim' again for the real non-config stuff!
|
||||
resetSystemArtifacts(graph)
|
||||
# do not remove the defined symbols
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
# This module implements the semantic checking pass.
|
||||
|
||||
import
|
||||
ast, strutils, hashes, options, lexer, astalgo, trees, treetab,
|
||||
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
|
||||
magicsys, parser, nversion, nimsets, semfold, modulepaths, importer,
|
||||
ast, strutils, options, astalgo, trees,
|
||||
wordrecg, ropes, msgs, idents, renderer, types, platform, math,
|
||||
magicsys, nversion, nimsets, semfold, modulepaths, importer,
|
||||
procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch,
|
||||
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
||||
evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
|
||||
lowerings, pluginsupport, plugins/active, rod, lineinfos, strtabs
|
||||
lowerings, plugins/active, rod, lineinfos, strtabs, int128
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward
|
||||
|
||||
@@ -24,7 +24,7 @@ when defined(nimfix):
|
||||
import nimfix/prettybase
|
||||
|
||||
when not defined(leanCompiler):
|
||||
import semparallel
|
||||
import spawn, semparallel
|
||||
|
||||
# implementation
|
||||
|
||||
@@ -77,14 +77,12 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
|
||||
discard safeSemExpr(c, n)
|
||||
|
||||
proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode =
|
||||
result = arg
|
||||
let x = result.skipConv
|
||||
let x = arg.skipConv
|
||||
if x.kind in {nkPar, nkTupleConstr, nkCurly} and formal.kind != tyUntyped:
|
||||
changeType(c, x, formal, check=true)
|
||||
else:
|
||||
result = skipHiddenSubConv(result)
|
||||
#result.typ = takeType(formal, arg.typ)
|
||||
#echo arg.info, " picked ", result.typ.typeToString
|
||||
result = arg
|
||||
result = skipHiddenSubConv(result)
|
||||
|
||||
|
||||
proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
|
||||
if arg.typ.isNil:
|
||||
@@ -405,7 +403,13 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||
if s.typ.sons[0] == nil:
|
||||
result = semStmt(c, result, flags)
|
||||
else:
|
||||
case s.typ.sons[0].kind
|
||||
var retType = s.typ.sons[0]
|
||||
if retType.kind == tyTypeDesc and tfUnresolved in retType.flags and
|
||||
retType.len == 1:
|
||||
# bug #11941: template fails(T: type X, v: auto): T
|
||||
# does not mean we expect a tyTypeDesc.
|
||||
retType = retType[0]
|
||||
case retType.kind
|
||||
of tyUntyped:
|
||||
# Not expecting a type here allows templates like in ``tmodulealias.in``.
|
||||
result = semExpr(c, result, flags)
|
||||
@@ -423,7 +427,6 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||
result.typ = makeTypeDesc(c, typ)
|
||||
#result = symNodeFromType(c, typ, n.info)
|
||||
else:
|
||||
var retType = s.typ.sons[0]
|
||||
if s.ast[genericParamsPos] != nil and retType.isMetaType:
|
||||
# The return type may depend on the Macro arguments
|
||||
# e.g. template foo(T: typedesc): seq[T]
|
||||
@@ -444,13 +447,14 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||
|
||||
const
|
||||
errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters"
|
||||
errFloatToString = "cannot convert '$1' to '$2'"
|
||||
|
||||
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||
flags: TExprFlags = {}): PNode =
|
||||
pushInfoContext(c.config, nOrig.info, sym.detailedInfo)
|
||||
|
||||
let info = getCallLineInfo(n)
|
||||
markUsed(c.config, info, sym, c.graph.usageSym)
|
||||
markUsed(c, info, sym)
|
||||
onUse(info, sym)
|
||||
if sym == c.p.owner:
|
||||
globalError(c.config, info, "recursive dependency: '$1'" % sym.name.s)
|
||||
@@ -523,12 +527,6 @@ proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
|
||||
if sfSystemModule in module.flags:
|
||||
graph.systemModule = module
|
||||
c.topLevelScope = openScope(c)
|
||||
# don't be verbose unless the module belongs to the main package:
|
||||
if module.owner.id == graph.config.mainPackageId:
|
||||
graph.config.notes = graph.config.mainPackageNotes
|
||||
else:
|
||||
if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes
|
||||
graph.config.notes = graph.config.foreignPackageNotes
|
||||
result = c
|
||||
|
||||
proc isImportSystemStmt(g: ModuleGraph; n: PNode): bool =
|
||||
@@ -577,7 +575,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||
if c.lastGenericIdx < c.generics.len:
|
||||
var a = newNodeI(nkStmtList, n.info)
|
||||
addCodeForGenerics(c, a)
|
||||
if sonsLen(a) > 0:
|
||||
if len(a) > 0:
|
||||
# a generic has been added to `a`:
|
||||
if result.kind != nkEmpty: addSon(a, result)
|
||||
result = a
|
||||
@@ -618,12 +616,18 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
|
||||
#if c.config.cmd == cmdIdeTools: findSuggest(c, n)
|
||||
rod.storeNode(c.graph, c.module, result)
|
||||
|
||||
proc reportUnusedModules(c: PContext) =
|
||||
for i in 0..high(c.unusedImports):
|
||||
if sfUsed notin c.unusedImports[i][0].flags:
|
||||
message(c.config, c.unusedImports[i][1], warnUnusedImportX, c.unusedImports[i][0].name.s)
|
||||
|
||||
proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
|
||||
var c = PContext(context)
|
||||
if c.config.cmd == cmdIdeTools and not c.suggestionsMade:
|
||||
suggestSentinel(c)
|
||||
closeScope(c) # close module's scope
|
||||
rawCloseScope(c) # imported symbols; don't check for unused ones!
|
||||
reportUnusedModules(c)
|
||||
result = newNode(nkStmtList)
|
||||
if n != nil:
|
||||
internalError(c.config, n.info, "n is not nil") #result := n;
|
||||
|
||||
@@ -107,7 +107,6 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
elif errorsEnabled or z.diagnosticsEnabled:
|
||||
errors.add(CandidateError(
|
||||
sym: sym,
|
||||
unmatchedVarParam: int z.mutabilityProblem,
|
||||
firstMismatch: z.firstMismatch,
|
||||
diagnostics: z.diagnostics))
|
||||
else:
|
||||
@@ -173,14 +172,16 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||
var filterOnlyFirst = false
|
||||
if optShowAllMismatches notin c.config.globalOptions:
|
||||
for err in errors:
|
||||
if err.firstMismatch > 1:
|
||||
if err.firstMismatch.arg > 1:
|
||||
filterOnlyFirst = true
|
||||
break
|
||||
|
||||
var maybeWrongSpace = false
|
||||
|
||||
var candidates = ""
|
||||
var skipped = 0
|
||||
for err in errors:
|
||||
if filterOnlyFirst and err.firstMismatch == 1:
|
||||
if filterOnlyFirst and err.firstMismatch.arg == 1:
|
||||
inc skipped
|
||||
continue
|
||||
if err.sym.kind in routineKinds and err.sym.ast != nil:
|
||||
@@ -189,39 +190,47 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||
else:
|
||||
add(candidates, getProcHeader(c.config, err.sym, prefer))
|
||||
add(candidates, "\n")
|
||||
if err.firstMismatch != 0 and n.len > 1:
|
||||
let cond = n.len > 2
|
||||
if cond:
|
||||
candidates.add(" first type mismatch at position: " & $abs(err.firstMismatch))
|
||||
if err.firstMismatch >= 0: candidates.add("\n required type: ")
|
||||
else: candidates.add("\n unknown named parameter: " & $n[-err.firstMismatch][0])
|
||||
var wanted, got: PType = nil
|
||||
if err.firstMismatch < 0:
|
||||
discard
|
||||
elif err.firstMismatch < err.sym.typ.len:
|
||||
wanted = err.sym.typ.sons[err.firstMismatch]
|
||||
if cond: candidates.add typeToString(wanted)
|
||||
else:
|
||||
if cond: candidates.add "none"
|
||||
if err.firstMismatch > 0 and err.firstMismatch < n.len:
|
||||
if cond:
|
||||
candidates.add "\n but expression '"
|
||||
candidates.add renderTree(n[err.firstMismatch])
|
||||
let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil
|
||||
let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: ""
|
||||
if n.len > 1:
|
||||
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
|
||||
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
|
||||
case err.firstMismatch.kind
|
||||
of kUnknownNamedParam: candidates.add("\n unknown named parameter: " & $nArg[0])
|
||||
of kAlreadyGiven: candidates.add("\n named param already provided: " & $nArg[0])
|
||||
of kPositionalAlreadyGiven: candidates.add("\n positional param was already given as named param")
|
||||
of kExtraArg: candidates.add("\n extra argument given")
|
||||
of kMissingParam: candidates.add("\n missing parameter: " & nameParam)
|
||||
of kTypeMismatch, kVarNeeded:
|
||||
doAssert nArg != nil
|
||||
var wanted = err.firstMismatch.formal.typ
|
||||
doAssert err.firstMismatch.formal != nil
|
||||
candidates.add("\n required type for " & nameParam & ": ")
|
||||
candidates.add typeToString(wanted)
|
||||
candidates.add "\n but expression '"
|
||||
if err.firstMismatch.kind == kVarNeeded:
|
||||
candidates.add renderNotLValue(nArg)
|
||||
candidates.add "' is immutable, not 'var'"
|
||||
else:
|
||||
candidates.add renderTree(nArg)
|
||||
candidates.add "' is of type: "
|
||||
got = n[err.firstMismatch].typ
|
||||
if cond: candidates.add typeToString(got)
|
||||
if wanted != nil and got != nil:
|
||||
effectProblem(wanted, got, candidates)
|
||||
if cond: candidates.add "\n"
|
||||
if err.unmatchedVarParam != 0 and err.unmatchedVarParam < n.len:
|
||||
candidates.add(" for a 'var' type a variable needs to be passed, but '" &
|
||||
renderNotLValue(n[err.unmatchedVarParam]) &
|
||||
"' is immutable\n")
|
||||
var got = nArg.typ
|
||||
candidates.add typeToString(got)
|
||||
doAssert wanted != nil
|
||||
if got != nil: effectProblem(wanted, got, candidates)
|
||||
of kUnknown: discard "do not break 'nim check'"
|
||||
candidates.add "\n"
|
||||
if err.firstMismatch.arg == 1 and nArg.kind == nkTupleConstr and
|
||||
n.kind == nkCommand:
|
||||
maybeWrongSpace = true
|
||||
for diag in err.diagnostics:
|
||||
candidates.add(diag & "\n")
|
||||
if skipped > 0:
|
||||
candidates.add($skipped & " other mismatching symbols have been " &
|
||||
"suppressed; compile with --showAllMismatches:on to see them\n")
|
||||
if maybeWrongSpace:
|
||||
candidates.add("maybe misplaced space between " & renderTree(n[0]) & " and '(' \n")
|
||||
|
||||
result = (prefer, candidates)
|
||||
|
||||
const
|
||||
@@ -260,7 +269,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
|
||||
while symx != nil:
|
||||
if symx.kind in routineKinds:
|
||||
errors.add(CandidateError(sym: symx,
|
||||
unmatchedVarParam: 0, firstMismatch: 0,
|
||||
firstMismatch: MismatchInfo(),
|
||||
diagnostics: @[],
|
||||
enabled: false))
|
||||
symx = nextOverloadIter(o, c, headSymbol)
|
||||
@@ -396,7 +405,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
elif c.config.errorCounter == 0:
|
||||
# don't cascade errors
|
||||
var args = "("
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
if i > 1: add(args, ", ")
|
||||
add(args, typeToString(n.sons[i].typ))
|
||||
add(args, ")")
|
||||
@@ -474,7 +483,7 @@ proc semResolvedCall(c: PContext, x: TCandidate,
|
||||
assert x.state == csMatch
|
||||
var finalCallee = x.calleeSym
|
||||
let info = getCallLineInfo(n)
|
||||
markUsed(c.config, info, finalCallee, c.graph.usageSym)
|
||||
markUsed(c, info, finalCallee)
|
||||
onUse(info, finalCallee)
|
||||
assert finalCallee.ast != nil
|
||||
if x.hasFauxMatch:
|
||||
@@ -568,7 +577,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||
# binding has to stay 'nil' for this to work!
|
||||
initCandidate(c, m, s, nil)
|
||||
|
||||
for i in 1..sonsLen(n)-1:
|
||||
for i in 1..len(n)-1:
|
||||
let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
|
||||
var arg = n[i].typ
|
||||
# try transforming the argument into a static one before feeding it into
|
||||
@@ -584,16 +593,16 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||
var newInst = generateInstance(c, s, m.bindings, n.info)
|
||||
newInst.typ.flags.excl tfUnresolved
|
||||
let info = getCallLineInfo(n)
|
||||
markUsed(c.config, info, s, c.graph.usageSym)
|
||||
markUsed(c, info, s)
|
||||
onUse(info, s)
|
||||
result = newSymNode(newInst, info)
|
||||
|
||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
assert n.kind == nkBracketExpr
|
||||
for i in 1..sonsLen(n)-1:
|
||||
for i in 1..len(n)-1:
|
||||
let e = semExpr(c, n.sons[i])
|
||||
if e.typ == nil:
|
||||
localError(c.config, e.info, "expression has no type")
|
||||
n.sons[i].typ = errorType(c)
|
||||
else:
|
||||
n.sons[i].typ = e.typ.skipTypes({tyTypeDesc})
|
||||
var s = s
|
||||
|
||||
@@ -10,11 +10,8 @@
|
||||
## This module contains the data structures for the semantic checking phase.
|
||||
|
||||
import
|
||||
strutils, intsets, options, lexer, ast, astalgo, trees, treetab,
|
||||
wordrecg,
|
||||
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
|
||||
magicsys, nversion, nimsets, parser, times, passes, vmdef,
|
||||
modulegraphs, lineinfos
|
||||
intsets, options, ast, astalgo, msgs, idents, renderer,
|
||||
magicsys, vmdef, modulegraphs, lineinfos, sets
|
||||
|
||||
type
|
||||
TOptionEntry* = object # entries to put on a stack for pragma parsing
|
||||
@@ -74,7 +71,8 @@ type
|
||||
TExprFlags* = set[TExprFlag]
|
||||
|
||||
PContext* = ref TContext
|
||||
TContext* = object of TPassContext # a context represents a module
|
||||
TContext* = object of TPassContext # a context represents the module
|
||||
# that is currently being compiled
|
||||
enforceVoidContext*: PType
|
||||
module*: PSym # the module sym belonging to the context
|
||||
currentScope*: PScope # current scope
|
||||
@@ -139,6 +137,8 @@ type
|
||||
# the generic type has been constructed completely. See
|
||||
# tests/destructor/topttree.nim for an example that
|
||||
# would otherwise fail.
|
||||
unusedImports*: seq[(PSym, TLineInfo)]
|
||||
exportIndirections*: HashSet[(int, int)]
|
||||
|
||||
template config*(c: PContext): ConfigRef = c.graph.config
|
||||
|
||||
@@ -368,7 +368,7 @@ proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
|
||||
if n.typ != nil and n.typ.n == nil:
|
||||
result.flags.incl tfUnresolved
|
||||
result.n = newNode(nkRange, n.info, @[
|
||||
newIntTypeNode(nkIntLit, 0, intType),
|
||||
newIntTypeNode(0, intType),
|
||||
makeStaticExpr(c, nMinusOne(c, n))])
|
||||
|
||||
template rangeHasUnresolvedStatic*(t: PType): bool =
|
||||
@@ -392,8 +392,8 @@ proc makeRangeType*(c: PContext; first, last: BiggestInt;
|
||||
info: TLineInfo; intType: PType = nil): PType =
|
||||
let intType = if intType != nil: intType else: getSysType(c.graph, info, tyInt)
|
||||
var n = newNodeI(nkRange, info)
|
||||
addSon(n, newIntTypeNode(nkIntLit, first, intType))
|
||||
addSon(n, newIntTypeNode(nkIntLit, last, intType))
|
||||
addSon(n, newIntTypeNode(first, intType))
|
||||
addSon(n, newIntTypeNode(last, intType))
|
||||
result = newTypeS(tyRange, c)
|
||||
result.n = n
|
||||
addSonSkipIntLit(result, intType) # basetype of range
|
||||
@@ -410,10 +410,10 @@ proc illFormedAstLocal*(n: PNode; conf: ConfigRef) =
|
||||
localError(conf, n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||
|
||||
proc checkSonsLen*(n: PNode, length: int; conf: ConfigRef) =
|
||||
if sonsLen(n) != length: illFormedAst(n, conf)
|
||||
if len(n) != length: illFormedAst(n, conf)
|
||||
|
||||
proc checkMinSonsLen*(n: PNode, length: int; conf: ConfigRef) =
|
||||
if sonsLen(n) < length: illFormedAst(n, conf)
|
||||
if len(n) < length: illFormedAst(n, conf)
|
||||
|
||||
proc isTopLevel*(c: PContext): bool {.inline.} =
|
||||
result = c.currentScope.depthLevel <= 2
|
||||
|
||||
@@ -25,12 +25,12 @@ const
|
||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||
flags: TExprFlags = {}): PNode =
|
||||
let info = getCallLineInfo(n)
|
||||
markUsed(c.config, info, s, c.graph.usageSym)
|
||||
markUsed(c, info, s)
|
||||
onUse(info, s)
|
||||
# Note: This is n.info on purpose. It prevents template from creating an info
|
||||
# context when called from an another template
|
||||
pushInfoContext(c.config, n.info, s.detailedInfo)
|
||||
result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags)
|
||||
result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache, efFromHlo in flags)
|
||||
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
|
||||
popInfoContext(c.config)
|
||||
|
||||
@@ -149,10 +149,10 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus =
|
||||
(srcBaseTyp.kind in IntegralTypes):
|
||||
if targetTyp.isOrdinalType:
|
||||
if src.kind in nkCharLit..nkUInt64Lit and
|
||||
src.intVal notin firstOrd(c.config, targetTyp)..lastOrd(c.config, targetTyp):
|
||||
src.getInt notin firstOrd(c.config, targetTyp)..lastOrd(c.config, targetTyp):
|
||||
result = convNotInRange
|
||||
elif src.kind in nkFloatLit..nkFloat64Lit and
|
||||
(classify(src.floatVal) in {fcNaN, fcNegInf, fcInf} or
|
||||
(classify(src.floatVal) in {fcNan, fcNegInf, fcInf} or
|
||||
src.floatVal.int64 notin firstOrd(c.config, targetTyp)..lastOrd(c.config, targetTyp)):
|
||||
result = convNotInRange
|
||||
elif targetBaseTyp.kind in tyFloat..tyFloat64:
|
||||
@@ -160,7 +160,7 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus =
|
||||
not floatRangeCheck(src.floatVal, targetTyp):
|
||||
result = convNotInRange
|
||||
elif src.kind in nkCharLit..nkUInt64Lit and
|
||||
not floatRangeCheck(src.intval.float, targetTyp):
|
||||
not floatRangeCheck(src.intVal.float, targetTyp):
|
||||
result = convNotInRange
|
||||
else:
|
||||
# we use d, s here to speed up that operation a bit:
|
||||
@@ -220,8 +220,12 @@ proc maybeLiftType(t: var PType, c: PContext, info: TLineInfo) =
|
||||
closeScope(c)
|
||||
if lifted != nil: t = lifted
|
||||
|
||||
proc isOwnedSym(c: PContext; n: PNode): bool =
|
||||
let s = qualifiedLookUp(c, n, {})
|
||||
result = s != nil and sfSystemModule in s.owner.flags and s.name.s == "owned"
|
||||
|
||||
proc semConv(c: PContext, n: PNode): PNode =
|
||||
if sonsLen(n) != 2:
|
||||
if len(n) != 2:
|
||||
localError(c.config, n.info, "a type conversion takes exactly one argument")
|
||||
return n
|
||||
|
||||
@@ -247,7 +251,7 @@ proc semConv(c: PContext, n: PNode): PNode =
|
||||
|
||||
maybeLiftType(targetType, c, n[0].info)
|
||||
|
||||
if targetType.kind in {tySink, tyLent, tyOwned}:
|
||||
if targetType.kind in {tySink, tyLent} or isOwnedSym(c, n[0]):
|
||||
let baseType = semTypeNode(c, n.sons[1], nil).skipTypes({tyTypeDesc})
|
||||
let t = newTypeS(targetType.kind, c)
|
||||
if targetType.kind == tyOwned:
|
||||
@@ -297,11 +301,11 @@ proc semConv(c: PContext, n: PNode): PNode =
|
||||
localError(c.config, n.info, errGenerated, value & " can't be converted to " &
|
||||
result.typ.typeToString)
|
||||
else:
|
||||
for i in 0 ..< sonsLen(op):
|
||||
for i in 0 ..< len(op):
|
||||
let it = op.sons[i]
|
||||
let status = checkConvertible(c, result.typ, it)
|
||||
if status in {convOK, convNotNeedeed}:
|
||||
markUsed(c.config, n.info, it.sym, c.graph.usageSym)
|
||||
markUsed(c, n.info, it.sym)
|
||||
onUse(n.info, it.sym)
|
||||
markIndirect(c, it.sym)
|
||||
return it
|
||||
@@ -327,7 +331,7 @@ proc semCast(c: PContext, n: PNode): PNode =
|
||||
proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
|
||||
const
|
||||
opToStr: array[mLow..mHigh, string] = ["low", "high"]
|
||||
if sonsLen(n) != 2:
|
||||
if len(n) != 2:
|
||||
localError(c.config, n.info, errXExpectsTypeOrValue % opToStr[m])
|
||||
else:
|
||||
n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
|
||||
@@ -337,7 +341,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
|
||||
n.typ = getSysType(c.graph, n.info, tyInt)
|
||||
of tyArray:
|
||||
n.typ = typ.sons[0] # indextype
|
||||
of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32, tyFloat..tyFloat64:
|
||||
of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt..tyUInt64, tyFloat..tyFloat64:
|
||||
n.typ = n.sons[1].typ.skipTypes({tyTypeDesc})
|
||||
of tyGenericParam:
|
||||
# prepare this for resolving in semtypinst:
|
||||
@@ -365,7 +369,7 @@ proc fixupStaticType(c: PContext, n: PNode) =
|
||||
|
||||
proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
internalAssert c.config,
|
||||
n.sonsLen == 3 and
|
||||
n.len == 3 and
|
||||
n[1].typ != nil and
|
||||
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
||||
|
||||
@@ -404,7 +408,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result.typ = n.typ
|
||||
|
||||
proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
if sonsLen(n) != 3:
|
||||
if len(n) != 3:
|
||||
localError(c.config, n.info, "'is' operator takes 2 arguments")
|
||||
|
||||
let boolType = getSysType(c.graph, n.info, tyBool)
|
||||
@@ -448,9 +452,9 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
|
||||
proc semOpAux(c: PContext, n: PNode) =
|
||||
const flags = {efDetermineType}
|
||||
for i in 1 ..< n.sonsLen:
|
||||
for i in 1 ..< n.len:
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
|
||||
if a.kind == nkExprEqExpr and len(a) == 2:
|
||||
let info = a.sons[0].info
|
||||
a.sons[0] = newIdentNode(considerQuotedIdent(c, a.sons[0], a), info)
|
||||
a.sons[1] = semExprWithType(c, a.sons[1], flags)
|
||||
@@ -466,22 +470,22 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
addSon(result, newIdentNode(par, n.info))
|
||||
for i in 0 ..< sonsLen(n): addSon(result, n.sons[i])
|
||||
for i in 0 ..< len(n): addSon(result, n.sons[i])
|
||||
result = semExpr(c, result)
|
||||
|
||||
proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
|
||||
case n.kind
|
||||
of nkCurly, nkBracket:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
changeType(c, n.sons[i], elemType(newType), check)
|
||||
of nkPar, nkTupleConstr:
|
||||
let tup = newType.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
|
||||
if tup.kind != tyTuple:
|
||||
if tup.kind == tyObject: return
|
||||
globalError(c.config, n.info, "no tuple type for constructor")
|
||||
elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
|
||||
elif len(n) > 0 and n.sons[0].kind == nkExprColonExpr:
|
||||
# named tuple?
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
var m = n.sons[i].sons[0]
|
||||
if m.kind != nkSym:
|
||||
globalError(c.config, m.info, "invalid tuple constructor")
|
||||
@@ -495,7 +499,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
|
||||
else:
|
||||
changeType(c, n.sons[i].sons[1], tup.sons[i], check)
|
||||
else:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
changeType(c, n.sons[i], tup.sons[i], check)
|
||||
when false:
|
||||
var m = n.sons[i]
|
||||
@@ -509,43 +513,61 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
|
||||
if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
|
||||
localError(c.config, n.info, "cannot convert " & $value &
|
||||
" to " & typeToString(newType))
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
if check and not floatRangeCheck(n.floatVal, newType):
|
||||
localError(c.config, n.info, errFloatToString % [$n.floatVal, typeToString(newType)])
|
||||
else: discard
|
||||
n.typ = newType
|
||||
|
||||
proc arrayConstrType(c: PContext, n: PNode): PType =
|
||||
var typ = newTypeS(tyArray, c)
|
||||
rawAddSon(typ, nil) # index type
|
||||
if sonsLen(n) == 0:
|
||||
if len(n) == 0:
|
||||
rawAddSon(typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
|
||||
else:
|
||||
var t = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
||||
addSonSkipIntLit(typ, t)
|
||||
typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info)
|
||||
typ.sons[0] = makeRangeType(c, 0, len(n) - 1, n.info)
|
||||
result = typ
|
||||
|
||||
proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = newNodeI(nkBracket, n.info)
|
||||
result.typ = newTypeS(tyArray, c)
|
||||
rawAddSon(result.typ, nil) # index type
|
||||
if sonsLen(n) == 0:
|
||||
var
|
||||
firstIndex, lastIndex: Int128
|
||||
indexType = getSysType(c.graph, n.info, tyInt)
|
||||
lastValidIndex = lastOrd(c.config, indexType)
|
||||
if len(n) == 0:
|
||||
rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
|
||||
lastIndex = toInt128(-1)
|
||||
else:
|
||||
var x = n.sons[0]
|
||||
var lastIndex: BiggestInt = 0
|
||||
var indexType = getSysType(c.graph, n.info, tyInt)
|
||||
if x.kind == nkExprColonExpr and sonsLen(x) == 2:
|
||||
if x.kind == nkExprColonExpr and len(x) == 2:
|
||||
var idx = semConstExpr(c, x.sons[0])
|
||||
lastIndex = getOrdValue(idx)
|
||||
indexType = idx.typ
|
||||
x = x.sons[1]
|
||||
if not isOrdinalType(idx.typ):
|
||||
localError(c.config, idx.info, "expected ordinal value for array " &
|
||||
"index, got '$1'" % renderTree(idx))
|
||||
else:
|
||||
firstIndex = getOrdValue(idx)
|
||||
lastIndex = firstIndex
|
||||
indexType = idx.typ
|
||||
lastValidIndex = lastOrd(c.config, indexType)
|
||||
x = x.sons[1]
|
||||
|
||||
let yy = semExprWithType(c, x)
|
||||
var typ = yy.typ
|
||||
addSon(result, yy)
|
||||
#var typ = skipTypes(result.sons[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal})
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
if lastIndex == lastValidIndex:
|
||||
let validIndex = makeRangeType(c, toInt64(firstIndex), toInt64(lastValidIndex), n.info,
|
||||
indexType)
|
||||
localError(c.config, n.info, "size of array exceeds range of index " &
|
||||
"type '$1' by $2 elements" % [typeToString(validIndex), $(n.len-i)])
|
||||
|
||||
x = n.sons[i]
|
||||
if x.kind == nkExprColonExpr and sonsLen(x) == 2:
|
||||
if x.kind == nkExprColonExpr and len(x) == 2:
|
||||
var idx = semConstExpr(c, x.sons[0])
|
||||
idx = fitNode(c, indexType, idx, x.info)
|
||||
if lastIndex+1 != getOrdValue(idx):
|
||||
@@ -561,7 +583,8 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
addSonSkipIntLit(result.typ, typ)
|
||||
for i in 0 ..< result.len:
|
||||
result.sons[i] = fitNode(c, typ, result.sons[i], result.sons[i].info)
|
||||
result.typ.sons[0] = makeRangeType(c, 0, sonsLen(result) - 1, n.info)
|
||||
result.typ.sons[0] = makeRangeType(c, toInt64(firstIndex), toInt64(lastIndex), n.info,
|
||||
indexType)
|
||||
|
||||
proc fixAbstractType(c: PContext, n: PNode) =
|
||||
for i in 1 ..< n.len:
|
||||
@@ -660,8 +683,8 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||
if n.sons[0].kind == nkSym and n.sons[0].sym.magic in FakeVarParams:
|
||||
# BUGFIX: check for L-Value still needs to be done for the arguments!
|
||||
# note sometimes this is eval'ed twice so we check for nkHiddenAddr here:
|
||||
for i in 1 ..< sonsLen(n):
|
||||
if i < sonsLen(t) and t.sons[i] != nil and
|
||||
for i in 1 ..< len(n):
|
||||
if i < len(t) and t.sons[i] != nil and
|
||||
skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
|
||||
let it = n[i]
|
||||
if isAssignable(c, it) notin {arLValue, arLocalLValue}:
|
||||
@@ -676,13 +699,13 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||
localError(c.config, n.info, errXStackEscape % renderTree(n[1], {renderNoComments}))
|
||||
|
||||
return
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
let n = if n.kind == nkHiddenDeref: n[0] else: n
|
||||
if n.sons[i].kind == nkHiddenCallConv:
|
||||
# we need to recurse explicitly here as converters can create nested
|
||||
# calls and then they wouldn't be analysed otherwise
|
||||
analyseIfAddressTakenInCall(c, n.sons[i])
|
||||
if i < sonsLen(t) and
|
||||
if i < len(t) and
|
||||
skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
|
||||
if n.sons[i].kind != nkHiddenAddr:
|
||||
n.sons[i] = analyseIfAddressTaken(c, n.sons[i])
|
||||
@@ -844,9 +867,10 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
||||
analyseIfAddressTakenInCall(c, result)
|
||||
if callee.magic != mNone:
|
||||
result = magicsAfterOverloadResolution(c, result, flags)
|
||||
if result.typ != nil and
|
||||
not (result.typ.kind == tySequence and result.typ.sons[0].kind == tyEmpty):
|
||||
liftTypeBoundOps(c, result.typ, n.info)
|
||||
when false:
|
||||
if result.typ != nil and
|
||||
not (result.typ.kind == tySequence and result.typ.sons[0].kind == tyEmpty):
|
||||
liftTypeBoundOps(c, result.typ, n.info)
|
||||
#result = patchResolvedTypeBoundOp(c, result)
|
||||
if c.matchedConcept == nil:
|
||||
result = evalAtCompileTime(c, result)
|
||||
@@ -863,7 +887,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = n0
|
||||
result.kind = nkCall
|
||||
result.flags.incl nfExplicitCall
|
||||
for i in 1 ..< sonsLen(n): addSon(result, n.sons[i])
|
||||
for i in 1 ..< len(n): addSon(result, n.sons[i])
|
||||
return semExpr(c, result, flags)
|
||||
else:
|
||||
n.sons[0] = n0
|
||||
@@ -882,7 +906,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
semOpAux(c, n)
|
||||
var t: PType = nil
|
||||
if n.sons[0].typ != nil:
|
||||
t = skipTypes(n.sons[0].typ, abstractInst+{tyOwned}-{tyTypeDesc})
|
||||
t = skipTypes(n.sons[0].typ, abstractInst+{tyOwned}-{tyTypeDesc, tyDistinct})
|
||||
if t != nil and t.kind == tyProc:
|
||||
# This is a proc variable, apply normal overload resolution
|
||||
let m = resolveIndirectCall(c, n, nOrig, t)
|
||||
@@ -894,7 +918,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
else:
|
||||
var hasErrorType = false
|
||||
var msg = "type mismatch: got <"
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
if i > 1: add(msg, ", ")
|
||||
let nt = n.sons[i].typ
|
||||
add(msg, typeToString(nt))
|
||||
@@ -982,7 +1006,7 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
|
||||
result = nil
|
||||
case r.kind
|
||||
of nkRecList:
|
||||
for i in 0 ..< sonsLen(r):
|
||||
for i in 0 ..< len(r):
|
||||
result = lookupInRecordAndBuildCheck(c, n, r.sons[i], field, check)
|
||||
if result != nil: return
|
||||
of nkRecCase:
|
||||
@@ -992,19 +1016,19 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
|
||||
if result != nil: return
|
||||
let setType = createSetType(c, r.sons[0].typ)
|
||||
var s = newNodeIT(nkCurly, r.info, setType)
|
||||
for i in 1 ..< sonsLen(r):
|
||||
for i in 1 ..< len(r):
|
||||
var it = r.sons[i]
|
||||
case it.kind
|
||||
of nkOfBranch:
|
||||
result = lookupInRecordAndBuildCheck(c, n, lastSon(it), field, check)
|
||||
if result == nil:
|
||||
for j in 0..sonsLen(it)-2: addSon(s, copyTree(it.sons[j]))
|
||||
for j in 0..len(it)-2: addSon(s, copyTree(it.sons[j]))
|
||||
else:
|
||||
if check == nil:
|
||||
check = newNodeI(nkCheckedFieldExpr, n.info)
|
||||
addSon(check, c.graph.emptyNode) # make space for access node
|
||||
s = newNodeIT(nkCurly, n.info, setType)
|
||||
for j in 0 .. sonsLen(it) - 2: addSon(s, copyTree(it.sons[j]))
|
||||
for j in 0 .. len(it) - 2: addSon(s, copyTree(it.sons[j]))
|
||||
var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool))
|
||||
addSon(inExpr, newSymNode(c.graph.opContains, n.info))
|
||||
addSon(inExpr, s)
|
||||
@@ -1085,7 +1109,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
let s = getGenSym(c, sym)
|
||||
case s.kind
|
||||
of skConst:
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
markUsed(c, n.info, s)
|
||||
onUse(n.info, s)
|
||||
let typ = skipTypes(s.typ, abstractInst-{tyTypeDesc})
|
||||
case typ.kind
|
||||
@@ -1117,7 +1141,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
of skMacro:
|
||||
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
|
||||
(n.kind notin nkCallKinds and s.requiredParams > 0):
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
markUsed(c, n.info, s)
|
||||
onUse(n.info, s)
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
else:
|
||||
@@ -1127,13 +1151,13 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
(n.kind notin nkCallKinds and s.requiredParams > 0) or
|
||||
sfCustomPragma in sym.flags:
|
||||
let info = getCallLineInfo(n)
|
||||
markUsed(c.config, info, s, c.graph.usageSym)
|
||||
markUsed(c, info, s)
|
||||
onUse(info, s)
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
else:
|
||||
result = semTemplateExpr(c, n, s, flags)
|
||||
of skParam:
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
markUsed(c, n.info, s)
|
||||
onUse(n.info, s)
|
||||
if s.typ != nil and s.typ.kind == tyStatic and s.typ.n != nil:
|
||||
# XXX see the hack in sigmatch.nim ...
|
||||
@@ -1157,7 +1181,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
if s.magic == mNimvm:
|
||||
localError(c.config, n.info, "illegal context for 'nimvm' magic")
|
||||
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
markUsed(c, n.info, s)
|
||||
onUse(n.info, s)
|
||||
result = newSymNode(s, n.info)
|
||||
# We cannot check for access to outer vars for example because it's still
|
||||
@@ -1175,7 +1199,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
n.typ = s.typ
|
||||
return n
|
||||
of skType:
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
markUsed(c, n.info, s)
|
||||
onUse(n.info, s)
|
||||
if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil:
|
||||
return s.typ.n
|
||||
@@ -1197,7 +1221,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
if f != nil and fieldVisible(c, f):
|
||||
# is the access to a public field or in the same module or in a friend?
|
||||
doAssert f == s
|
||||
markUsed(c.config, n.info, f, c.graph.usageSym)
|
||||
markUsed(c, n.info, f)
|
||||
onUse(n.info, f)
|
||||
result = newNodeIT(nkDotExpr, n.info, f.typ)
|
||||
result.add makeDeref(newSymNode(p.selfSym))
|
||||
@@ -1210,12 +1234,13 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
if ty.sons[0] == nil: break
|
||||
ty = skipTypes(ty.sons[0], skipPtrs)
|
||||
# old code, not sure if it's live code:
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
markUsed(c, n.info, s)
|
||||
onUse(n.info, s)
|
||||
result = newSymNode(s, n.info)
|
||||
else:
|
||||
let info = getCallLineInfo(n)
|
||||
markUsed(c.config, info, s, c.graph.usageSym)
|
||||
#if efInCall notin flags:
|
||||
markUsed(c, info, s)
|
||||
onUse(info, s)
|
||||
result = newSymNode(s, info)
|
||||
|
||||
@@ -1237,7 +1262,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
if result.kind == nkSym: result = semSym(c, n, s, flags)
|
||||
else:
|
||||
markUsed(c.config, n.sons[1].info, s, c.graph.usageSym)
|
||||
markUsed(c, n.sons[1].info, s)
|
||||
result = semSym(c, n, s, flags)
|
||||
onUse(n.sons[1].info, s)
|
||||
return
|
||||
@@ -1301,7 +1326,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = newSymNode(f)
|
||||
result.info = n.info
|
||||
result.typ = ty
|
||||
markUsed(c.config, n.info, f, c.graph.usageSym)
|
||||
markUsed(c, n.info, f)
|
||||
onUse(n.info, f)
|
||||
return
|
||||
of tyObject, tyTuple:
|
||||
@@ -1336,7 +1361,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
else: true
|
||||
if not visibilityCheckNeeded or fieldVisible(c, f):
|
||||
# is the access to a public field or in the same module or in a friend?
|
||||
markUsed(c.config, n.sons[1].info, f, c.graph.usageSym)
|
||||
markUsed(c, n.sons[1].info, f)
|
||||
onUse(n.sons[1].info, f)
|
||||
n.sons[0] = makeDeref(n.sons[0])
|
||||
n.sons[1] = newSymNode(f) # we now have the correct field
|
||||
@@ -1350,7 +1375,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
elif ty.kind == tyTuple and ty.n != nil:
|
||||
f = getSymFromList(ty.n, i)
|
||||
if f != nil:
|
||||
markUsed(c.config, n.sons[1].info, f, c.graph.usageSym)
|
||||
markUsed(c, n.sons[1].info, f)
|
||||
onUse(n.sons[1].info, f)
|
||||
n.sons[0] = makeDeref(n.sons[0])
|
||||
n.sons[1] = newSymNode(f)
|
||||
@@ -1399,7 +1424,7 @@ proc semDeref(c: PContext, n: PNode): PNode =
|
||||
proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
## returns nil if not a built-in subscript operator; also called for the
|
||||
## checking of assignments
|
||||
if sonsLen(n) == 1:
|
||||
if len(n) == 1:
|
||||
let x = semDeref(c, n)
|
||||
if x == nil: return nil
|
||||
result = newNodeIT(nkDerefExpr, x.info, x.typ)
|
||||
@@ -1426,7 +1451,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
tyUncheckedArray:
|
||||
if n.len != 2: return nil
|
||||
n.sons[0] = makeDeref(n.sons[0])
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
n.sons[i] = semExprWithType(c, n.sons[i],
|
||||
flags*{efInTypeof, efDetermineType})
|
||||
# Arrays index type is dictated by the range's type
|
||||
@@ -1457,7 +1482,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal, tyAlias, tySink}).kind in
|
||||
{tyInt..tyInt64}:
|
||||
let idx = getOrdValue(n.sons[1])
|
||||
if idx >= 0 and idx < len(arr): n.typ = arr.sons[int(idx)]
|
||||
if idx >= 0 and idx < len(arr): n.typ = arr.sons[toInt(idx)]
|
||||
else: localError(c.config, n.info, "invalid index value for tuple subscript")
|
||||
result = n
|
||||
else:
|
||||
@@ -1536,11 +1561,11 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
|
||||
of nkBracketExpr:
|
||||
if len(n) == 1: return n.sons[0]
|
||||
else: discard
|
||||
let valid = isAssignable(c, n)
|
||||
let valid = isAssignable(c, n, isLent)
|
||||
if valid != arLValue:
|
||||
if valid == arLocalLValue:
|
||||
localError(c.config, n.info, errXStackEscape % renderTree(n, {renderNoComments}))
|
||||
elif not isLent:
|
||||
else:
|
||||
localError(c.config, n.info, errExprHasNoAddress)
|
||||
result = newNodeIT(nkHiddenAddr, n.info, makePtrType(c, n.typ))
|
||||
result.add(n)
|
||||
@@ -1600,7 +1625,7 @@ proc borrowCheck(c: PContext, n, le, ri: PNode) =
|
||||
template resultTypeIsInferrable(typ: PType): untyped =
|
||||
typ.isMetaType and typ.kind != tyTypeDesc
|
||||
|
||||
proc goodLineInfo(arg: PNode): TLineinfo =
|
||||
proc goodLineInfo(arg: PNode): TLineInfo =
|
||||
if arg.kind == nkStmtListExpr and arg.len > 0:
|
||||
goodLineInfo(arg[^1])
|
||||
else:
|
||||
@@ -1689,8 +1714,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||
borrowCheck(c, n, lhs, rhs)
|
||||
|
||||
n.sons[1] = fitNode(c, le, rhs, goodLineInfo(n[1]))
|
||||
liftTypeBoundOps(c, lhs.typ, lhs.info)
|
||||
#liftTypeBoundOps(c, n.sons[0].typ, n.sons[0].info)
|
||||
when false: liftTypeBoundOps(c, lhs.typ, lhs.info)
|
||||
|
||||
fixAbstractType(c, n)
|
||||
asgnToResultVar(c, n, n.sons[0], n.sons[1])
|
||||
@@ -1757,21 +1781,21 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
|
||||
var t = skipTypes(restype, {tyGenericInst, tyAlias, tySink})
|
||||
case t.kind
|
||||
of tyVar, tyLent:
|
||||
if t.kind == tyVar: t.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
|
||||
t.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
|
||||
if n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
||||
n.sons[0] = n.sons[0].sons[1]
|
||||
n.sons[0] = takeImplicitAddr(c, n.sons[0], t.kind == tyLent)
|
||||
of tyTuple:
|
||||
for i in 0..<t.sonsLen:
|
||||
var e = skipTypes(t.sons[i], {tyGenericInst, tyAlias, tySink})
|
||||
for i in 0..<t.len:
|
||||
let e = skipTypes(t.sons[i], {tyGenericInst, tyAlias, tySink})
|
||||
if e.kind in {tyVar, tyLent}:
|
||||
if e.kind == tyVar: e.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
|
||||
e.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
|
||||
if n.sons[0].kind in {nkPar, nkTupleConstr}:
|
||||
n.sons[0].sons[i] = takeImplicitAddr(c, n.sons[0].sons[i], e.kind == tyLent)
|
||||
elif n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and
|
||||
n.sons[0].sons[1].kind in {nkPar, nkTupleConstr}:
|
||||
var a = n.sons[0].sons[1]
|
||||
a.sons[i] = takeImplicitAddr(c, a.sons[i], false)
|
||||
a.sons[i] = takeImplicitAddr(c, a.sons[i], e.kind == tyLent)
|
||||
else:
|
||||
localError(c.config, n.sons[0].info, errXExpected, "tuple constructor")
|
||||
else: discard
|
||||
@@ -1872,7 +1896,6 @@ proc expectString(c: PContext, n: PNode): string =
|
||||
|
||||
proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo): PSym =
|
||||
result = newSym(kind, c.cache.idAnon, getCurrOwner(c), info)
|
||||
result.flags = {sfGenSym}
|
||||
|
||||
proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||
let macroCall = n[1]
|
||||
@@ -1882,7 +1905,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||
if expandedSym.kind == skError: return n
|
||||
|
||||
macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
|
||||
markUsed(c.config, n.info, expandedSym, c.graph.usageSym)
|
||||
markUsed(c, n.info, expandedSym)
|
||||
onUse(n.info, expandedSym)
|
||||
|
||||
if isCallExpr(macroCall):
|
||||
@@ -1907,7 +1930,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
let info = macroCall.sons[0].info
|
||||
macroCall.sons[0] = newSymNode(cand, info)
|
||||
markUsed(c.config, info, cand, c.graph.usageSym)
|
||||
markUsed(c, info, cand)
|
||||
onUse(info, cand)
|
||||
|
||||
# we just perform overloading resolution here:
|
||||
@@ -1923,7 +1946,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||
|
||||
proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
|
||||
flags: TExprFlags = {}): PNode =
|
||||
if sonsLen(n) == 2:
|
||||
if len(n) == 2:
|
||||
n.sons[0] = newSymNode(magicSym, n.info)
|
||||
result = semExpandToAst(c, n)
|
||||
else:
|
||||
@@ -1996,7 +2019,14 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||
var tmpl = semTemplateDef(c, dummyTemplate)
|
||||
quotes[0] = tmpl[namePos]
|
||||
# This adds a call to newIdentNode("result") as the first argument to the template call
|
||||
quotes[1] = newNode(nkCall, n.info, @[newIdentNode(getIdent(c.cache, "newIdentNode"), n.info), newStrNode(nkStrLit, "result")])
|
||||
let identNodeSym = getCompilerProc(c.graph, "newIdentNode")
|
||||
# so that new Nim compilers can compile old macros.nim versions, we check for 'nil'
|
||||
# here and provide the old fallback solution:
|
||||
let identNode = if identNodeSym == nil:
|
||||
newIdentNode(getIdent(c.cache, "newIdentNode"), n.info)
|
||||
else:
|
||||
identNodeSym.newSymNode
|
||||
quotes[1] = newNode(nkCall, n.info, @[identNode, newStrNode(nkStrLit, "result")])
|
||||
result = newNode(nkCall, n.info, @[
|
||||
createMagic(c.graph, "getAst", mExpandToAst).newSymNode,
|
||||
newNode(nkCall, n.info, quotes)])
|
||||
@@ -2007,8 +2037,11 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
let oldErrorCount = c.config.errorCounter
|
||||
let oldErrorMax = c.config.errorMax
|
||||
let oldCompilesId = c.compilesContextId
|
||||
inc c.compilesContextIdGenerator
|
||||
c.compilesContextId = c.compilesContextIdGenerator
|
||||
# if this is a nested 'when compiles', do not increase the ID so that
|
||||
# generic instantations can still be cached for this level.
|
||||
if c.compilesContextId == 0:
|
||||
inc c.compilesContextIdGenerator
|
||||
c.compilesContextId = c.compilesContextIdGenerator
|
||||
# do not halt after first error:
|
||||
c.config.errorMax = high(int)
|
||||
|
||||
@@ -2050,14 +2083,14 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
|
||||
proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# we replace this node by a 'true' or 'false' node:
|
||||
if sonsLen(n) != 2: return semDirectOp(c, n, flags)
|
||||
if len(n) != 2: return semDirectOp(c, n, flags)
|
||||
|
||||
result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil))
|
||||
result.info = n.info
|
||||
result.typ = getSysType(c.graph, n.info, tyBool)
|
||||
|
||||
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
if sonsLen(n) == 3:
|
||||
if len(n) == 3:
|
||||
# XXX ugh this is really a hack: shallowCopy() can be overloaded only
|
||||
# with procs that take not 2 parameters:
|
||||
result = newNodeI(nkFastAsgn, n.info)
|
||||
@@ -2085,7 +2118,7 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
|
||||
# since it's an instantiation, we unmark it as a compilerproc. Otherwise
|
||||
# codegen would fail:
|
||||
if sfCompilerProc in result.flags:
|
||||
result.flags = result.flags - {sfCompilerProc, sfExportC, sfImportC}
|
||||
result.flags = result.flags - {sfCompilerProc, sfExportc, sfImportc}
|
||||
result.loc.r = nil
|
||||
|
||||
proc setMs(n: PNode, s: PSym): PNode =
|
||||
@@ -2094,50 +2127,55 @@ proc setMs(n: PNode, s: PSym): PNode =
|
||||
n.sons[0].info = n.info
|
||||
|
||||
proc semSizeof(c: PContext, n: PNode): PNode =
|
||||
if sonsLen(n) != 2:
|
||||
if len(n) != 2:
|
||||
localError(c.config, n.info, errXExpectsTypeOrValue % "sizeof")
|
||||
else:
|
||||
n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
|
||||
#restoreOldStyleType(n.sons[1])
|
||||
n.typ = getSysType(c.graph, n.info, tyInt)
|
||||
|
||||
let size = getSize(c.config, n[1].typ)
|
||||
if size >= 0:
|
||||
result = newIntNode(nkIntLit, size)
|
||||
result.info = n.info
|
||||
result.typ = n.typ
|
||||
else:
|
||||
result = n
|
||||
result = foldSizeOf(c.config, n, n)
|
||||
|
||||
proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
# this is a hotspot in the compiler!
|
||||
result = n
|
||||
case s.magic # magics that need special treatment
|
||||
of mAddr:
|
||||
markUsed(c, n.info, s)
|
||||
checkSonsLen(n, 2, c.config)
|
||||
result[0] = newSymNode(s, n[0].info)
|
||||
result[1] = semAddrArg(c, n.sons[1], s.name.s == "unsafeAddr")
|
||||
result.typ = makePtrType(c, result[1].typ)
|
||||
of mTypeOf:
|
||||
markUsed(c, n.info, s)
|
||||
result = semTypeOf(c, n)
|
||||
#of mArrGet: result = semArrGet(c, n, flags)
|
||||
#of mArrPut: result = semArrPut(c, n, flags)
|
||||
#of mAsgn: result = semAsgnOpr(c, n)
|
||||
of mDefined: result = semDefined(c, setMs(n, s), false)
|
||||
of mDefinedInScope: result = semDefined(c, setMs(n, s), true)
|
||||
of mCompiles: result = semCompiles(c, setMs(n, s), flags)
|
||||
#of mLow: result = semLowHigh(c, setMs(n, s), mLow)
|
||||
#of mHigh: result = semLowHigh(c, setMs(n, s), mHigh)
|
||||
of mIs: result = semIs(c, setMs(n, s), flags)
|
||||
#of mOf: result = semOf(c, setMs(n, s))
|
||||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
||||
of mExpandToAst: result = semExpandToAst(c, n, s, flags)
|
||||
of mQuoteAst: result = semQuoteAst(c, n)
|
||||
of mDefined:
|
||||
markUsed(c, n.info, s)
|
||||
result = semDefined(c, setMs(n, s), false)
|
||||
of mDefinedInScope:
|
||||
markUsed(c, n.info, s)
|
||||
result = semDefined(c, setMs(n, s), true)
|
||||
of mCompiles:
|
||||
markUsed(c, n.info, s)
|
||||
result = semCompiles(c, setMs(n, s), flags)
|
||||
of mIs:
|
||||
markUsed(c, n.info, s)
|
||||
result = semIs(c, setMs(n, s), flags)
|
||||
of mShallowCopy:
|
||||
markUsed(c, n.info, s)
|
||||
result = semShallowCopy(c, n, flags)
|
||||
of mExpandToAst:
|
||||
markUsed(c, n.info, s)
|
||||
result = semExpandToAst(c, n, s, flags)
|
||||
of mQuoteAst:
|
||||
markUsed(c, n.info, s)
|
||||
result = semQuoteAst(c, n)
|
||||
of mAstToStr:
|
||||
markUsed(c, n.info, s)
|
||||
checkSonsLen(n, 2, c.config)
|
||||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph)
|
||||
result.typ = getSysType(c.graph, n.info, tyString)
|
||||
of mParallel:
|
||||
markUsed(c, n.info, s)
|
||||
if parallel notin c.features:
|
||||
localError(c.config, n.info, "use the {.experimental.} pragma to enable 'parallel'")
|
||||
result = setMs(n, s)
|
||||
@@ -2147,23 +2185,30 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
result.sons[1] = semStmt(c, x, {})
|
||||
dec c.inParallelStmt
|
||||
of mSpawn:
|
||||
result = setMs(n, s)
|
||||
for i in 1 ..< n.len:
|
||||
result.sons[i] = semExpr(c, n.sons[i])
|
||||
let typ = result[^1].typ
|
||||
if not typ.isEmptyType:
|
||||
if spawnResult(typ, c.inParallelStmt > 0) == srFlowVar:
|
||||
result.typ = createFlowVar(c, typ, n.info)
|
||||
else:
|
||||
result.typ = typ
|
||||
result.add instantiateCreateFlowVarCall(c, typ, n.info).newSymNode
|
||||
markUsed(c, n.info, s)
|
||||
when defined(leanCompiler):
|
||||
localError(c.config, n.info, "compiler was built without 'spawn' support")
|
||||
result = n
|
||||
else:
|
||||
result.add c.graph.emptyNode
|
||||
result = setMs(n, s)
|
||||
for i in 1 ..< n.len:
|
||||
result.sons[i] = semExpr(c, n.sons[i])
|
||||
let typ = result[^1].typ
|
||||
if not typ.isEmptyType:
|
||||
if spawnResult(typ, c.inParallelStmt > 0) == srFlowVar:
|
||||
result.typ = createFlowVar(c, typ, n.info)
|
||||
else:
|
||||
result.typ = typ
|
||||
result.add instantiateCreateFlowVarCall(c, typ, n.info).newSymNode
|
||||
else:
|
||||
result.add c.graph.emptyNode
|
||||
of mProcCall:
|
||||
markUsed(c, n.info, s)
|
||||
result = setMs(n, s)
|
||||
result.sons[1] = semExpr(c, n.sons[1])
|
||||
result.typ = n[1].typ
|
||||
of mPlugin:
|
||||
markUsed(c, n.info, s)
|
||||
# semDirectOp with conditional 'afterCallActions':
|
||||
let nOrig = n.copyTree
|
||||
#semLazyOpAux(c, n)
|
||||
@@ -2180,6 +2225,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
if callee.magic != mNone:
|
||||
result = magicsAfterOverloadResolution(c, result, flags)
|
||||
of mRunnableExamples:
|
||||
markUsed(c, n.info, s)
|
||||
if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList:
|
||||
when false:
|
||||
# some of this dead code was moved to `prepareExamples`
|
||||
@@ -2196,7 +2242,9 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
result = setMs(n, s)
|
||||
else:
|
||||
result = c.graph.emptyNode
|
||||
of mSizeOf: result = semSizeof(c, setMs(n, s))
|
||||
of mSizeOf:
|
||||
markUsed(c, n.info, s)
|
||||
result = semSizeof(c, setMs(n, s))
|
||||
else:
|
||||
result = semDirectOp(c, n, flags)
|
||||
|
||||
@@ -2225,7 +2273,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||
whenNimvm = exprNode.sym.magic == mNimvm
|
||||
if whenNimvm: n.flags.incl nfLL
|
||||
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
var it = n.sons[i]
|
||||
case it.kind
|
||||
of nkElifBranch, nkElifExpr:
|
||||
@@ -2263,12 +2311,12 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||
proc semSetConstr(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkCurly, n.info)
|
||||
result.typ = newTypeS(tySet, c)
|
||||
if sonsLen(n) == 0:
|
||||
if len(n) == 0:
|
||||
rawAddSon(result.typ, newTypeS(tyEmpty, c))
|
||||
else:
|
||||
# only semantic checking for all elements, later type checking:
|
||||
var typ: PType = nil
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if isRange(n.sons[i]):
|
||||
checkSonsLen(n.sons[i], 3, c.config)
|
||||
n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1])
|
||||
@@ -2292,7 +2340,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
|
||||
elif lengthOrd(c.config, typ) > MaxSetElements:
|
||||
typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
|
||||
addSonSkipIntLit(result.typ, typ)
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
var m: PNode
|
||||
let info = n.sons[i].info
|
||||
if isRange(n.sons[i]):
|
||||
@@ -2311,7 +2359,7 @@ proc semTableConstr(c: PContext, n: PNode): PNode =
|
||||
var lastKey = 0
|
||||
for i in 0..n.len-1:
|
||||
var x = n.sons[i]
|
||||
if x.kind == nkExprColonExpr and sonsLen(x) == 2:
|
||||
if x.kind == nkExprColonExpr and len(x) == 2:
|
||||
for j in lastKey ..< i:
|
||||
var pair = newNodeI(nkTupleConstr, x.info)
|
||||
pair.add(n.sons[j])
|
||||
@@ -2333,7 +2381,7 @@ type
|
||||
paNone, paSingle, paTupleFields, paTuplePositions
|
||||
|
||||
proc checkPar(c: PContext; n: PNode): TParKind =
|
||||
var length = sonsLen(n)
|
||||
var length = len(n)
|
||||
if length == 0:
|
||||
result = paTuplePositions # ()
|
||||
elif length == 1:
|
||||
@@ -2359,12 +2407,10 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
var typ = newTypeS(tyTuple, c)
|
||||
typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
|
||||
var ids = initIntSet()
|
||||
for i in 0 ..< sonsLen(n):
|
||||
if n[i].kind != nkExprColonExpr or n[i][0].kind notin {nkSym, nkIdent}:
|
||||
for i in 0 ..< len(n):
|
||||
if n[i].kind != nkExprColonExpr:
|
||||
illFormedAst(n.sons[i], c.config)
|
||||
var id: PIdent
|
||||
if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident
|
||||
else: id = n.sons[i].sons[0].sym.name
|
||||
let id = considerQuotedIdent(c, n[i][0])
|
||||
if containsOrIncl(ids, id.id):
|
||||
localError(c.config, n.sons[i].info, errFieldInitTwice % id.s)
|
||||
n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1],
|
||||
@@ -2387,7 +2433,7 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = n # we don't modify n, but compute the type:
|
||||
result.kind = nkTupleConstr
|
||||
var typ = newTypeS(tyTuple, c) # leave typ.n nil!
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
n.sons[i] = semExprWithType(c, n.sons[i], flags*{efAllowDestructor})
|
||||
addSonSkipIntLit(typ, n.sons[i].typ)
|
||||
result.typ = typ
|
||||
@@ -2429,10 +2475,11 @@ proc semExportExcept(c: PContext, n: PNode): PNode =
|
||||
var s = initTabIter(i, exported.tab)
|
||||
while s != nil:
|
||||
if s.kind in ExportableSymKinds+{skModule} and
|
||||
s.name.id notin exceptSet:
|
||||
s.name.id notin exceptSet and sfError notin s.flags:
|
||||
strTableAdd(c.module.tab, s)
|
||||
result.add newSymNode(s, n.info)
|
||||
s = nextIter(i, exported.tab)
|
||||
markUsed(c, n.info, exported)
|
||||
|
||||
proc semExport(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkExportStmt, n.info)
|
||||
@@ -2452,14 +2499,16 @@ proc semExport(c: PContext, n: PNode): PNode =
|
||||
strTableAdd(c.module.tab, it)
|
||||
result.add newSymNode(it, a.info)
|
||||
it = nextIter(ti, s.tab)
|
||||
markUsed(c, n.info, s)
|
||||
else:
|
||||
while s != nil:
|
||||
if s.kind == skEnumField:
|
||||
localError(c.config, a.info, errGenerated, "cannot export: " & renderTree(a) &
|
||||
"; enum field cannot be exported individually")
|
||||
if s.kind in ExportableSymKinds+{skModule}:
|
||||
if s.kind in ExportableSymKinds+{skModule} and sfError notin s.flags:
|
||||
result.add(newSymNode(s, a.info))
|
||||
strTableAdd(c.module.tab, s)
|
||||
markUsed(c, n.info, s)
|
||||
s = nextOverloadIter(o, c, a)
|
||||
|
||||
proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
@@ -2706,7 +2755,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
of nkUsingStmt: result = semUsing(c, n)
|
||||
of nkAsmStmt: result = semAsm(c, n)
|
||||
of nkYieldStmt: result = semYield(c, n)
|
||||
of nkPragma: pragma(c, c.p.owner, n, stmtPragmas)
|
||||
of nkPragma: pragma(c, c.p.owner, n, stmtPragmas, true)
|
||||
of nkIteratorDef: result = semIterator(c, n)
|
||||
of nkProcDef: result = semProc(c, n)
|
||||
of nkFuncDef: result = semFunc(c, n)
|
||||
|
||||
@@ -27,7 +27,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
|
||||
of nkIdent, nkSym:
|
||||
result = n
|
||||
let ident = considerQuotedIdent(c.c, n)
|
||||
var L = sonsLen(forLoop)
|
||||
var L = len(forLoop)
|
||||
if c.replaceByFieldName:
|
||||
if ident.id == considerQuotedIdent(c.c, forLoop[0]).id:
|
||||
let fieldName = if c.tupleType.isNil: c.field.name.s
|
||||
@@ -54,8 +54,8 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
|
||||
localError(c.c.config, n.info,
|
||||
"'continue' not supported in a 'fields' loop")
|
||||
result = copyNode(n)
|
||||
newSons(result, sonsLen(n))
|
||||
for i in 0 ..< sonsLen(n):
|
||||
newSons(result, len(n))
|
||||
for i in 0 ..< len(n):
|
||||
result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
|
||||
|
||||
type
|
||||
@@ -120,9 +120,9 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
||||
var stmts = newNodeI(nkStmtList, n.info)
|
||||
result.sons[1] = stmts
|
||||
|
||||
var length = sonsLen(n)
|
||||
var length = len(n)
|
||||
var call = n.sons[length-2]
|
||||
if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
|
||||
if length-2 != len(call)-1 + ord(m==mFieldPairs):
|
||||
localError(c.config, n.info, errWrongNumberOfVariables)
|
||||
return result
|
||||
|
||||
@@ -139,7 +139,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
||||
inc(c.p.nestedLoopCounter)
|
||||
if tupleTypeA.kind == tyTuple:
|
||||
var loopBody = n.sons[length-1]
|
||||
for i in 0..sonsLen(tupleTypeA)-1:
|
||||
for i in 0..len(tupleTypeA)-1:
|
||||
openScope(c)
|
||||
var fc: TFieldInstCtx
|
||||
fc.tupleType = tupleTypeA
|
||||
|
||||
@@ -11,11 +11,16 @@
|
||||
# and evaluation phase
|
||||
|
||||
import
|
||||
strutils, options, ast, astalgo, trees, treetab, nimsets,
|
||||
nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
|
||||
strutils, options, ast, trees, nimsets,
|
||||
platform, math, msgs, idents, renderer, types,
|
||||
commands, magicsys, modulegraphs, strtabs, lineinfos
|
||||
|
||||
proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
proc errorType*(g: ModuleGraph): PType =
|
||||
## creates a type representing an error state
|
||||
result = newType(tyError, g.owners[^1])
|
||||
result.flags.incl tfCheckedForDestructor
|
||||
|
||||
proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode {.deprecated: "intVal should be Int128".} =
|
||||
case skipTypes(n.typ, abstractVarRange).kind
|
||||
of tyInt:
|
||||
result = newIntNode(nkIntLit, intVal)
|
||||
@@ -35,8 +40,20 @@ proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
result.typ = n.typ
|
||||
result.info = n.info
|
||||
|
||||
proc newIntNodeT*(intVal: Int128, n: PNode; g: ModuleGraph): PNode =
|
||||
result = newIntTypeNode(intVal, n.typ)
|
||||
# See bug #6989. 'pred' et al only produce an int literal type if the
|
||||
# original type was 'int', not a distinct int etc.
|
||||
if n.typ.kind == tyInt:
|
||||
# access cache for the int lit type
|
||||
result.typ = getIntLitType(g, result)
|
||||
result.info = n.info
|
||||
|
||||
proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
|
||||
result = newFloatNode(nkFloatLit, floatVal)
|
||||
if n.typ.skipTypes(abstractInst).kind == tyFloat32:
|
||||
result = newFloatNode(nkFloat32Lit, floatVal)
|
||||
else:
|
||||
result = newFloatNode(nkFloatLit, floatVal)
|
||||
result.typ = n.typ
|
||||
result.info = n.info
|
||||
|
||||
@@ -50,65 +67,30 @@ proc getConstExpr*(m: PSym, n: PNode; g: ModuleGraph): PNode
|
||||
# expression
|
||||
proc evalOp*(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode
|
||||
|
||||
proc checkInRange(conf: ConfigRef; n: PNode, res: BiggestInt): bool =
|
||||
if res in firstOrd(conf, n.typ)..lastOrd(conf, n.typ):
|
||||
result = true
|
||||
proc checkInRange(conf: ConfigRef; n: PNode, res: Int128): bool =
|
||||
res in firstOrd(conf, n.typ)..lastOrd(conf, n.typ)
|
||||
|
||||
proc foldAdd(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
let res = a +% b
|
||||
if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and
|
||||
checkInRange(g.config, n, res):
|
||||
proc foldAdd(a, b: Int128, n: PNode; g: ModuleGraph): PNode =
|
||||
let res = a + b
|
||||
if checkInRange(g.config, n, res):
|
||||
result = newIntNodeT(res, n, g)
|
||||
|
||||
proc foldSub*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
let res = a -% b
|
||||
if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and
|
||||
checkInRange(g.config, n, res):
|
||||
proc foldSub(a, b: Int128, n: PNode; g: ModuleGraph): PNode =
|
||||
let res = a - b
|
||||
if checkInRange(g.config, n, res):
|
||||
result = newIntNodeT(res, n, g)
|
||||
|
||||
proc foldUnarySub(a: BiggestInt, n: PNode, g: ModuleGraph): PNode =
|
||||
proc foldUnarySub(a: Int128, n: PNode, g: ModuleGraph): PNode =
|
||||
if a != firstOrd(g.config, n.typ):
|
||||
result = newIntNodeT(-a, n, g)
|
||||
|
||||
proc foldAbs*(a: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
proc foldAbs(a: Int128, n: PNode; g: ModuleGraph): PNode =
|
||||
if a != firstOrd(g.config, n.typ):
|
||||
result = newIntNodeT(abs(a), n, g)
|
||||
|
||||
proc foldMod*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
if b != 0'i64:
|
||||
result = newIntNodeT(a mod b, n, g)
|
||||
|
||||
proc foldModU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
if b != 0'i64:
|
||||
result = newIntNodeT(a %% b, n, g)
|
||||
|
||||
proc foldDiv*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
if b != 0'i64 and (a != firstOrd(g.config, n.typ) or b != -1'i64):
|
||||
result = newIntNodeT(a div b, n, g)
|
||||
|
||||
proc foldDivU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
if b != 0'i64:
|
||||
result = newIntNodeT(a /% b, n, g)
|
||||
|
||||
proc foldMul*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
let res = a *% b
|
||||
let floatProd = toBiggestFloat(a) * toBiggestFloat(b)
|
||||
let resAsFloat = toBiggestFloat(res)
|
||||
|
||||
# Fast path for normal case: small multiplicands, and no info
|
||||
# is lost in either method.
|
||||
if resAsFloat == floatProd and checkInRange(g.config, n, res):
|
||||
return newIntNodeT(res, n, g)
|
||||
|
||||
# Somebody somewhere lost info. Close enough, or way off? Note
|
||||
# that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
|
||||
# The difference either is or isn't significant compared to the
|
||||
# true value (of which floatProd is a good approximation).
|
||||
|
||||
# abs(diff)/abs(prod) <= 1/32 iff
|
||||
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
|
||||
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and
|
||||
checkInRange(g.config, n, res):
|
||||
proc foldMul(a, b: Int128, n: PNode; g: ModuleGraph): PNode =
|
||||
let res = a * b
|
||||
if checkInRange(g.config, n, res):
|
||||
return newIntNodeT(res, n, g)
|
||||
|
||||
proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
|
||||
@@ -119,10 +101,10 @@ proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
|
||||
var t = skipTypes(a.typ, abstractRange)
|
||||
case t.kind
|
||||
of tyChar:
|
||||
result = $chr(int(x) and 0xff)
|
||||
result = $chr(toInt64(x) and 0xff)
|
||||
of tyEnum:
|
||||
var n = t.n
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
if n.sons[i].kind != nkSym: internalError(g.config, a.info, "ordinalValToString")
|
||||
var field = n.sons[i].sym
|
||||
if field.position == x:
|
||||
@@ -157,7 +139,7 @@ proc makeRange(typ: PType, first, last: BiggestInt; g: ModuleGraph): PType =
|
||||
let lowerNode = newIntNode(nkIntLit, minA)
|
||||
if typ.kind == tyInt and minA == maxA:
|
||||
result = getIntLitType(g, lowerNode)
|
||||
elif typ.kind in {tyUint, tyUInt64}:
|
||||
elif typ.kind in {tyUInt, tyUInt64}:
|
||||
# these are not ordinal types, so you get no subrange type for these:
|
||||
result = typ
|
||||
else:
|
||||
@@ -176,7 +158,7 @@ proc makeRangeF(typ: PType, first, last: BiggestFloat; g: ModuleGraph): PType =
|
||||
result.n = n
|
||||
addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
|
||||
|
||||
proc fitLiteral(c: ConfigRef, n: PNode): PNode =
|
||||
proc fitLiteral(c: ConfigRef, n: PNode): PNode {.deprecated: "no substitute".} =
|
||||
# Trim the literal value in order to make it fit in the destination type
|
||||
if n == nil:
|
||||
# `n` may be nil if the overflow check kicks in
|
||||
@@ -187,92 +169,113 @@ proc fitLiteral(c: ConfigRef, n: PNode): PNode =
|
||||
result = n
|
||||
|
||||
let typ = n.typ.skipTypes(abstractRange)
|
||||
if typ.kind in tyUInt..tyUint32:
|
||||
result.intVal = result.intVal and lastOrd(c, typ, fixedUnsigned=true)
|
||||
if typ.kind in tyUInt..tyUInt32:
|
||||
result.intVal = result.intVal and castToInt64(lastOrd(c, typ))
|
||||
|
||||
proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
||||
template doAndFit(op: untyped): untyped =
|
||||
# Implements wrap-around behaviour for unsigned types
|
||||
fitLiteral(g.config, op)
|
||||
# b and c may be nil
|
||||
result = nil
|
||||
case m
|
||||
of mOrd: result = newIntNodeT(getOrdValue(a), n, g)
|
||||
of mChr: result = newIntNodeT(getInt(a), n, g)
|
||||
of mUnaryMinusI, mUnaryMinusI64: result = foldUnarySub(getInt(a), n, g)
|
||||
of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g)
|
||||
of mNot: result = newIntNodeT(1 - getInt(a), n, g)
|
||||
of mUnaryMinusF64: result = newFloatNodeT(-getFloat(a), n, g)
|
||||
of mNot: result = newIntNodeT(One - getInt(a), n, g)
|
||||
of mCard: result = newIntNodeT(nimsets.cardSet(g.config, a), n, g)
|
||||
of mBitnotI: result = doAndFit(newIntNodeT(not getInt(a), n, g))
|
||||
of mBitnotI:
|
||||
if n.typ.isUnsigned:
|
||||
result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(n.typ.size)), n, g)
|
||||
else:
|
||||
result = newIntNodeT(bitnot(getInt(a)), n, g)
|
||||
of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g)
|
||||
of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
|
||||
if a.kind == nkNilLit:
|
||||
result = newIntNodeT(0, n, g)
|
||||
result = newIntNodeT(Zero, n, g)
|
||||
elif a.kind in {nkStrLit..nkTripleStrLit}:
|
||||
result = newIntNodeT(len a.strVal, n, g)
|
||||
result = newIntNodeT(toInt128(a.strVal.len), n, g)
|
||||
else:
|
||||
result = newIntNodeT(sonsLen(a), n, g)
|
||||
result = newIntNodeT(toInt128(len(a)), n, g)
|
||||
of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
|
||||
of mToFloat, mToBiggestFloat:
|
||||
result = newFloatNodeT(toFloat(int(getInt(a))), n, g)
|
||||
# XXX: Hides overflow/underflow
|
||||
of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n, g)
|
||||
of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n, g)
|
||||
of mAbsI: result = foldAbs(getInt(a), n, g)
|
||||
of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
|
||||
# byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64
|
||||
result = newIntNodeT(getInt(a) and (`shl`(1, getSize(g.config, a.typ) * 8) - 1), n, g)
|
||||
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n, g)
|
||||
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g)
|
||||
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g)
|
||||
of mUnaryLt: result = doAndFit(foldSub(getOrdValue(a), 1, n, g))
|
||||
of mSucc: result = doAndFit(foldAdd(getOrdValue(a), getInt(b), n, g))
|
||||
of mPred: result = doAndFit(foldSub(getOrdValue(a), getInt(b), n, g))
|
||||
of mUnaryLt: result = foldSub(getOrdValue(a), One, n, g)
|
||||
of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g)
|
||||
of mPred: result = foldSub(getOrdValue(a), getInt(b), n, g)
|
||||
of mAddI: result = foldAdd(getInt(a), getInt(b), n, g)
|
||||
of mSubI: result = foldSub(getInt(a), getInt(b), n, g)
|
||||
of mMulI: result = foldMul(getInt(a), getInt(b), n, g)
|
||||
of mMinI:
|
||||
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n, g)
|
||||
else: result = newIntNodeT(getInt(a), n, g)
|
||||
let argA = getInt(a)
|
||||
let argB = getInt(b)
|
||||
result = newIntNodeT(if argA < argB: argA else: argB, n, g)
|
||||
of mMaxI:
|
||||
if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n, g)
|
||||
else: result = newIntNodeT(getInt(b), n, g)
|
||||
let argA = getInt(a)
|
||||
let argB = getInt(b)
|
||||
result = newIntNodeT(if argA > argB: argA else: argB, n, g)
|
||||
of mShlI:
|
||||
case skipTypes(n.typ, abstractRange).kind
|
||||
of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n, g)
|
||||
of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n, g)
|
||||
of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n, g)
|
||||
of tyInt64, tyInt:
|
||||
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g)
|
||||
of tyUInt..tyUInt64:
|
||||
result = doAndFit(newIntNodeT(`shl`(getInt(a), getInt(b)), n, g))
|
||||
of tyInt8: result = newIntNodeT(toInt8(getInt(a)) shl getInt64(b), n, g)
|
||||
of tyInt16: result = newIntNodeT(toInt16(getInt(a)) shl getInt64(b), n, g)
|
||||
of tyInt32: result = newIntNodeT(toInt32(getInt(a)) shl getInt64(b), n, g)
|
||||
of tyInt64: result = newIntNodeT(toInt64(getInt(a)) shl getInt64(b), n, g)
|
||||
of tyInt:
|
||||
if g.config.target.intSize == 4:
|
||||
result = newIntNodeT(toInt128(toInt32(getInt(a)) shl getInt64(b)), n, g)
|
||||
else:
|
||||
result = newIntNodeT(toInt128(toInt64(getInt(a)) shl getInt64(b)), n, g)
|
||||
of tyUInt8: result = newIntNodeT(toInt128(toUInt8(getInt(a)) shl getInt64(b)), n, g)
|
||||
of tyUInt16: result = newIntNodeT(toInt128(toUInt16(getInt(a)) shl getInt64(b)), n, g)
|
||||
of tyUInt32: result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl getInt64(b)), n, g)
|
||||
of tyUInt64: result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl getInt64(b)), n, g)
|
||||
of tyUInt:
|
||||
if g.config.target.intSize == 4:
|
||||
result = newIntNodeT(BiggestInt(toUInt32(getInt(a)) shl getInt64(b)), n, g)
|
||||
else:
|
||||
result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl getInt64(b)), n, g)
|
||||
else: internalError(g.config, n.info, "constant folding for shl")
|
||||
of mShrI:
|
||||
let a = cast[uint64](getInt(a))
|
||||
var a = cast[uint64](getInt(a))
|
||||
let b = cast[uint64](getInt(b))
|
||||
# To support the ``-d:nimOldShiftRight`` flag, we need to mask the
|
||||
# signed integers to cut off the extended sign bit in the internal
|
||||
# representation.
|
||||
if 0'u64 < b: # do not cut off the sign extension, when there is
|
||||
# no bit shifting happening.
|
||||
case skipTypes(n.typ, abstractRange).kind
|
||||
of tyInt8: a = a and 0xff'u64
|
||||
of tyInt16: a = a and 0xffff'u64
|
||||
of tyInt32: a = a and 0xffffffff'u64
|
||||
of tyInt:
|
||||
if g.config.target.intSize == 4:
|
||||
a = a and 0xffffffff'u64
|
||||
else:
|
||||
# unsigned and 64 bit integers don't need masking
|
||||
discard
|
||||
let c = cast[BiggestInt](a shr b)
|
||||
result = newIntNodeT(c, n, g)
|
||||
of mAshrI:
|
||||
case skipTypes(n.typ, abstractRange).kind
|
||||
of tyInt8: result = newIntNodeT(ashr(int8(getInt(a)), int8(getInt(b))), n, g)
|
||||
of tyInt16: result = newIntNodeT(ashr(int16(getInt(a)), int16(getInt(b))), n, g)
|
||||
of tyInt32: result = newIntNodeT(ashr(int32(getInt(a)), int32(getInt(b))), n, g)
|
||||
of tyInt8: result = newIntNodeT(ashr(int8(getInt64(a)), int8(getInt64(b))), n, g)
|
||||
of tyInt16: result = newIntNodeT(ashr(int16(getInt64(a)), int16(getInt64(b))), n, g)
|
||||
of tyInt32: result = newIntNodeT(ashr(int32(getInt64(a)), int32(getInt64(b))), n, g)
|
||||
of tyInt64, tyInt:
|
||||
result = newIntNodeT(ashr(getInt(a), getInt(b)), n, g)
|
||||
result = newIntNodeT(ashr(getInt64(a), getInt64(b)), n, g)
|
||||
else: internalError(g.config, n.info, "constant folding for ashr")
|
||||
of mDivI: result = foldDiv(getInt(a), getInt(b), n, g)
|
||||
of mModI: result = foldMod(getInt(a), getInt(b), n, g)
|
||||
of mDivI:
|
||||
let argA = getInt(a)
|
||||
let argB = getInt(b)
|
||||
if argB != Zero and (argA != firstOrd(g.config, n.typ) or argB != NegOne):
|
||||
result = newIntNodeT(argA div argB, n, g)
|
||||
of mModI:
|
||||
let argA = getInt(a)
|
||||
let argB = getInt(b)
|
||||
if argB != Zero and (argA != firstOrd(g.config, n.typ) or argB != NegOne):
|
||||
result = newIntNodeT(argA mod argB, n, g)
|
||||
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n, g)
|
||||
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n, g)
|
||||
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g)
|
||||
of mDivF64:
|
||||
result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
|
||||
of mMaxF64:
|
||||
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n, g)
|
||||
else: result = newFloatNodeT(getFloat(b), n, g)
|
||||
of mMinF64:
|
||||
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n, g)
|
||||
else: result = newFloatNodeT(getFloat(a), n, g)
|
||||
of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n, g)
|
||||
of mLtI, mLtB, mLtEnum, mLtCh:
|
||||
result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n, g)
|
||||
@@ -287,17 +290,32 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
||||
of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n, g)
|
||||
of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n, g)
|
||||
of mLtU, mLtU64:
|
||||
result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n, g)
|
||||
result = newIntNodeT(ord(`<%`(getOrdValue64(a), getOrdValue64(b))), n, g)
|
||||
of mLeU, mLeU64:
|
||||
result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g)
|
||||
of mBitandI, mAnd: result = doAndFit(newIntNodeT(a.getInt and b.getInt, n, g))
|
||||
of mBitorI, mOr: result = doAndFit(newIntNodeT(getInt(a) or getInt(b), n, g))
|
||||
of mBitxorI, mXor: result = doAndFit(newIntNodeT(a.getInt xor b.getInt, n, g))
|
||||
of mAddU: result = doAndFit(newIntNodeT(`+%`(getInt(a), getInt(b)), n, g))
|
||||
of mSubU: result = doAndFit(newIntNodeT(`-%`(getInt(a), getInt(b)), n, g))
|
||||
of mMulU: result = doAndFit(newIntNodeT(`*%`(getInt(a), getInt(b)), n, g))
|
||||
of mModU: result = doAndFit(foldModU(getInt(a), getInt(b), n, g))
|
||||
of mDivU: result = doAndFit(foldDivU(getInt(a), getInt(b), n, g))
|
||||
result = newIntNodeT(ord(`<=%`(getOrdValue64(a), getOrdValue64(b))), n, g)
|
||||
of mBitandI, mAnd: result = newIntNodeT(bitand(a.getInt, b.getInt), n, g)
|
||||
of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, g)
|
||||
of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, g)
|
||||
of mAddU:
|
||||
let val = maskBytes(getInt(a) + getInt(b), int(n.typ.size))
|
||||
result = newIntNodeT(val, n, g)
|
||||
of mSubU:
|
||||
let val = maskBytes(getInt(a) - getInt(b), int(n.typ.size))
|
||||
result = newIntNodeT(val, n, g)
|
||||
# echo "subU: ", val, " n: ", n, " result: ", val
|
||||
of mMulU:
|
||||
let val = maskBytes(getInt(a) * getInt(b), int(n.typ.size))
|
||||
result = newIntNodeT(val, n, g)
|
||||
of mModU:
|
||||
let argA = maskBytes(getInt(a), int(a.typ.size))
|
||||
let argB = maskBytes(getInt(b), int(a.typ.size))
|
||||
if argB != Zero:
|
||||
result = newIntNodeT(argA mod argB, n, g)
|
||||
of mDivU:
|
||||
let argA = maskBytes(getInt(a), int(a.typ.size))
|
||||
let argB = maskBytes(getInt(b), int(a.typ.size))
|
||||
if argB != Zero:
|
||||
result = newIntNodeT(argA div argB, n, g)
|
||||
of mLeSet: result = newIntNodeT(ord(containsSets(g.config, a, b)), n, g)
|
||||
of mEqSet: result = newIntNodeT(ord(equalSets(g.config, a, b)), n, g)
|
||||
of mLtSet:
|
||||
@@ -323,10 +341,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
||||
of mBoolToStr:
|
||||
if getOrdValue(a) == 0: result = newStrNodeT("false", n, g)
|
||||
else: result = newStrNodeT("true", n, g)
|
||||
of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n, g)
|
||||
of mCopyStr: result = newStrNodeT(substr(getStr(a), int(toInt64(getOrdValue(b)))), n, g)
|
||||
of mCopyStrLast:
|
||||
result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)),
|
||||
int(getOrdValue(c))), n, g)
|
||||
result = newStrNodeT(substr(getStr(a), toInt(getOrdValue(b)),
|
||||
toInt(getOrdValue(c))), n, g)
|
||||
of mFloatToStr: result = newStrNodeT($getFloat(a), n, g)
|
||||
of mCStrToStr, mCharToStr:
|
||||
if a.kind == nkBracket:
|
||||
@@ -353,7 +371,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
||||
|
||||
proc getConstIfExpr(c: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
result = nil
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
var it = n.sons[i]
|
||||
if it.len == 2:
|
||||
var e = getConstExpr(c, it.sons[0], g)
|
||||
@@ -371,27 +389,27 @@ proc leValueConv*(a, b: PNode): bool =
|
||||
case a.kind
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
case b.kind
|
||||
of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
|
||||
of nkCharLit..nkUInt64Lit: result = a.getInt <= b.getInt
|
||||
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal).int
|
||||
else: result = false #internalError(a.info, "leValueConv")
|
||||
of nkFloatLit..nkFloat128Lit:
|
||||
case b.kind
|
||||
of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal
|
||||
of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal))
|
||||
of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat64(b.getInt)
|
||||
else: result = false # internalError(a.info, "leValueConv")
|
||||
else: result = false # internalError(a.info, "leValueConv")
|
||||
|
||||
proc magicCall(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
if sonsLen(n) <= 1: return
|
||||
if len(n) <= 1: return
|
||||
|
||||
var s = n.sons[0].sym
|
||||
var a = getConstExpr(m, n.sons[1], g)
|
||||
var b, c: PNode
|
||||
if a == nil: return
|
||||
if sonsLen(n) > 2:
|
||||
if len(n) > 2:
|
||||
b = getConstExpr(m, n.sons[2], g)
|
||||
if b == nil: return
|
||||
if sonsLen(n) > 3:
|
||||
if len(n) > 3:
|
||||
c = getConstExpr(m, n.sons[3], g)
|
||||
if c == nil: return
|
||||
result = evalOp(s.magic, n, a, b, c, g)
|
||||
@@ -406,57 +424,44 @@ proc getAppType(n: PNode; g: ModuleGraph): PNode =
|
||||
else:
|
||||
result = newStrNodeT("console", n, g)
|
||||
|
||||
proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
|
||||
var err = false
|
||||
if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
|
||||
err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
|
||||
else:
|
||||
err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ)
|
||||
if err:
|
||||
proc rangeCheck(n: PNode, value: Int128; g: ModuleGraph) =
|
||||
if value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ):
|
||||
localError(g.config, n.info, "cannot convert " & $value &
|
||||
" to " & typeToString(n.typ))
|
||||
|
||||
proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
|
||||
let dstTyp = skipTypes(n.typ, abstractRange)
|
||||
let srcTyp = skipTypes(a.typ, abstractRange)
|
||||
let dstTyp = skipTypes(n.typ, abstractRange - {tyTypeDesc})
|
||||
let srcTyp = skipTypes(a.typ, abstractRange - {tyTypeDesc})
|
||||
|
||||
|
||||
# if srcTyp.kind == tyUInt64 and "FFFFFF" in $n:
|
||||
# echo "n: ", n, " a: ", a
|
||||
# echo "from: ", srcTyp, " to: ", dstTyp, " check: ", check
|
||||
# echo getInt(a)
|
||||
# echo high(int64)
|
||||
# writeStackTrace()
|
||||
|
||||
# XXX range checks?
|
||||
case dstTyp.kind
|
||||
of tyInt..tyInt64, tyUint..tyUInt64:
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
case srcTyp.kind
|
||||
of tyFloat..tyFloat64:
|
||||
result = newIntNodeT(int(getFloat(a)), n, g)
|
||||
of tyChar:
|
||||
result = newIntNodeT(getOrdValue(a), n, g)
|
||||
of tyUInt..tyUInt64, tyInt..tyInt64:
|
||||
let toSigned = dstTyp.kind in tyInt..tyInt64
|
||||
result = newIntNodeT(BiggestInt(getFloat(a)), n, g)
|
||||
of tyChar, tyUInt..tyUInt64, tyInt..tyInt64:
|
||||
var val = a.getOrdValue
|
||||
|
||||
if dstTyp.kind in {tyInt, tyInt64, tyUint, tyUInt64}:
|
||||
# No narrowing needed
|
||||
discard
|
||||
elif dstTyp.kind in {tyInt..tyInt64}:
|
||||
# Signed type: Overflow check (if requested) and conversion
|
||||
if check: rangeCheck(n, val, g)
|
||||
let mask = (`shl`(1, getSize(g.config, dstTyp) * 8) - 1)
|
||||
let valSign = val < 0
|
||||
val = abs(val) and mask
|
||||
if valSign: val = -val
|
||||
else:
|
||||
# Unsigned type: Conversion
|
||||
let mask = (`shl`(1, getSize(g.config, dstTyp) * 8) - 1)
|
||||
val = val and mask
|
||||
|
||||
if check: rangeCheck(n, val, g)
|
||||
result = newIntNodeT(val, n, g)
|
||||
if dstTyp.kind in {tyUInt .. tyUInt64}:
|
||||
result.kind = nkUIntLit
|
||||
else:
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
if check and result.kind in {nkCharLit..nkUInt64Lit}:
|
||||
rangeCheck(n, result.intVal, g)
|
||||
rangeCheck(n, getInt(result), g)
|
||||
of tyFloat..tyFloat64:
|
||||
case srcTyp.kind
|
||||
of tyInt..tyInt64, tyEnum, tyBool, tyChar:
|
||||
result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n, g)
|
||||
result = newFloatNodeT(toFloat64(getOrdValue(a)), n, g)
|
||||
else:
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
@@ -481,16 +486,16 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
var y = getConstExpr(m, n.sons[1], g)
|
||||
if y == nil: return
|
||||
|
||||
var idx = getOrdValue(y)
|
||||
var idx = toInt64(getOrdValue(y))
|
||||
case x.kind
|
||||
of nkPar, nkTupleConstr:
|
||||
if idx >= 0 and idx < sonsLen(x):
|
||||
result = x.sons[int(idx)]
|
||||
if idx >= 0 and idx < len(x):
|
||||
result = x.sons[idx]
|
||||
if result.kind == nkExprColonExpr: result = result.sons[1]
|
||||
else:
|
||||
localError(g.config, n.info, formatErrorIndexBound(idx, sonsLen(x)-1) & $n)
|
||||
localError(g.config, n.info, formatErrorIndexBound(idx, len(x)-1) & $n)
|
||||
of nkBracket:
|
||||
idx = idx - firstOrd(g.config, x.typ)
|
||||
idx = idx - toInt64(firstOrd(g.config, x.typ))
|
||||
if idx >= 0 and idx < x.len: result = x.sons[int(idx)]
|
||||
else: localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
@@ -509,7 +514,7 @@ proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
if x == nil or x.kind notin {nkObjConstr, nkPar, nkTupleConstr}: return
|
||||
|
||||
var field = n.sons[1].sym
|
||||
for i in ord(x.kind == nkObjConstr) ..< sonsLen(x):
|
||||
for i in ord(x.kind == nkObjConstr) ..< len(x):
|
||||
var it = x.sons[i]
|
||||
if it.kind != nkExprColonExpr:
|
||||
# lookup per index:
|
||||
@@ -524,7 +529,7 @@ proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
proc foldConStrStr(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
result = newNodeIT(nkStrLit, n.info, n.typ)
|
||||
result.strVal = ""
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
let a = getConstExpr(m, n.sons[i], g)
|
||||
if a == nil: return nil
|
||||
result.strVal.add(getStrOrChar(a))
|
||||
@@ -626,12 +631,12 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
var a = getArrayConstr(m, n.sons[1], g)
|
||||
if a.kind == nkBracket:
|
||||
# we can optimize it away:
|
||||
result = newIntNodeT(sonsLen(a)-1, n, g)
|
||||
result = newIntNodeT(len(a)-1, n, g)
|
||||
of mLengthOpenArray:
|
||||
var a = getArrayConstr(m, n.sons[1], g)
|
||||
if a.kind == nkBracket:
|
||||
# we can optimize it away! This fixes the bug ``len(134)``.
|
||||
result = newIntNodeT(sonsLen(a), n, g)
|
||||
result = newIntNodeT(len(a), n, g)
|
||||
else:
|
||||
result = magicCall(m, n, g)
|
||||
of mLengthArray:
|
||||
@@ -639,13 +644,11 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
# This fixes bug #544.
|
||||
result = newIntNodeT(lengthOrd(g.config, n.sons[1].typ), n, g)
|
||||
of mSizeOf:
|
||||
let size = getSize(g.config, n[1].typ)
|
||||
if size >= 0:
|
||||
result = newIntNode(nkIntLit, size)
|
||||
result.info = n.info
|
||||
result.typ = getSysType(g, n.info, tyInt)
|
||||
else:
|
||||
result = nil
|
||||
result = foldSizeOf(g.config, n, nil)
|
||||
of mAlignOf:
|
||||
result = foldAlignOf(g.config, n, nil)
|
||||
of mOffsetOf:
|
||||
result = foldOffsetOf(g.config, n, nil)
|
||||
of mAstToStr:
|
||||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, g)
|
||||
of mConStrStr:
|
||||
@@ -682,7 +685,7 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
addSon(result, b)
|
||||
#of nkObjConstr:
|
||||
# result = copyTree(n)
|
||||
# for i in 1 ..< sonsLen(n):
|
||||
# for i in 1 ..< len(n):
|
||||
# var a = getConstExpr(m, n.sons[i].sons[1])
|
||||
# if a == nil: return nil
|
||||
# result.sons[i].sons[1] = a
|
||||
@@ -690,7 +693,7 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
of nkPar, nkTupleConstr:
|
||||
# tuple constructor
|
||||
result = copyNode(n)
|
||||
if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr):
|
||||
if (len(n) > 0) and (n.sons[0].kind == nkExprColonExpr):
|
||||
for i, expr in n.pairs:
|
||||
let exprNew = copyNode(expr) # nkExprColonExpr
|
||||
exprNew.add expr[0]
|
||||
@@ -722,8 +725,7 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
var a = getConstExpr(m, n.sons[1], g)
|
||||
if a == nil: return
|
||||
# XXX: we should enable `check` for other conversion types too
|
||||
result = foldConv(n, a, g, check=n.kind == nkHiddenStdConv)
|
||||
result = foldConv(n, a, g, check=true)
|
||||
of nkCast:
|
||||
var a = getConstExpr(m, n.sons[1], g)
|
||||
if a == nil: return
|
||||
|
||||
@@ -282,7 +282,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
|
||||
# is not exported and yet the generic 'threadProcWrapper' works correctly.
|
||||
let flags = if mixinContext: flags+{withinMixin} else: flags
|
||||
for i in first ..< sonsLen(result):
|
||||
for i in first ..< safeLen(result):
|
||||
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
|
||||
of nkCurlyExpr:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
@@ -316,13 +316,13 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
withBracketExpr ctx, a.sons[0]:
|
||||
result = semGenericStmt(c, result, flags, ctx)
|
||||
else:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
|
||||
of nkIfStmt:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx)
|
||||
of nkWhenStmt:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
# bug #8603: conditions of 'when' statements are not
|
||||
# in a 'mixin' context:
|
||||
let it = n[i]
|
||||
@@ -333,22 +333,22 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
n.sons[i] = semGenericStmt(c, it, flags+{withinMixin}, ctx)
|
||||
of nkWhileStmt:
|
||||
openScope(c)
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
n.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
|
||||
closeScope(c)
|
||||
of nkCaseStmt:
|
||||
openScope(c)
|
||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
var a = n.sons[i]
|
||||
checkMinSonsLen(a, 1, c.config)
|
||||
var L = sonsLen(a)
|
||||
var L = len(a)
|
||||
for j in 0 .. L-2:
|
||||
a.sons[j] = semGenericStmt(c, a.sons[j], flags, ctx)
|
||||
a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
|
||||
closeScope(c)
|
||||
of nkForStmt, nkParForStmt:
|
||||
var L = sonsLen(n)
|
||||
var L = len(n)
|
||||
openScope(c)
|
||||
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx)
|
||||
for i in 0 .. L - 3:
|
||||
@@ -372,10 +372,10 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
of nkTryStmt, nkHiddenTryStmt:
|
||||
checkMinSonsLen(n, 2, c.config)
|
||||
n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, ctx)
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
var a = n.sons[i]
|
||||
checkMinSonsLen(a, 1, c.config)
|
||||
var L = sonsLen(a)
|
||||
var L = len(a)
|
||||
openScope(c)
|
||||
for j in 0 .. L-2:
|
||||
if a.sons[j].isInfixAs():
|
||||
@@ -387,28 +387,28 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
closeScope(c)
|
||||
|
||||
of nkVarSection, nkLetSection:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a, c.config)
|
||||
checkMinSonsLen(a, 3, c.config)
|
||||
var L = sonsLen(a)
|
||||
var L = len(a)
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
||||
for j in 0 .. L-3:
|
||||
addTempDecl(c, getIdentNode(c, a.sons[j]), skVar)
|
||||
of nkGenericParams:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
var a = n.sons[i]
|
||||
if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
|
||||
checkMinSonsLen(a, 3, c.config)
|
||||
var L = sonsLen(a)
|
||||
var L = len(a)
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||
# do not perform symbol lookup for default expressions
|
||||
for j in 0 .. L-3:
|
||||
addTempDecl(c, getIdentNode(c, a.sons[j]), skType)
|
||||
of nkConstSection:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkConstDef): illFormedAst(a, c.config)
|
||||
@@ -417,13 +417,13 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
|
||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
|
||||
of nkTypeSection:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkTypeDef): illFormedAst(a, c.config)
|
||||
checkSonsLen(a, 3, c.config)
|
||||
addTempDecl(c, getIdentNode(c, a.sons[0]), skType)
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkTypeDef): illFormedAst(a, c.config)
|
||||
@@ -436,10 +436,10 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
else:
|
||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
|
||||
of nkEnumTy:
|
||||
if n.sonsLen > 0:
|
||||
if n.len > 0:
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
var a: PNode
|
||||
case n.sons[i].kind
|
||||
of nkEnumFieldDef: a = n.sons[i].sons[0]
|
||||
@@ -452,11 +452,11 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
checkMinSonsLen(n, 1, c.config)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
var a = n.sons[i]
|
||||
if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
|
||||
checkMinSonsLen(a, 3, c.config)
|
||||
var L = sonsLen(a)
|
||||
var L = len(a)
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
||||
for j in 0 .. L-3:
|
||||
@@ -489,7 +489,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
checkMinSonsLen(n, 2, c.config)
|
||||
result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
||||
else:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
|
||||
|
||||
when defined(nimsuggest):
|
||||
@@ -497,13 +497,13 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
|
||||
proc semGenericStmt(c: PContext, n: PNode): PNode =
|
||||
var ctx: GenericCtx
|
||||
ctx.toMixin = initIntset()
|
||||
ctx.toMixin = initIntSet()
|
||||
result = semGenericStmt(c, n, {}, ctx)
|
||||
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
|
||||
|
||||
proc semConceptBody(c: PContext, n: PNode): PNode =
|
||||
var ctx: GenericCtx
|
||||
ctx.toMixin = initIntset()
|
||||
ctx.toMixin = initIntSet()
|
||||
result = semGenericStmt(c, n, {withinConcept}, ctx)
|
||||
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ proc sameInstantiation(a, b: TInstantiation): bool =
|
||||
proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
|
||||
id: CompilesId): PSym =
|
||||
for inst in genericSym.procInstCache:
|
||||
if inst.compilesId == id and sameInstantiation(entry, inst[]):
|
||||
if (inst.compilesId == 0 or inst.compilesId == id) and sameInstantiation(entry, inst[]):
|
||||
return inst.sym
|
||||
|
||||
when false:
|
||||
@@ -387,7 +387,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
if c.inGenericContext == 0:
|
||||
instantiateBody(c, n, fn.typ.n, result, fn)
|
||||
sideEffectsCheck(c, result)
|
||||
if result.magic != mSlice:
|
||||
if result.magic notin {mSlice, mTypeOf}:
|
||||
# 'toOpenArray' is special and it is allowed to return 'openArray':
|
||||
paramsTypeCheck(c, result.typ)
|
||||
else:
|
||||
|
||||
@@ -10,20 +10,20 @@
|
||||
## Implements type sanity checking for ASTs resulting from macros. Lots of
|
||||
## room for improvement here.
|
||||
|
||||
import ast, astalgo, msgs, types, options
|
||||
import ast, msgs, types, options
|
||||
|
||||
proc ithField(n: PNode, field: var int): PSym =
|
||||
result = nil
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
for i in 0 ..< len(n):
|
||||
result = ithField(n.sons[i], field)
|
||||
if result != nil: return
|
||||
of nkRecCase:
|
||||
if n.sons[0].kind != nkSym: return
|
||||
result = ithField(n.sons[0], field)
|
||||
if result != nil: return
|
||||
for i in 1 ..< sonsLen(n):
|
||||
for i in 1 ..< len(n):
|
||||
case n.sons[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
result = ithField(lastSon(n.sons[i]), field)
|
||||
|
||||
@@ -141,6 +141,14 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
|
||||
return typeWithSonsResult(tyAnd, @[operand, operand2])
|
||||
of "not":
|
||||
return typeWithSonsResult(tyNot, @[operand])
|
||||
of "typeToString":
|
||||
var prefer = preferTypeName
|
||||
if traitCall.sons.len >= 2:
|
||||
let preferStr = traitCall.sons[2].strVal
|
||||
prefer = parseEnum[TPreferedDesc](preferStr)
|
||||
result = newStrNode(nkStrLit, operand.typeToString(prefer))
|
||||
result.typ = newType(tyString, context)
|
||||
result.info = traitCall.info
|
||||
of "name", "$":
|
||||
result = newStrNode(nkStrLit, operand.typeToString(preferTypeName))
|
||||
result.typ = newType(tyString, context)
|
||||
@@ -172,7 +180,7 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
|
||||
checkMinSonsLen(n, 2, c.config)
|
||||
let t = n.sons[1].typ
|
||||
internalAssert c.config, t != nil and t.kind == tyTypeDesc
|
||||
if t.sonsLen > 0:
|
||||
if t.len > 0:
|
||||
# This is either a type known to sem or a typedesc
|
||||
# param to a regular proc (again, known at instantiation)
|
||||
result = evalTypeTrait(c, n, t, getCurrOwner(c))
|
||||
@@ -186,7 +194,9 @@ proc semOrd(c: PContext, n: PNode): PNode =
|
||||
if isOrdinalType(parType, allowEnumWithHoles=true):
|
||||
discard
|
||||
elif parType.kind == tySet:
|
||||
result.typ = makeRangeType(c, firstOrd(c.config, parType), lastOrd(c.config, parType), n.info)
|
||||
let a = toInt64(firstOrd(c.config, parType))
|
||||
let b = toInt64(lastOrd(c.config, parType))
|
||||
result.typ = makeRangeType(c, a, b, n.info)
|
||||
else:
|
||||
localError(c.config, n.info, errOrdinalTypeExpected)
|
||||
result.typ = errorType(c)
|
||||
@@ -273,7 +283,7 @@ proc semDynamicBindSym(c: PContext, n: PNode): PNode =
|
||||
# executed like 'normal' VM callback
|
||||
idx = vm.registerCallback("bindSymImpl", bindSymWrapper)
|
||||
# dummy node to carry idx information to VM
|
||||
idxNode = newIntTypeNode(nkIntLit, idx, c.graph.getSysType(TLineInfo(), tyInt))
|
||||
idxNode = newIntTypeNode(idx, c.graph.getSysType(TLineInfo(), tyInt))
|
||||
|
||||
result = copyNode(n)
|
||||
for x in n: result.add x
|
||||
@@ -283,7 +293,7 @@ proc semDynamicBindSym(c: PContext, n: PNode): PNode =
|
||||
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||
|
||||
proc semOf(c: PContext, n: PNode): PNode =
|
||||
if sonsLen(n) == 3:
|
||||
if len(n) == 3:
|
||||
n.sons[1] = semExprWithType(c, n.sons[1])
|
||||
n.sons[2] = semExprWithType(c, n.sons[2], {efDetermineType})
|
||||
#restoreOldStyleType(n.sons[1])
|
||||
@@ -355,6 +365,8 @@ proc semUnown(c: PContext; n: PNode): PNode =
|
||||
|
||||
result = copyTree(n[1])
|
||||
result.typ = unownedType(c, result.typ)
|
||||
# little hack for injectdestructors.nim (see bug #11350):
|
||||
#result.sons[0].typ = nil
|
||||
|
||||
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
flags: TExprFlags): PNode =
|
||||
@@ -373,52 +385,11 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
of mTypeOf:
|
||||
result = semTypeOf(c, n)
|
||||
of mSizeOf:
|
||||
# TODO there is no proper way to find out if a type cannot be queried for the size.
|
||||
let size = getSize(c.config, n[1].typ)
|
||||
# We just assume here that the type might come from the c backend
|
||||
if size == szUnknownSize:
|
||||
# Forward to the c code generation to emit a `sizeof` in the C code.
|
||||
result = n
|
||||
elif size >= 0:
|
||||
result = newIntNode(nkIntLit, size)
|
||||
result.info = n.info
|
||||
result.typ = n.typ
|
||||
else:
|
||||
localError(c.config, n.info, "cannot evaluate 'sizeof' because its type is not defined completely, type: " & n[1].typ.typeToString)
|
||||
result = n
|
||||
result = foldSizeOf(c.config, n, n)
|
||||
of mAlignOf:
|
||||
# this is 100% analog to mSizeOf, could be made more dry.
|
||||
let align = getAlign(c.config, n[1].typ)
|
||||
if align == szUnknownSize:
|
||||
result = n
|
||||
elif align >= 0:
|
||||
result = newIntNode(nkIntLit, align)
|
||||
result.info = n.info
|
||||
result.typ = n.typ
|
||||
else:
|
||||
localError(c.config, n.info, "cannot evaluate 'alignof' because its type is not defined completely, type: " & n[1].typ.typeToString)
|
||||
result = n
|
||||
result = foldAlignOf(c.config, n, n)
|
||||
of mOffsetOf:
|
||||
var dotExpr: PNode
|
||||
|
||||
block findDotExpr:
|
||||
if n[1].kind == nkDotExpr:
|
||||
dotExpr = n[1]
|
||||
elif n[1].kind == nkCheckedFieldExpr:
|
||||
dotExpr = n[1][0]
|
||||
else:
|
||||
illFormedAst(n, c.config)
|
||||
|
||||
assert dotExpr != nil
|
||||
|
||||
let value = dotExpr[0]
|
||||
let member = dotExpr[1]
|
||||
|
||||
discard computeSize(c.config, value.typ)
|
||||
|
||||
result = newIntNode(nkIntLit, member.sym.offset)
|
||||
result.info = n.info
|
||||
result.typ = n.typ
|
||||
result = foldOffsetOf(c.config, n, n)
|
||||
of mArrGet:
|
||||
result = semArrGet(c, n, flags)
|
||||
of mArrPut:
|
||||
|
||||
@@ -100,7 +100,7 @@ proc allPossibleValues(c: PContext, t: PType): IntSet =
|
||||
for field in t.n.sons:
|
||||
result.incl(field.sym.position)
|
||||
else:
|
||||
for i in firstOrd(c.config, t) .. lastOrd(c.config, t):
|
||||
for i in toInt64(firstOrd(c.config, t)) .. toInt64(lastOrd(c.config, t)):
|
||||
result.incl(i.int)
|
||||
|
||||
proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,
|
||||
@@ -113,6 +113,13 @@ proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,
|
||||
for i in 1 .. caseNode.len-2:
|
||||
processBranchVals(caseNode[i], excl)
|
||||
|
||||
proc rangeTypVals(rangeTyp: PType): IntSet =
|
||||
assert rangeTyp.kind == tyRange
|
||||
let (a, b) = (rangeTyp.n.sons[0].intVal, rangeTyp.n.sons[1].intVal)
|
||||
result = initIntSet()
|
||||
for it in a .. b:
|
||||
result.incl(it.int)
|
||||
|
||||
proc formatUnsafeBranchVals(t: PType, diffVals: IntSet): string =
|
||||
if diffVals.len <= 32:
|
||||
var strs: seq[string]
|
||||
@@ -200,8 +207,9 @@ proc semConstructFields(c: PContext, recNode: PNode,
|
||||
fieldsPresentInInitExpr(c, fields, initExpr)
|
||||
|
||||
template checkMissingFields(branchNode: PNode) =
|
||||
let fields = branchNode[branchNode.len - 1]
|
||||
checkForMissingFields(c, fields, initExpr)
|
||||
if branchNode != nil:
|
||||
let fields = branchNode[branchNode.len - 1]
|
||||
checkForMissingFields(c, fields, initExpr)
|
||||
|
||||
let discriminator = recNode.sons[0]
|
||||
internalAssert c.config, discriminator.kind == nkSym
|
||||
@@ -227,9 +235,9 @@ proc semConstructFields(c: PContext, recNode: PNode,
|
||||
template badDiscriminatorError =
|
||||
let fields = fieldsPresentInBranch(selectedBranch)
|
||||
localError(c.config, initExpr.info,
|
||||
("you must provide a compile-time value for the discriminator '$1' " &
|
||||
"in order to prove that it's safe to initialize $2.") %
|
||||
[discriminator.sym.name.s, fields])
|
||||
("cannot prove that it's safe to initialize $1 with " &
|
||||
"the runtime value for the discriminator '$2' ") %
|
||||
[fields, discriminator.sym.name.s])
|
||||
mergeInitStatus(result, initNone)
|
||||
|
||||
template wrongBranchError(i) =
|
||||
@@ -240,30 +248,45 @@ proc semConstructFields(c: PContext, recNode: PNode,
|
||||
"are in conflict with this value.",
|
||||
[discriminator.sym.name.s, discriminatorVal.renderTree, fields])
|
||||
|
||||
template valuesInConflictError(valsDiff) =
|
||||
localError(c.config, discriminatorVal.info, ("possible values " &
|
||||
"$2are in conflict with discriminator values for " &
|
||||
"selected object branch $1.") % [$selectedBranch,
|
||||
formatUnsafeBranchVals(recNode.sons[0].typ, valsDiff)])
|
||||
|
||||
let branchNode = recNode[selectedBranch]
|
||||
let flags = flags*{efAllowDestructor} + {efPreferStatic,
|
||||
efPreferNilResult}
|
||||
var discriminatorVal = semConstrField(c, flags,
|
||||
discriminator.sym, initExpr)
|
||||
|
||||
if discriminatorVal != nil:
|
||||
discriminatorVal = discriminatorVal.skipHidden
|
||||
if discriminatorVal.kind notin nkLiterals and (
|
||||
not isOrdinalType(discriminatorVal.typ, true) or
|
||||
lengthOrd(c.config, discriminatorVal.typ) > MaxSetElements or
|
||||
lengthOrd(c.config, recNode.sons[0].typ) > MaxSetElements):
|
||||
localError(c.config, discriminatorVal.info,
|
||||
"branch initialization with a runtime discriminator only " &
|
||||
"supports ordinal types with 2^16 elements or less.")
|
||||
|
||||
if discriminatorVal == nil:
|
||||
badDiscriminatorError()
|
||||
elif discriminatorVal.kind == nkSym:
|
||||
let (ctorCase, ctorIdx) = findUsefulCaseContext(c, discriminatorVal)
|
||||
if ctorCase == nil:
|
||||
badDiscriminatorError()
|
||||
if discriminatorVal.typ.kind == tyRange:
|
||||
let rangeVals = rangeTypVals(discriminatorVal.typ)
|
||||
let recBranchVals = branchVals(c, recNode, selectedBranch, false)
|
||||
let diff = rangeVals - recBranchVals
|
||||
if diff.len != 0:
|
||||
valuesInConflictError(diff)
|
||||
else:
|
||||
badDiscriminatorError()
|
||||
elif discriminatorVal.sym.kind notin {skLet, skParam} or
|
||||
discriminatorVal.sym.typ.kind == tyVar:
|
||||
localError(c.config, discriminatorVal.info,
|
||||
"runtime discriminator must be immutable if branch fields are " &
|
||||
"initialized, a 'let' binding is required.")
|
||||
elif not isOrdinalType(discriminatorVal.sym.typ, true) or
|
||||
lengthOrd(c.config, discriminatorVal.sym.typ) > MaxSetElements:
|
||||
localError(c.config, discriminatorVal.info,
|
||||
"branch initialization with a runtime discriminator only " &
|
||||
"supports ordinal types with 2^16 elements or less.")
|
||||
elif ctorCase[ctorIdx].kind == nkElifBranch:
|
||||
localError(c.config, discriminatorVal.info, "branch initialization " &
|
||||
"with a runtime discriminator is not supported inside of an " &
|
||||
@@ -274,20 +297,27 @@ proc semConstructFields(c: PContext, recNode: PNode,
|
||||
recBranchVals = branchVals(c, recNode, selectedBranch, false)
|
||||
branchValsDiff = ctorBranchVals - recBranchVals
|
||||
if branchValsDiff.len != 0:
|
||||
localError(c.config, discriminatorVal.info, ("possible values " &
|
||||
"$2are in conflict with discriminator values for " &
|
||||
"selected object branch $1.") % [$selectedBranch,
|
||||
formatUnsafeBranchVals(recNode.sons[0].typ, branchValsDiff)])
|
||||
valuesInConflictError(branchValsDiff)
|
||||
else:
|
||||
var failedBranch = -1
|
||||
if branchNode.kind != nkElse:
|
||||
if not branchNode.caseBranchMatchesExpr(discriminatorVal):
|
||||
wrongBranchError(selectedBranch)
|
||||
failedBranch = selectedBranch
|
||||
else:
|
||||
# With an else clause, check that all other branches don't match:
|
||||
for i in 1 .. (recNode.len - 2):
|
||||
if recNode[i].caseBranchMatchesExpr(discriminatorVal):
|
||||
wrongBranchError(i)
|
||||
failedBranch = i
|
||||
break
|
||||
if failedBranch != -1:
|
||||
if discriminatorVal.typ.kind == tyRange:
|
||||
let rangeVals = rangeTypVals(discriminatorVal.typ)
|
||||
let recBranchVals = branchVals(c, recNode, selectedBranch, false)
|
||||
let diff = rangeVals - recBranchVals
|
||||
if diff.len != 0:
|
||||
valuesInConflictError(diff)
|
||||
else:
|
||||
wrongBranchError(failedBranch)
|
||||
|
||||
# When a branch is selected with a partial match, some of the fields
|
||||
# that were not initialized may be mandatory. We must check for this:
|
||||
@@ -352,6 +382,9 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
t = skipTypes(t.sons[0], {tyGenericInst, tyAlias, tySink, tyOwned})
|
||||
if optNimV2 in c.config.globalOptions:
|
||||
result.typ = makeVarType(c, result.typ, tyOwned)
|
||||
# we have to watch out, there are also 'owned proc' types that can be used
|
||||
# multiple times as long as they don't have closures.
|
||||
result.typ.flags.incl tfHasOwned
|
||||
if t.kind != tyObject:
|
||||
localError(c.config, n.info, errGenerated, "object constructor needs an object type")
|
||||
return
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
import
|
||||
ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs,
|
||||
renderer, types, modulegraphs, options
|
||||
renderer, types, modulegraphs, options, spawn
|
||||
|
||||
from trees import getMagic
|
||||
from strutils import `%`
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user